/*
 * Builder client-side Index page controller
 */
+function ($) { "use strict";

    if ($.oc.builder === undefined) {
        $.oc.builder = {};
    }

    var Base = $.oc.foundation.base,
        BaseProto = Base.prototype;

    var Builder = function() {
        Base.call(this);

        this.$masterTabs = null;
        this.masterTabsObj = null;
        this.hideStripeIndicatorProxy = null;
        this.entityControllers = {};

        this.init();
    }

    Builder.prototype = Object.create(BaseProto)
    Builder.prototype.constructor = Builder

    Builder.prototype.dispose = function() {
        // We don't really care about disposing the
        // index controller, as it's used only once
        // and always exists during the page life.
        BaseProto.dispose.call(this)
    }

    // PUBLIC METHODS
    // ============================

    Builder.prototype.openOrLoadMasterTab = function($form, serverHandlerName, tabId, data) {
        if (this.masterTabsObj.goTo(tabId)) {
            return false;
        }

        var requestData = data === undefined ? {} : data;

        $.oc.stripeLoadIndicator.show();

        var promise = $form
            .request(serverHandlerName, {
                data: requestData
            })
            .done(this.proxy(this.addMasterTab))
            .always(this.hideStripeIndicatorProxy);

        return promise;
    }

    Builder.prototype.getMasterTabActivePane = function() {
        return this.$masterTabs.find('> .tab-content > .tab-pane.active');
    }

    Builder.prototype.unchangeTab = function($pane) {
        $pane.find('form').trigger('unchange.oc.changeMonitor');
    }

    Builder.prototype.triggerCommand = function(command, ev) {
        var commandParts = command.split(':')

        if (commandParts.length === 2) {
            var entity = commandParts[0],
                commandToExecute = commandParts[1]

            if (this.entityControllers[entity] === undefined) {
                throw new Error('Unknown entity type: ' + entity)
            }

            this.entityControllers[entity].invokeCommand(commandToExecute, ev)
        }
    }

    // INTERNAL METHODS
    // ============================

    Builder.prototype.init = function() {
        this.$masterTabs = $('#builder-master-tabs')
        this.$sidePanel = $('#builder-side-panel')

        this.masterTabsObj = this.$masterTabs.data('oc.tab')
        this.hideStripeIndicatorProxy = this.proxy(this.hideStripeIndicator)
        new $.oc.tabFormExpandControls(this.$masterTabs)

        this.createEntityControllers()
        this.registerHandlers()
    }

    Builder.prototype.createEntityControllers = function() {
        for (var controller in $.oc.builder.entityControllers) {
            if (controller == "base") {
                continue;
            }

            this.entityControllers[controller] = new $.oc.builder.entityControllers[controller](this);
        }
    }

    Builder.prototype.registerHandlers = function() {
        $(document).on('click', '[data-builder-command]', this.proxy(this.onCommand));
        $(document).on('submit', '[data-builder-command]', this.proxy(this.onCommand));

        this.$masterTabs.on('changed.oc.changeMonitor', this.proxy(this.onFormChanged));
        this.$masterTabs.on('unchanged.oc.changeMonitor', this.proxy(this.onFormUnchanged));
        this.$masterTabs.on('shown.bs.tab', this.proxy(this.onTabShown));
        this.$masterTabs.on('afterAllClosed.oc.tab', this.proxy(this.onAllTabsClosed));
        this.$masterTabs.on('closed.oc.tab', this.proxy(this.onTabClosed));
        this.$masterTabs.on('autocompleteitems.oc.inspector', this.proxy(this.onDataRegistryItems));
        this.$masterTabs.on('dropdownoptions.oc.inspector', this.proxy(this.onDataRegistryItems));

        for (var controller in this.entityControllers) {
            if (this.entityControllers[controller].registerHandlers !== undefined) {
                this.entityControllers[controller].registerHandlers();
            }
        }
    }

    Builder.prototype.hideStripeIndicator = function() {
        $.oc.stripeLoadIndicator.hide();
    }

    Builder.prototype.addMasterTab = function(data) {
        this.masterTabsObj.addTab(data.tabTitle, data.tab, data.tabId, 'oc-' + data.tabIcon)

        var $masterTabPane = this.getMasterTabActivePane();

        if (data.isNewRecord) {
            $masterTabPane.find('form').one('ready.oc.changeMonitor', this.proxy(this.onChangeMonitorReady));
        }

        $('[data-builder-tabs]', $masterTabPane).dragScroll();
    }

    Builder.prototype.updateModifiedCounter = function() {
        var counters = {
            database: { menu: 'database', count: 0 },
            models: { menu: 'models', count: 0 },
            permissions: { menu: 'permissions', count: 0 },
            menus: { menu: 'menus', count: 0 },
            imports: { menu: 'imports', count: 0 },
            versions: { menu: 'versions', count: 0 },
            localization: { menu: 'localization', count: 0 },
            controller: { menu: 'controllers', count: 0 },
            code: { menu: 'code', count: 0 }
        }

        $('> div.tab-content > div.tab-pane[data-modified] > form', this.$masterTabs).each(function(){
            var entity = $(this).data('entity')
            counters[entity].count++
        })

        $.each(counters, function(type, data){
            $.oc.sideNav.setCounter('builder/' + data.menu, data.count);
        })
    }

    Builder.prototype.getFormPluginCode = function(formElement) {
        var $form = $(formElement).closest('form'),
            $input = $form.find('input[name="plugin_code"]'),
            code = $input.val()

        if (!code) {
            throw new Error('Plugin code input is not found in the form.')
        }

        return code
    }

    Builder.prototype.setPageTitle = function(title) {
        $.oc.layout.setPageTitle(title.length ? (title + ' | ') : title)
    }

    Builder.prototype.getFileLists = function() {
        return $('[data-control=filelist]', this.$sidePanel)
    }

    Builder.prototype.dataToInspectorArray = function(data) {
        var result = []

        for (var key in data) {
            var item = {
                title: data[key],
                value: key
            }
            result.push(item)
        }

        return result
    }

    // EVENT HANDLERS
    // ============================

    Builder.prototype.onCommand = function(ev) {
        if (ev.currentTarget.tagName == 'FORM' && ev.type == 'click') {
            // The form elements could have data-builder-command attribute,
            // but for them we only handle the submit event and ignore clicks.
            return;
        }

        var command = $(ev.currentTarget).data('builderCommand');
        this.triggerCommand(command, ev);

        // Prevent default for everything except drop-down menu items
        //
        var $target = $(ev.currentTarget);
        if (ev.currentTarget.tagName === 'A' && $target.attr('role') == 'menuitem' && $target.attr('href') == 'javascript:;') {
            return;
        }

        ev.preventDefault();
        return false;
    }

    Builder.prototype.onFormChanged = function(ev) {
        $('.form-tabless-fields', ev.target).trigger('modified.oc.tab')
        this.updateModifiedCounter()
    }

    Builder.prototype.onFormUnchanged = function(ev) {
        $('.form-tabless-fields', ev.target).trigger('unmodified.oc.tab')
        this.updateModifiedCounter()
    }

    Builder.prototype.onTabShown = function(ev) {
        var $tabControl = $(ev.target).closest('[data-control=tab]')

        if ($tabControl.attr('id') != this.$masterTabs.attr('id')) {
            return
        }

        var dataId = $(ev.target).closest('li').attr('data-tab-id'),
            title = $(ev.target).attr('title')

        if (title) {
            this.setPageTitle(title)
        }

        this.getFileLists().fileList('markActive', dataId)

        $(window).trigger('resize')
    }

    Builder.prototype.onAllTabsClosed = function(ev) {
        this.setPageTitle('')
        this.getFileLists().fileList('markActive', null)
    }

    Builder.prototype.onTabClosed = function(ev, tab, pane) {
        $(pane).find('form').off('ready.oc.changeMonitor', this.proxy(this.onChangeMonitorReady))

        this.updateModifiedCounter()
    }

    Builder.prototype.onChangeMonitorReady = function(ev) {
        $(ev.target).trigger('change')
    }

    Builder.prototype.onDataRegistryItems = function(ev, data) {
        var self = this

        if (data.propertyDefinition.fillFrom == 'model-classes' ||
            data.propertyDefinition.fillFrom == 'model-forms' ||
            data.propertyDefinition.fillFrom == 'model-lists' ||
            data.propertyDefinition.fillFrom == 'controller-urls' ||
            data.propertyDefinition.fillFrom == 'model-columns' ||
            data.propertyDefinition.fillFrom == 'plugin-lists' ||
            data.propertyDefinition.fillFrom == 'permissions'
        ) {
            ev.preventDefault()

            var subtype = null,
                subtypeProperty = data.propertyDefinition.subtypeFrom

            if (subtypeProperty !== undefined) {
                subtype = data.values[subtypeProperty]
            }

            $.oc.builder.dataRegistry.get($(ev.target), this.getFormPluginCode(ev.target), data.propertyDefinition.fillFrom, subtype, function(response){
                data.callback({
                    options: self.dataToInspectorArray(response)
                })
            })
        }
    }

    // INITIALIZATION
    // ============================

    $(document).ready(function(){
        $.oc.builder.indexController = new Builder()
    })

}(window.jQuery);