/**
 * Widgster plugin.
 */
!function ($) {

    "use strict";

    // WIDGSTER CLASS DEFINITION
    // ======================

    var Widgster = function (el, options) {
        this.$element = $(el);
        this.$collapse = this.$element.find('[data-widgster=collapse]');
        this.$expand = this.$element.find('[data-widgster=expand]');
        this.$fullscreen = this.$element.find('[data-widgster=fullscreen]');
        this.$restore = this.$element.find('[data-widgster=restore]');
        this.options = options;
        this.collapsed = options.collapsed;
        this.fullscreened = options.fullscreened;

        this._initHandlers();

        if (this.collapsed){
            this.collapse(false);
        } else {
            this.$expand.hide();
        }

        if (this.fullscreened){
            this.fullscreen();
        } else {
            this.$restore.hide();
        }

        this.options.autoload && this.load();
        var interval = parseInt(this.options.autoload);
        if (!isNaN(interval)){
            var widgster = this;
            this._autoloadInterval = setInterval(function(){
                widgster.load();
            }, interval)
        }
    };

    Widgster.DEFAULTS = {
        collapsed: false,
        fullscreened: false,
        transitionDuration: 150,
        bodySelector: '.body',
        showLoader: true,
        autoload: false,
        loaderTemplate: '<div style="text-align: center; margin-top: 10px;">Loading...</div>',
        /**
         * provide a way to insert a prompt before removing widget
         * @param callback
         */
        closePrompt: function(callback){
            callback()
        }
    };

    Widgster.prototype.toleft = function(e){
        e.preventDefault();
        var e = $.Event('toleft.widgster');
        this.$element.trigger(e);
        if (e.isDefaultPrevented()) return;
        const colDiv = this.$element.closest('.col-layer');
        if(colDiv.length <= 0) return;
        adjustSize(colDiv, false);
        return false;
    };

    Widgster.prototype.toright = function(e){
        e.preventDefault();
        var e = $.Event('toright.widgster');
        this.$element.trigger(e);
        if (e.isDefaultPrevented()) return;
        const colDiv = this.$element.closest('.col-layer');
        if(colDiv.length <= 0) return;
        adjustSize(colDiv, true);
        return false;
    };

    function adjustSize(colDiv, increase) {
        const proportions = Array.from($('.col-layer'));
        let result = [];
        let layer = 1;
        let sum = 0;

        proportions.forEach(current => {
            const sizeRegex = /col-lg-(\d+)/;
            const match = current.className.match(sizeRegex);
            const sizeValue = match ? parseInt(match[1], 10) : 0;

            sum += sizeValue;

            result.push({
                current,
                layer
            });

            if (sum % 12 === 0) {
                layer++;
            }
        });

        const colDivItem = result.find(item => item.current === colDiv[0]);

        if (!colDivItem) return;

        const colDivLayer = colDivItem.layer;
        const filteredResult = result.filter(item => item.layer === colDivLayer);
        const filteredLength = filteredResult.length;
        for (let i = 0; i < filteredLength; i++) {
            const left = filteredResult[(i - 1 + filteredLength) % filteredLength];
            const right = filteredResult[(i + 1) % filteredLength];
            filteredResult[i].left = left.current;
            filteredResult[i].right = right.current;
        }

        if (increase) {
            if (canIncrease(colDivItem.current) && canDecrease(colDivItem.right)) {
                adjustColSize(colDivItem.right, -1, function() {
                    adjustColSize(colDivItem.current, 1);
                });
            }
        } else {
            if (canDecrease(colDivItem.current) && canIncrease(colDivItem.right)) {
                adjustColSize(colDivItem.current, -1, function() {
                    adjustColSize(colDivItem.right, 1);
                });
            }
        }
    }

    function canDecrease(node) {
        const sizeRegex = /col-lg-(\d+)/;
        const match = node.className.match(sizeRegex);
        if (!match) {
            return false;
        }
        const size = parseInt(match[1], 10);
        return size > 1;
    }

    function canIncrease(node) {
        const sizeRegex = /col-lg-(\d+)/;
        const match = node.className.match(sizeRegex);
        if (!match) {
            return false;
        }
        const size = parseInt(match[1], 10);
        return size < 12;
    }
    function adjustColSize(node, change, callback) {
        const sizeRegex = /col-lg-(\d+)/;
        const match = node.className.match(sizeRegex);
        if (!match) {
            callback && callback();
            return;
        }
        let newSize = parseInt(match[1], 10) + change;
        const newWidthPercentage = ((parseInt(match[1], 10) + change) / 12) * 100;

        $(node).animate({
            width: newWidthPercentage + '%'
        }, 200, function() {
            node.className = node.className.replace(sizeRegex, `col-lg-${newSize}`);
            $(node).css('width', '');
            callback && callback();
        });
    }

    Widgster.prototype.collapse = function(animate){
        animate = typeof animate == "undefined" ? true : animate;
        var e = $.Event('collapse.widgster');
        this.$element.trigger(e);
        if (e.isDefaultPrevented()) return;

        var widgster = this,
            duration = animate ? this.options.transitionDuration : 0;
        this.$element.find(this.options.bodySelector).slideUp(duration, function(){
            widgster.$element.addClass('collapsed');
            widgster.$element.trigger($.Event('collapsed.widgster'));
            widgster.collapsed = true;
        });

        this.$collapse.hide();
        this.$expand.show();

        return false;
    };

    Widgster.prototype.expand = function(animate){
        animate = typeof animate == "undefined" ? true : animate;
        var e = $.Event('expand.widgster');
        this.$element.trigger(e);
        if (e.isDefaultPrevented()) return;

        var widgster = this,
            duration = animate ? this.options.transitionDuration : 0;
        this.$element.find(this.options.bodySelector).slideDown(duration, function(){
            widgster.$element.removeClass('collapsed');
            widgster.$element.trigger($.Event('expanded.widgster'));
            widgster.collapsed = false;
        });

        this.$collapse.show();
        this.$expand.hide();

        return false;
    };

    Widgster.prototype.close = function(){

        this.options.closePrompt && this.options.closePrompt($.proxy(this._doClose, this));

        return false;
    };

    Widgster.prototype.load = function(){
        var e = $.Event('load.widgster');

        this.$element.trigger(e);

        if (e.isDefaultPrevented()) return;

        var widgster = this;
        this.$element.find(this.options.bodySelector).load(this.options.load, function(responseText, textStatus, xhr){
            widgster.expand();
            widgster.options.showLoader && widgster._hideLoader();
            widgster.$element.trigger($.Event('loaded.widgster', {
                responseText: responseText,
                textStatus: textStatus,
                xhr: xhr
            }))
        });
        this.options.showLoader && this._showLoader();

        return false;
    };

    Widgster.prototype.fullscreen = function(){
        var e = $.Event('fullscreen.widgster');

        this.$element.trigger(e);

        if (e.isDefaultPrevented()) return;

        this.$element.css({
            position: 'fixed',
            top: 0,
            right: 0,
            bottom: 0,
            left: 0,
            margin: 0,
            'z-index': 10000
        });
        $('body').css('overflow', 'hidden');

        this.wasCollapsed = this.collapsed;
        this.expand(false);

        this.$fullscreen.hide();
        this.$restore.show();

        this.$collapse.hide(); this.$expand.hide();

        this.$element.addClass('fullscreened');

        this.$element.addClass('modalDarkBack');

        this.$element.trigger($.Event('fullscreened.widgster'));

        return false;
    };

    Widgster.prototype.restore = function(){
        var e = $.Event('restore.widgster');

        this.$element.trigger(e);

        if (e.isDefaultPrevented()) return;

        this.$element.css({
            position: '',
            top: '',
            right: '',
            bottom: '',
            left: '',
            margin: '',
            'z-index': ''
        });
        $('body').css('overflow', '');

        this.$fullscreen.show();
        this.$restore.hide();

        if (this.collapsed){
            this.$collapse.hide(); this.$expand.show();
        } else {
            this.$collapse.show(); this.$expand.hide();
        }

        this.wasCollapsed && this.collapse(false);

        this.$element.removeClass('fullscreened');

        this.$element.removeClass('modalDarkBack');

        this.$element.trigger($.Event('restored.widgster'));

        return false;
    };

    Widgster.prototype._doClose = function(){
        //could have been remove.widgster, but http://bugs.jquery.com/ticket/14600
        var e = $.Event('close.widgster');

        this.$element.trigger(e);

        if (e.isDefaultPrevented()) return;

        $('body').css('overflow', '');

        this.$element.detach();

        e = $.Event('closed.widgster', {$element: this.$element});

        this.$element.trigger(e);
    };

    Widgster.prototype._showLoader = function(){
        var $body = this.$element.find(this.options.bodySelector);

        this.$loaderWrap = this.$element.find('.widgster-loader-wrap');

        //create loader html if does not exist
        if (this.$loaderWrap.length == 0){
            this.$loaderWrap = $('<div class="widgster-loader-wrap" style="position: absolute; top: 0; right: 0; bottom: 0; ' +
                'left: 0; display: none"></div>');
            this.$element.append(this.$loaderWrap);
        }
        this.$loaderWrap.html(this.options.loaderTemplate);
        this.$loaderWrap.css({
            'margin-top': $body.position().top
        });
        if (!this.collapsed){
            $body.fadeTo(this.options.transitionDuration, 0);
            this.$loaderWrap.fadeIn(this.options.transitionDuration)
        }
    };

    Widgster.prototype._hideLoader = function(){
        this.$loaderWrap.fadeOut(this.options.transitionDuration);
        this.$element.find(this.options.bodySelector).fadeTo(this.options.transitionDuration, 1);
    };

    /**
     * Attach all required widgster functions to data-widgster elements.
     * @private
     */
    Widgster.prototype._initHandlers = function(){
        this.$element.on('click.toleft.widgster', '[data-widgster=toleft]', $.proxy(this.toleft, this));
        this.$element.on('click.toright.widgster', '[data-widgster=toright]', $.proxy(this.toright, this));
        this.$element.on('click.collapse.widgster', '[data-widgster=collapse]', $.proxy(this.collapse, this));
        this.$element.on('click.expand.widgster', '[data-widgster=expand]', $.proxy(this.expand, this));
        this.$element.on('click.close.widgster', '[data-widgster=close]', $.proxy(this.close, this));
        this.$element.on('click.load.widgster', '[data-widgster=load]', $.proxy(this.load, this));
        this.$element.on('click.fullscreen.widgster', '[data-widgster=fullscreen]', $.proxy(this.fullscreen, this));
        this.$element.on('click.restore.widgster', '[data-widgster=restore]', $.proxy(this.restore, this));
    };


    // NAMESPACED DATA ATTRIBUTES
    // =======================

    function getNamespacedData(namespace, data){
        var namespacedData = {};
        for (var key in data){
            // key starts with namespace
            if (key.slice(0, namespace.length) == namespace){
                var namespacedKey = key.slice(namespace.length, key.length);
                namespacedKey = namespacedKey.charAt(0).toLowerCase() + namespacedKey.slice(1);
                namespacedData[namespacedKey] = data[key];
            }
        }

        return namespacedData;
    }

    // WIDGSTER PLUGIN DEFINITION
    // =======================

    $.fn.widgster = function (option) {
        return this.each(function () {
            var $this   = $(this);
            var data    = $this.data('widgster');
            var options = $.extend({}, Widgster.DEFAULTS, getNamespacedData('widgster', $this.data()), typeof option == 'object' && option);

            if (!data) $this.data('widgster', new Widgster(this, options));
            if (typeof option == 'string') data[option]();
        })
    };

    $.fn.widgster.Constructor = Widgster;


}(window.jQuery);
