var OU = OU || {};

OU.tab = (function() {
    var index = (typeof index == 'number') ? ++index : 0;

    /**
     * Creates a set of tabs
     * @param {object[]} data - array of tab cfg objects
     * @constructor
     */
    var TabSet = function(data) {
        this.id = 'tab-set' + index;
        this.index = index;
        this.data = data || [];
        this.tabs = [];
        this.active = null;
        this.container = OU.utils.createElement('div', 'tab-container', this.id);
        this.list = OU.utils.createElement('ul', 'nav nav-tabs');
        this.content = OU.utils.createElement('div', 'tab-content');

        this.init();
    };

    TabSet.prototype = {
        init: function() {
            this.list.setAttribute('role', 'tablist');

            this.data.forEach(function(data) {
                this.add(data);
            }.bind(this));

            this.container.addEventListener('shown', this);

            this.container.appendChild(this.list);
            this.container.appendChild(this.content);
        },

        /**
         *
         * @param {object} data - to be passed to Tab.
         */
        add: function(data) {
            var tab = new Tab(data, this);

            this.tabs.push(tab);
            this.tabs[data.id] = tab;
            this.list.appendChild(tab.nav);
            this.content.appendChild(tab.pane);

            //push any tab data added after init
            if (this.data.length < this.tabs.length) {
                this.data.push(data);
            }

            if (this.tabs.length == 1) {
                tab.show();
                this.setActive(tab);
            }

            return tab;
        },

        setActive: function(tab) {
            this.active = tab;
        },

        get: function(id) {
            return this.tabs[id] || {};
        },

        on: function(type, handler) {
            if (typeof handler == 'function') {
                handler.bind(this);
            }

            this.container.addEventListener(type, handler);
        },

        handleEvent: function(e) {
            switch (e.type) {
                case 'shown':
                    this.setActive(e.detail.tab);
            }
        }
    };

    /**
     * Creates a tab instance
     * @param {object[]} data
     * @param {string} data.id
     * @param {boolean} [data.active]
     * @param {boolean} [data.disabled]
     * @param {string} data.label - label for nav tab
     * @param {string||Element} data.content - pane content
     * @param {TabSet} set
     * @constructor
     */
    var Tab = function(data, set) {
        this.id = '';
        this.active = false;
        this.disabled = false;
        this.label = '';
        this.content = '';
        this.nav = null;
        this.pane = null;
        this.set = set;

        OU.utils.extendDeep(this, data);

        this.createNav();
        this.createPane();
        this.on('click', this);
        this.set.on('show', this);
        this.set.on('hide', this);

        if (this.active) {
            this.active = false;
            this.show();
        }
    };

    Tab.prototype = {
        createNav: function() {
            var classes = [];
            var li = document.createElement('li');
            var a = document.createElement('a');

            a.href = '#' + this.id + '_tab';
            a.textContent = this.label;
            a.setAttribute('role', 'tab');
            a.setAttribute('aria-controls', this.id + '_tab');

            if (this.active) {
                classes.push('active');
            }
            if (this.disabled) {
                classes.push('disabled');
            }
            if (classes.length) {
                li.className = classes.join(' ');
            }

            li.id = this.id;
            li.setAttribute('role', 'presentation');
            li.appendChild(a);

            this.nav = li;
        },

        createPane: function() {
            var container =  OU.utils.createElement('div', 'tab-pane', this.id + '_tab');

            //TODO just call this.hide();
            container.setAttribute('role', 'tabpanel');
            container.setAttribute('aria-hidden', 'true');

            switch(true) {
                case (this.content instanceof Element):
                    container.appendChild(this.content);
                    break;
                case OU.utils.isObject(this.content):
                    container.appendChild(this.content.container);
                    break;
                case (typeof this.content == 'string'):
                    container.insertAdjacentHTML('beforeend', this.content);
                    break;
                default:
                    throw new Error('Tab content type not supported');
            }

            this.pane = container;
        },

        show: function() {
            if (this.active) {
                return;
            }

            if (this.set.active) {
                this.set.active.hide();
            }

            this.trigger('show');
            this.active = true;
            this.pane.style.display = 'block';
            this.pane.setAttribute('aria-hidden', 'false');
            OU.utils.addClass(this.nav, 'active');
            this.trigger('shown');
        },

        hide: function() {
            if (!this.active) {
                return;
            }

            this.trigger('hide');
            this.active = false;
            this.pane.style.display = 'none';
            this.pane.setAttribute('aria-hidden', 'true');
            OU.utils.removeClass(this.nav, 'active');
            this.trigger('hidden');
        },

        enable: function() {
            this.disabled = false;
            OU.utils.removeClass(this.nav, 'disabled');
        },

        disable: function() {
            this.disabled = true;
            OU.utils.addClass(this.nav, 'disabled');
        },

        on: function(type, handler) {
            if (typeof handler == 'function') {
                handler.bind(this);
            }

            this.nav.addEventListener(type, handler);
        },

        off: function() {
            //TODO needed?
        },

        trigger: function(event) {
            OU.utils.triggerCustomEvent(this.nav, event, {tab: this});
        },

        handleEvent: function(e) {
            e.stopPropagation();

            switch (e.type) {
                case 'click':
                    if (!this.disabled) {
                        e.preventDefault();
                        this.show();
                    }
            }

            if (this.events && typeof this.events[e.type] == 'function') {
                this.events[e.type].call(this, e);
            }
        }
    };

    var construct = function(cfg) {
        return new TabSet(cfg);
    };

    return {
        construct: construct
    };
})();