/* $Id$ */

/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

//Make sure jQuery has been loaded before app.js
if (typeof jQuery === "undefined")
{
  throw new Error("ManifoldCF requires jQuery");
}

/* ManifoldCF
 *
 * @type Object
 * @description $.ManifoldCF is the main object for the template's app.
 *              It's used for implementing functions and options related
 *              to the template. Keeping everything wrapped in an object
 *              prevents conflict with other plugins and is a better
 *              way to organize our code.
 */
$.ManifoldCF={};

/* --------------------
 * - ManifoldCF Options -
 * --------------------
 * Modify these options to suit your implementation
 */
$.ManifoldCF.options={
  //Sidebar push menu toggle button selector
  sidebarToggleSelector: "[data-toggle='offcanvas']",
  //Activate sidebar slimscroll if the fixed layout is set (requires SlimScroll Plugin)
  sidebarSlimScroll: true,
  BSTooltipSelector: '[data-toggle="tooltip"]',
  //The standard screen sizes that bootstrap uses.
  //If you change these in the variables.less file, change
  //them here too.
  screenSizes: {
    xs: 480,
    sm: 768,
    md: 992,
    lg: 1200
  }
};

/* ------------------
 * - Implementation -
 * ------------------
 * The next block of code implements ManifoldCF's
 * functions and plugins as specified by the
 * options above.
 */
$(function ()
{
  //Easy access to options
  var o=$.ManifoldCF.options;

  //Set up the object
  _init();

  //Activate the layout maker
  $.ManifoldCF.layout.activate();

  //Enable sidebar tree view controls
  $.ManifoldCF.tree('.sidebar');

  //Activate sidebar push menu
  $.ManifoldCF.pushMenu.activate(o.sidebarToggleSelector);

  //Activate Bootstrap tooltip
  $(o.BSTooltipSelector).tooltip({
    trigger: 'hover',
    container: 'body'
  });

  /*
   * INITIALIZE BUTTON TOGGLE
   * ------------------------
   */
  $('.btn-group[data-toggle="btn-toggle"]').each(function ()
  {
    var group=$(this);
    $(this).find(".btn").click(function (e)
    {
      group.find(".btn.active").removeClass("active");
      $(this).addClass("active");
      e.preventDefault();
    });

  });
});

/* ----------------------------------
 * - Initialize the ManifoldCF Object -
 * ----------------------------------
 * All ManifoldCF functions are implemented below.
 */
