'use strict';

import $ from 'jquery';
import { MediaQuery } from './foundation.util.mediaQuery';
import { GetYoDigits } from './foundation.core.utils';
import { Plugin }from './foundation.core.plugin';

import { Accordion } from './foundation.accordion';
import { Tabs } from './foundation.tabs';

// The plugin matches the plugin classes with these plugin instances.
var MenuPlugins = {
  tabs: {
    cssClass: 'tabs',
    plugin:   Tabs,
    open:     (plugin, target) => plugin.selectTab(target),
    close:    null /* not supported */,
    toggle:   null /* not supported */,
  },
  accordion: {
    cssClass: 'accordion',
    plugin:   Accordion,
    open:     (plugin, target) => plugin.down($(target)),
    close:    (plugin, target) => plugin.up($(target)),
    toggle:   (plugin, target) => plugin.toggle($(target)),
  }
};


/**
 * ResponsiveAccordionTabs module.
 * @module foundation.responsiveAccordionTabs
 * @requires foundation.util.motion
 * @requires foundation.accordion
 * @requires foundation.tabs
 */

class ResponsiveAccordionTabs extends Plugin{
  constructor(element, options) {
    super(element, options);
    return this.options.reflow && this.storezfData || this;
  }

  /**
   * Creates a new instance of a responsive accordion tabs.
   * @class
   * @name ResponsiveAccordionTabs
   * @fires ResponsiveAccordionTabs#init
   * @param {jQuery} element - jQuery object to make into Responsive Accordion Tabs.
   * @param {Object} options - Overrides to the default plugin settings.
   */
  _setup(element, options) {
    this.$element = $(element);
    this.$element.data('zfPluginBase', this);
    this.options = $.extend({}, ResponsiveAccordionTabs.defaults, this.$element.data(), options);

    this.rules = this.$element.data('responsive-accordion-tabs');
    this.currentMq = null;
    this.currentRule = null;
    this.currentPlugin = null;
    this.className = 'ResponsiveAccordionTabs'; // ie9 back compat
    if (!this.$element.attr('id')) {
      this.$element.attr('id',GetYoDigits(6, 'responsiveaccordiontabs'));
    }

    this._init();
    this._events();
  }

  /**
   * Initializes the Menu by parsing the classes from the 'data-responsive-accordion-tabs' attribute on the element.
   * @function
   * @private
   */
  _init() {
    MediaQuery._init();

    // The first time an Interchange plugin is initialized, this.rules is converted from a string of "classes" to an object of rules
    if (typeof this.rules === 'string') {
      let rulesTree = {};

      // Parse rules from "classes" pulled from data attribute
      let rules = this.rules.split(' ');

      // Iterate through every rule found
      for (let i = 0; i < rules.length; i++) {
        let rule = rules[i].split('-');
        let ruleSize = rule.length > 1 ? rule[0] : 'small';
        let rulePlugin = rule.length > 1 ? rule[1] : rule[0];

        if (MenuPlugins[rulePlugin] !== null) {
          rulesTree[ruleSize] = MenuPlugins[rulePlugin];
        }
      }

      this.rules = rulesTree;
    }

    this._getAllOptions();

    if (!$.isEmptyObject(this.rules)) {
      this._checkMediaQueries();
    }
  }

  _getAllOptions() {
    //get all defaults and options
    var _this = this;
    _this.allOptions = {};
    for (var key in MenuPlugins) {
      if (MenuPlugins.hasOwnProperty(key)) {
        var obj = MenuPlugins[key];
        try {
          var dummyPlugin = $('<ul></ul>');
          var tmpPlugin = new obj.plugin(dummyPlugin,_this.options);
          for (var keyKey in tmpPlugin.options) {
            if (tmpPlugin.options.hasOwnProperty(keyKey) && keyKey !== 'zfPlugin') {
              var objObj = tmpPlugin.options[keyKey];
              _this.allOptions[keyKey] = objObj;
            }
          }
          tmpPlugin.destroy();
        }
        catch(e) {
        }
      }
    }
  }

  /**
   * Initializes events for the Menu.
   * @function
   * @private
   */
  _events() {
    this._changedZfMediaQueryHandler = this._checkMediaQueries.bind(this);
    $(window).on('changed.zf.mediaquery', this._changedZfMediaQueryHandler);
  }

  /**
   * Checks the current screen width against available media queries. If the media query has changed, and the plugin needed has changed, the plugins will swap out.
   * @function
   * @private
   */
  _checkMediaQueries() {
    var matchedMq, _this = this;
    // Iterate through each rule and find the last matching rule
    $.each(this.rules, function(key) {
      if (MediaQuery.atLeast(key)) {
        matchedMq = key;
      }
    });

    // No match? No dice
    if (!matchedMq) return;

    // Plugin already initialized? We good
    if (this.currentPlugin instanceof this.rules[matchedMq].plugin) return;

    // Remove existing plugin-specific CSS classes
    $.each(MenuPlugins, function(key, value) {
      _this.$element.removeClass(value.cssClass);
    });

    // Add the CSS class for the new plugin
    this.$element.addClass(this.rules[matchedMq].cssClass);

    // Create an instance of the new plugin
    if (this.currentPlugin) {
      //don't know why but on nested elements data zfPlugin get's lost
      if (!this.currentPlugin.$element.data('zfPlugin') && this.storezfData) this.currentPlugin.$element.data('zfPlugin',this.storezfData);
      this.currentPlugin.destroy();
    }
    this._handleMarkup(this.rules[matchedMq].cssClass);
    this.currentRule = this.rules[matchedMq];
    this.currentPlugin = new this.currentRule.plugin(this.$element, this.options);
    this.storezfData = this.currentPlugin.$element.data('zfPlugin');

  }

