// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

// {namespace name=backend/viison_shipping_common_config/config}
Ext.define('Shopware.apps.ViisonShippingCommonConfig.controller.Main', {

    extend: 'Ext.app.Controller',

    /**
     * Class property which holds the main application if it is created
     *
     * @default null
     * @object
     */
    mainWindow: null,

    /**
     * Class property which holds the order config class name
     */
    orderConfigDataClass: 'Shopware.apps.ViisonShippingCommonOrder.store.OrderConfigData',

    /**
     * Creates the necessary event listeners for this specific
     * controller and creates the window for this sub-application.
     */
    init: function () {
        var additionalDataObject = { additionalData: this.createAdditionalWindowData() };
        this.mainWindow = this.getView('Window').create(additionalDataObject);
        this.mainWindow.show();

        this.mainWindow.loadMask.show();
        this.isFirstConfigStoreLoad = true;
        this.updateShopStore();

        this.initKeyMap();
        this.control({
            'viison-shipping-common-config-window': {
                clickSaveButton: this.onClickSaveButton,
                clickResetButton: this.onClickResetButton,
                beforehide: this.onBeforeHideWindow,
            },
            'viison-shipping-common-config-panel': {
                shopComboboxChange: this.onShopComboboxChange,
                beforeShopComboboxSelect: this.onBeforeShopComboboxSelect,
            },
        });
    },

    /**
     * Register key handlers for the configuration window.
     */
    initKeyMap: function () {
        this.map = new Ext.util.KeyMap(this.getWindow().getEl(), [{
            key: 's',
            ctrl: true,
            handler: this.onKeyHandler,
            scope: this,
            defaultEventAction: 'preventDefault',
        }]);
    },

    /**
     * Handle keyboard shortcuts.
     *
     * @param { integer } key The key code of the key that was pressed.
     */
    onKeyHandler: function (key) {
        switch (key) {
            case 83:
                this.saveConfig(this.getPanel());
                break;
            default:
        }
    },

    /**
     * Set the config values for the newly selected shop.
     *
     * @param { Shopware.apps.ViisonShippingCommonConfig.view.Panel } configPanel
     * @param { Shopware.apps.Base.model.Shop } newShop
     */
    onShopComboboxChange: function (configPanel, newShop) {
        configPanel.configValuePanel.removeAll();
        configPanel.configValuePanel.add([{
            xtype: 'config-fieldset',
            items: configPanel.getConfigItemsForShop(newShop),
        }]);
        this.setConfigValuesOnFormForShop(configPanel, newShop);
    },

    /**
     * Show a Message Box to confirm changing the shop if unsaved changes are detected.
     *
     * @param { Shopware.apps.ViisonShippingCommonConfig.view.Panel } configPanel
     * @param { Ext.form.field.ComboBox } shopCombobox
     * @param { Shopware.apps.Base.model.Shop } newlySelectedShop
     * @returns { boolean }
     */
    onBeforeShopComboboxSelect: function (configPanel, shopCombobox, newlySelectedShop) {
        var changes = configPanel.hasModifiedItems();
        if (!changes) {
            return true;
        }

        var newValue = newlySelectedShop.get('id');
        var oldValue = shopCombobox.getValue();

        if (newValue === oldValue) {
            return true;
        }

        Ext.Msg.show({
            title: '{s name="saving_prompt/title"}{/s}',
            msg: '{s name="saving_prompt/text"}{/s}',
            buttons: Ext.Msg.YESNOCANCEL,
            icon: Ext.Msg.QUESTION,
            fn: function (buttonValue) {
                if (buttonValue === 'cancel') {
                    shopCombobox.setValue(oldValue);

                    return;
                }

                if (buttonValue === 'yes') {
                    this.saveConfig(configPanel, function () {
                        shopCombobox.setValue(newValue);
                    });
                } else {
                    this.resetConfigFieldsOnForm(configPanel);
                    shopCombobox.setValue(newValue);
                }
            },
            scope: this,
        });

        return false;
    },

    onBeforeHideWindow: function (window) {
        var configPanel = window.configPanel;
        var changes = configPanel.hasModifiedItems();
        if (!changes) {
            return true;
        }

        Ext.Msg.show({
            title: '{s name="saving_prompt/title"}{/s}',
            msg: '{s name="saving_prompt/text"}{/s}',
            buttons: Ext.Msg.YESNOCANCEL,
            icon: Ext.Msg.QUESTION,
            fn: function (buttonValue) {
                if (buttonValue === 'yes') {
                    this.saveConfig(configPanel, function () {
                        this.resetConfigFieldsOnForm(configPanel);
                        window.close();
                    }.bind(this));
                } else if (buttonValue === 'no') {
                    this.resetConfigFieldsOnForm(configPanel);
                    window.close();
                }
            },
            scope: this,
        });

        return false;
    },

    /**
     * @param { Shopware.apps.ViisonShippingCommonConfig.view.Panel } configPanel
     */
    onClickSaveButton: function (configPanel) {
        this.saveConfig(configPanel, function () {
            this.resetConfigFieldsOnForm(configPanel);
        }.bind(this));
    },

    /**
     * @param { Shopware.apps.ViisonShippingCommonConfig.view.Panel } configPanel
     */
    onClickResetButton: function (configPanel) {
        this.resetConfigFieldsOnForm(configPanel);
    },

    /**
     * Load the default values for the currently selected shop and set them.
     *
     * @param { Shopware.apps.ViisonShippingCommonConfig.view.Panel } configPanel
     */
    resetConfigFieldsOnForm: function (configPanel) {
        var shop = configPanel.shopCombobox.getStore().getById(configPanel.shopCombobox.getValue());
        this.setConfigValuesOnFormForShop(configPanel, shop);
    },

    /**
     * @param { Shopware.apps.ViisonShippingCommonConfig.view.Panel } configPanel
     * @param { Shopware.apps.Base.model.Shop } shop
     */
    setConfigValuesOnFormForShop: function (configPanel, shop) {
        // Suspending the layouts here improves the performance significantly.
        Ext.suspendLayouts();
        configPanel.getForm().setValues(this.getConfigPairsForShop(shop, configPanel));
        Ext.resumeLayouts();
    },

    /**
     * Save the configuration for all subshops. If an configuration existed
     * before for a subshop, it is updated, if not, a new record is created.
     */
    saveConfig: function (configPanel, callback) {
        // Check the form and record
        var form = configPanel.getForm();

        if (!form.isValid()) { // At least one field is invalid
            // Switch to the tab where the first invalid field is
            var items = form.getFields().items;

            for (var i = 0; i < items.length; i++) {
                var field = items[i];
                if (!field.disabled && !field.isValid()) {
                    // Scroll to the invalid field
                    field.el.scrollIntoView(this.getWindow().el.child('.x-window-body'));
                    break;
                }
            }

            var notification = this.snippets.notifications.saveConfigurationValidationError;
            Shopware.Notification.createGrowlMessage(notification.title, notification.message, this.snippets.notifications.growlMessage);

            return;
        }

        var shopId = configPanel.shopCombobox.getValue();
        var shop = configPanel.shopCombobox.getStore().getById(shopId);
        var configRecord = this.getConfigRecordForShop(shop);

        // Update all changed fields in the record
        var fields = configRecord.fields.items;
        Ext.each(fields, function (field) {
            var fieldName = 'values[' + shopId + '][' + field.name + ']';
            var formField = form.findField(fieldName);
            if (!formField) {
                return true; // continue Ext.each loop
            }
            var value = formField.getSubmitValue();
            if ((typeof value) === 'string') {
                value = value.trim();
            }
            configRecord.set(field.name, value);
        });

        // Save the record
        configRecord.save({
            callback: function (record, operation) {
                var notification = operation.success ? this.snippets.notifications.saveConfigurationSuccess : this.snippets.notifications.saveConfigurationError;
                Shopware.Notification.createGrowlMessage(notification.title, notification.message, this.snippets.notifications.growlMessage);

                this.updateConfigStore();
                if (typeof callback === 'function') {
                    callback();
                }
            },
            scope: this,
        });
    },

    /**
     * Add possibility that a Adapter can inject data to the Window
     *
     * Note: The data will always be transferred to the View in a 'additionalData' object
     *
     * @return object
     */
    createAdditionalWindowData: function () {
        return { };
    },

    /**
     * Reloads the shop store and displays an error message, if the process failed.
     */
    updateShopStore: function () {
        this.shopStore = Ext.create('Shopware.apps.ViisonShippingCommonConfig.store.ShopLanguage'); // TODO: Change this class to Shopware.apps.Base.store.ShopLanguage as soon as Shopware 4.1.3 is a minimum requirement of our plugins.
        this.shopStore.load({
            callback: function (records, operation, success) {
                if (!success) {
                    var notification = this.snippets.notifications.loadAllConfigurationsError;
                    Shopware.Notification.createGrowlMessage(notification.title, notification.message, this.snippets.notifications.growlMessage);
                } else {
                    this.updateConfigStore();
                }
            },
            scope: this,
        });
    },

    /**
     * Retrieve the config from the configStore and map all configValues to the required format so we can set
     * them on the Form.
     *
     * @param { Shopware.apps.Base.model.Shop } shop
     * @param { Shopware.apps.ViisonShippingCommonConfig.view.Panel } configPanel
     */
    getConfigPairsForShop: function (shop, configPanel) {
        var config = this.getConfigRecordForShop(shop);
        // Set field values from record
        var configPairs = {};
        Ext.iterate(config.data, function (configKey, configValue) {
            if (configKey === 'id') {
                return true; // continue Ext.iterate loop
            }

            // This is not a good place for this manipulation but unfortunately because of the tight coupling
            // of this methods and the dynamic model that is managed in every adapter on it's own
            // it is hard to find a good way to manipulate the data after a save/update ...
            // The load logic needs to be more straight forward and do a lazy load it is a big TODO
            if (configKey === 'cashOnDeliveryPaymentMeansIds') {
                if (!configValue) {
                    configValue = [];
                } else {
                    // Split string into a array and convert the elements to a int if possible
                    configValue = configValue.split(',').map(function (id) {
                        return parseInt(id, 10);
                    });
                }
            }

            configPairs['values[' + shop.getId() + '][' + configKey + ']'] = configValue;
        });

        // Function that can be called in each Adapter if additional on load steps are necessary
        this.additionalFormSetupOnLoad && this.additionalFormSetupOnLoad(configPairs, shop.getId(), configPanel.getForm(), configPanel);

        return configPairs;
    },

    /**
     * If the config for the specified shop does not exist yet it is added to the store.
     *
     * @param { Shopware.apps.Base.model.Shop } shop
     * @returns { Ext.data.Model }
     */
    getConfigRecordForShop: function (shop) {
        var configRecordIndex = this.configStore.findExact('shopId', shop.getId());
        var configRecord;
        if (configRecordIndex >= 0) {
            configRecord = this.configStore.getAt(configRecordIndex);
        } else {
            configRecord = Ext.create(this.dispatchServiceProviderConfigModelClass, {
                shopId: shop.getId(),
            });
            this.configStore.add(configRecord);
        }

        return configRecord;
    },

    /**
     * Reloads the config store and displays an error message, if the process failed.
     */
    updateConfigStore: function () {
        this.configStore.load({
            callback: function (records, operation, success) {
                if (!success) {
                    var notification = this.snippets.notifications.loadAllConfigurationsError;
                    Shopware.Notification.createGrowlMessage(notification.title, notification.message, this.snippets.notifications.growlMessage);
                } else {
                    if (this.isFirstConfigStoreLoad) {
                        this.isFirstConfigStoreLoad = false;
                        var window = this.getWindow();
                        window.addPanel();
                        window.loadMask.hide();
                        var configPanel = window.configPanel;
                        configPanel.initForm(this.shopStore);
                        configPanel.shopCombobox.setValue(this.shopStore.getAt(0).get('id'));
                    }
                }
            },
            scope: this,
        });
    },

});