function _init()
{

  /* Layout
   * ======
   * Fixes the layout height in case min-height fails.
   *
   * @type Object
   * @usage $.ManifoldCF.layout.activate()
   *        $.ManifoldCF.layout.fix()
   *        $.ManifoldCF.layout.fixSidebar()
   */
  $.ManifoldCF.layout={
    activate: function ()
    {
      var _this=this;
      _this.fix();
      _this.fixSidebar();
      $(window,".wrapper").resize(function ()
      {
        _this.fix();
        _this.fixSidebar();
      });
    },
    fix: function ()
    {
      //Get window height and the wrapper height
      var neg=$('.main-header').outerHeight() + $('.main-footer').outerHeight();
      var window_height=$(window).height();
      var sidebar_height=$(".sidebar").height();
      //Set the min-height of the content and sidebar based on the
      //the height of the document.
      if ($("body").hasClass("fixed"))
      {
        $(".content-wrapper, .right-side").css('min-height',window_height - $('.main-footer').outerHeight());
      } else
      {
        var postSetWidth;
        if (window_height >= sidebar_height)
        {
          $(".content-wrapper, .right-side").css('min-height',window_height - neg);
          postSetWidth=window_height - neg;
        } else
        {
          $(".content-wrapper, .right-side").css('min-height',sidebar_height);
          postSetWidth=sidebar_height;
        }
      }
      $('.main-footer').show();
    },
    fixSidebar: function ()
    {
      //Make sure the body tag has the .fixed class
      if (!$("body").hasClass("fixed"))
      {
        if (typeof $.fn.slimScroll != 'undefined')
        {
          $(".sidebar").slimScroll({destroy: true}).height("auto");
        }
        return;
      } else if (typeof $.fn.slimScroll == 'undefined' && console)
      {
        console.error("Error: the fixed layout requires the slimscroll plugin!");
      }
      //Enable slimscroll for fixed layout
      if ($.ManifoldCF.options.sidebarSlimScroll)
      {
        if (typeof $.fn.slimScroll != 'undefined')
        {
          //Destroy if it exists
          $(".sidebar").slimScroll({destroy: true}).height("auto");
          //Add slimscroll
          $(".sidebar").slimscroll({
            height: ($(window).height() - $(".main-header").height()) + "px",
            color: "rgba(255,255,255,0.8)",
            size: "5px"
          });
        }
      }
    }
  };

  /* PushMenu()
   * ==========
   * Adds the push menu functionality to the sidebar.
   *
   * @type Function
   * @usage: $.ManifoldCF.pushMenu("[data-toggle='offcanvas']")
   */
  $.ManifoldCF.pushMenu={
    activate: function (toggleBtn)
    {
      //Get the screen sizes
      var screenSizes=$.ManifoldCF.options.screenSizes;

      //Enable sidebar toggle
      $(toggleBtn).on('click',function (e)
      {
        e.preventDefault();

        //Enable sidebar push menu
        if ($(window).width() > (screenSizes.sm - 1))
        {
          $("body").toggleClass('sidebar-collapse');
        }
        //Handle sidebar push menu for small screens
        else
        {
          if ($("body").hasClass('sidebar-open'))
          {
            $("body").removeClass('sidebar-open');
            $("body").removeClass('sidebar-collapse')
          } else
          {
            $("body").addClass('sidebar-open');
          }
        }
      });

      $(".content-wrapper").click(function ()
      {
        //Enable hide menu when clicking on the content-wrapper on small screens
        if ($(window).width() <= (screenSizes.sm - 1) && $("body").hasClass("sidebar-open"))
        {
          $("body").removeClass('sidebar-open');
        }
      });

      //Enable expand on hover for sidebar mini
      if ($.ManifoldCF.options.sidebarExpandOnHover
          || ($('body').hasClass('fixed')
          && $('body').hasClass('sidebar-mini')))
      {
        this.expandOnHover();
      }

    },
    expandOnHover: function ()
    {
      var _this=this;
      var screenWidth=$.ManifoldCF.options.screenSizes.sm - 1;
      //Expand sidebar on hover
      $('.main-sidebar').hover(function ()
      {
        if ($('body').hasClass('sidebar-mini')
            && $("body").hasClass('sidebar-collapse')
            && $(window).width() > screenWidth)
        {
          _this.expand();
        }
      },function ()
      {
        if ($('body').hasClass('sidebar-mini')
            && $('body').hasClass('sidebar-expanded-on-hover')
            && $(window).width() > screenWidth)
        {
          _this.collapse();
        }
      });
    },
    expand: function ()
    {
      $("body").removeClass('sidebar-collapse').addClass('sidebar-expanded-on-hover');
    },
    collapse: function ()
    {
      if ($('body').hasClass('sidebar-expanded-on-hover'))
      {
        $('body').removeClass('sidebar-expanded-on-hover').addClass('sidebar-collapse');
      }
    }
  };

  /* Tree()
   * ======
   * Converts the sidebar into a multilevel
   * tree view menu.
   *
   * @type Function
   * @Usage: $.ManifoldCF.tree('.sidebar')
   */
  $.ManifoldCF.tree=function (menu)
  {
    var _this=this;

    $("li a",$(menu)).on('click',function (e)
    {
      //Get the clicked link and the next element
      var $this=$(this);
      var checkElement=$this.next();

      //Check if the next element is a menu and is visible
      if ((checkElement.is('.treeview-menu')) && (checkElement.is(':visible')))
      {
        //Close the menu
        checkElement.slideUp('normal',function ()
        {
          checkElement.removeClass('menu-open');
          //Fix the layout in case the sidebar stretches over the height of the window
          //_this.layout.fix();
        });
        checkElement.parent("li").removeClass("active");
      }
      //If the menu is not visible
      else if ((checkElement.is('.treeview-menu')) && (!checkElement.is(':visible')))
      {
        //Get the parent menu
        var parent=$this.parents('ul').first();
        //Close all open menus within the parent
        var ul=parent.find('ul:visible').slideUp('normal');
        //Remove the menu-open class from the parent
        ul.removeClass('menu-open');
        //Get the parent li
        var parent_li=$this.parent("li");

        //Open the target menu and add the menu-open class
        checkElement.slideDown('normal',function ()
        {
          //Add the class active to the parent li
          checkElement.addClass('menu-open');
          parent.find('li.active').removeClass('active');
          parent_li.addClass('active');
          //Fix the layout in case the sidebar stretches over the height of the window
          _this.layout.fix();
        });
      }
      //if this isn't a link, prevent the page from being redirected
      if (checkElement.is('.treeview-menu'))
      {
        e.preventDefault();
      }
    });
  };
}

$.ManifoldCF.setTitle=function (title,header,activeMenu)
{
  document.title=title;

  $(".content-header #heading").text(header);

  activeMenu=typeof activeMenu !== 'undefined'?activeMenu:'outputs';
  $("." + activeMenu).addClass("active");

  $(".selectpicker").selectpicker({iconBase:'fa',tickIcon:'fa-check'});
};