  _handleMarkup(toSet){
    var _this = this, fromString = 'accordion';
    var $panels = $('[data-tabs-content='+this.$element.attr('id')+']');
    if ($panels.length) fromString = 'tabs';
    if (fromString === toSet) {
      return;
    }

    var tabsTitle = _this.allOptions.linkClass?_this.allOptions.linkClass:'tabs-title';
    var tabsPanel = _this.allOptions.panelClass?_this.allOptions.panelClass:'tabs-panel';

    this.$element.removeAttr('role');
    var $liHeads = this.$element.children('.'+tabsTitle+',[data-accordion-item]').removeClass(tabsTitle).removeClass('accordion-item').removeAttr('data-accordion-item');
    var $liHeadsA = $liHeads.children('a').removeClass('accordion-title');

    if (fromString === 'tabs') {
      $panels = $panels.children('.'+tabsPanel).removeClass(tabsPanel).removeAttr('role').removeAttr('aria-hidden').removeAttr('aria-labelledby');
      $panels.children('a').removeAttr('role').removeAttr('aria-controls').removeAttr('aria-selected');
    } else {
      $panels = $liHeads.children('[data-tab-content]').removeClass('accordion-content');
    }

    $panels.css({display:'',visibility:''});
    $liHeads.css({display:'',visibility:''});
    if (toSet === 'accordion') {
      $panels.each(function(key,value){
        $(value).appendTo($liHeads.get(key)).addClass('accordion-content').attr('data-tab-content','').removeClass('is-active').css({height:''});
        $('[data-tabs-content='+_this.$element.attr('id')+']').after('<div id="tabs-placeholder-'+_this.$element.attr('id')+'"></div>').detach();
        $liHeads.addClass('accordion-item').attr('data-accordion-item','');
        $liHeadsA.addClass('accordion-title');
      });
    } else if (toSet === 'tabs') {
      var $tabsContent = $('[data-tabs-content='+_this.$element.attr('id')+']');
      var $placeholder = $('#tabs-placeholder-'+_this.$element.attr('id'));
      if ($placeholder.length) {
        $tabsContent = $('<div class="tabs-content"></div>').insertAfter($placeholder).attr('data-tabs-content',_this.$element.attr('id'));
        $placeholder.remove();
      } else {
        $tabsContent = $('<div class="tabs-content"></div>').insertAfter(_this.$element).attr('data-tabs-content',_this.$element.attr('id'));
      }
      $panels.each(function(key,value){
        var tempValue = $(value).appendTo($tabsContent).addClass(tabsPanel);
        var hash = $liHeadsA.get(key).hash.slice(1);
        var id = $(value).attr('id') || GetYoDigits(6, 'accordion');
        if (hash !== id) {
          if (hash !== '') {
            $(value).attr('id',hash);
          } else {
            hash = id;
            $(value).attr('id',hash);
            $($liHeadsA.get(key)).attr('href',$($liHeadsA.get(key)).attr('href').replace('#','')+'#'+hash);
          }
        }
        var isActive = $($liHeads.get(key)).hasClass('is-active');
        if (isActive) {
          tempValue.addClass('is-active');
        }
      });
      $liHeads.addClass(tabsTitle);
    };
  }

  /**
   * Opens the plugin pane defined by `target`.
   * @param {jQuery | String} target - jQuery object or string of the id of the pane to open.
   * @see Accordion.down
   * @see Tabs.selectTab
   * @function
   */
  open(_target) {
    if (this.currentRule && typeof this.currentRule.open === 'function') {
      return this.currentRule.open(this.currentPlugin, ...arguments);
    }
  }

  /**
   * Closes the plugin pane defined by `target`. Not availaible for Tabs.
   * @param {jQuery | String} target - jQuery object or string of the id of the pane to close.
   * @see Accordion.up
   * @function
   */
  close(_target) {
    if (this.currentRule && typeof this.currentRule.close === 'function') {
      return this.currentRule.close(this.currentPlugin, ...arguments);
    }
  }

  /**
   * Toggles the plugin pane defined by `target`. Not availaible for Tabs.
   * @param {jQuery | String} target - jQuery object or string of the id of the pane to toggle.
   * @see Accordion.toggle
   * @function
   */
  toggle(_target) {
    if (this.currentRule && typeof this.currentRule.toggle === 'function') {
      return this.currentRule.toggle(this.currentPlugin, ...arguments);
    }
  }

  /**
   * Destroys the instance of the current plugin on this element, as well as the window resize handler that switches the plugins out.
   * @function
   */
  _destroy() {
    if (this.currentPlugin) this.currentPlugin.destroy();
    $(window).off('changed.zf.mediaquery', this._changedZfMediaQueryHandler);
  }
}

ResponsiveAccordionTabs.defaults = {};

export {ResponsiveAccordionTabs};