function displayError(xhr)
{
  $(".content-header #heading").text('Error!');
  document.title='Error';
  var msg = xhr.status + " " + xhr.statusText;
  //Proper error message, if the server is down.
  if(xhr.status === 0)
  {
    msg = MCFError.ServerDown;
  }
  else if(xhr.status === 500)
  {
    msg = MCFError.InternalServerError;
  }
  var errorTemplate = '<div class="box box-solid">' +
                        '<div class="box-body">' +
                          '<div class="alert alert-danger">' +
                            '<h3><i class="fa fa-ban fa-fw"></i> Error!</h3>' +
                            '<h4>' + msg +'</h4>' +
                          '</div>' +
                        '</div>' +
                        '<div class="box-footer with-border">' +
                          '<div class="btn-group">' +
                            '<a class="btn btn-default" href="index.jsp" title="Return" data-toggle="tooltip">' +
                              '<i class="fa fa-check fa-fw" aria-hidden="true"></i>OK' +
                            '</a>';
  if(xhr.status === 500)
  {
    errorTemplate +=        '<button type="button" class="btn btn-default" data-toggle="modal" data-target="#exceptionModal">' +
                              '<i class="fa fa-exclamation-triangle fa-fw" aria-hidden="true"></i>See Exception</button>';
    $('#exceptionModal .modal-body').empty();
    $('#exceptionModal .modal-body').html(xhr.responseText);
  }
  errorTemplate +=        '</div>' +
                        '</div>' +
                      '</div>';
  $("#content").html(errorTemplate);
}

function _endsWith(str, suffix) {
    return str.indexOf(suffix, str.length - suffix.length) !== -1;
}

function _preLoadContent()
{
  console.log('_preLoadContent');
  $($.ManifoldCF.options.BSTooltipSelector).tooltip('destroy');

  //Temporary fix for Javascript bug, when loading connector javascript.
  //Get all the global methods
  var methods = Object.keys(window);
  for(var i=0; i<=methods.length; i++){
    var method = methods[i];
      if (method && (_endsWith(method, 'checkConfig') ||
          _endsWith(method, 'checkConfigForSave') ||
          _endsWith(method, 'checkSpecification') ||
          _endsWith(method, 'checkSpecificationForSave'))) {
          delete window[method];
      }
  }
}

function _postLoadContent()
{
  console.log('_postLoadContent');
  //Activate Bootstrap tooltip
  $($.ManifoldCF.options.BSTooltipSelector).tooltip({
    trigger: 'hover',
    container: 'body'
  });
}

$.ManifoldCF.loadContent=function (url)
{
  $('.overlay,#loader').show();
  console.log("URL: " + url);
  _preLoadContent();

  //Add Client Timezone Offset
  var timezone_offset = new Date().getTimezoneOffset();
  var timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;

  $('#content').load(decodeURIComponent(url), { client_timezone_offset : timezone_offset, client_timezone : timezone } ,function (response,status,xhr)
  {
    if (status == 'error')
    {
      displayError(xhr);
    }
    _postLoadContent();
    $('.overlay,#loader').hide();
  });
};

$.ManifoldCF.submit=function (form)
{
  $('.overlay,#loader').show();

  var formData = new FormData(form),
      $form = $(form),
      action = $form.attr('action'),
      method = $form.attr('method');

  _preLoadContent();

  //Add Client Timezone Offset
  var timezone_offset = new Date().getTimezoneOffset();
  var timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
  formData.append('client_timezone_offset',timezone_offset);
  formData.append('client_timezone',timezone);

  $.ajax({
    type: method,
    url: action,
    data: formData,
    cache: false,
    contentType: false,
    processData: false
  }).done(function (data,textStatus,jqXHR)
  {
    var page=jqXHR.getResponseHeader("page");
    console.log("page: " + page)
    if (typeof page != 'undefined')
    {
      window.history.replaceState({urlPath: encodeURI(page)},null,'?p=' + page + '#execute');
    }
    else
    {
      window.history.replaceState({urlPath: encodeURI(action)},null,'#execute_' + form.name);
    }
    console.log("textStatus: " + textStatus);
    $('#content').html(data);
  }).fail(function (xhr,opts,error)
  {
    displayError(xhr);
  }).always(function ()
  {
    _postLoadContent();
    $('.overlay,#loader').hide();
  });
}

window.onpopstate = function (event) {
  console.log('historyEvent:',event);
  if (event.state) {
    // history changed because of pushState/replaceState
    var state=window.history.state;
    if (typeof  state != 'undefined')
    {
      if (!state.urlPath.startsWith('execute'))
      {
        $.ManifoldCF.loadContent(state.urlPath);
      }
    }
  }
  else
  {
    console.log('history changed because of a page load');
  }
}

$(function(){
  // navigation link handler
  $(document.body).on("click",'.link',function (e)
  {
    e.preventDefault();

    var urlPath = $(this).attr('data-href') || $(this).attr('href');
    var title=$(this).text();

    $.ManifoldCF.loadContent(urlPath);

    var data = {urlPath: encodeURIComponent(urlPath)};
    window.history.pushState(data,title,'?p=' + encodeURIComponent(urlPath) + '&_' + new Date().getTime());
  });

  //Prevent from submit on Enter
  $(window).keydown(function(e){
    var key = e.charCode || e.keyCode || 0;
    var node = (e.target) ? e.target : ((e.srcElement) ? e.srcElement : null);
    if(key == 13 && node.nodeName !== "TEXTAREA") {
      console.log("Enter on input fields is disabled.");
      e.preventDefault();
      return false;
    }
  });

});
