/*
 *  Copyright 2014 Anyware Services
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/**
 * Singleton class to handle actions on skin.
 */
Ext.define('Ametys.plugins.skinfactory.skin.SkinActions', {
    singleton : true,

    /**
     * Action called by the controller to unlinkModel
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
	unlinkModel: function (controller)
	{
		var targets = controller.getMatchingTargets();
		if (targets.length > 0)
		{
			var me = this;

			Ametys.Msg.confirm("{{i18n PLUGINS_SKINFACTORY_SKIN_MODEL_UNLINK_LABEL}}",
				"{{i18n PLUGINS_SKINFACTORY_SKIN_MODEL_UNLINK_CONFIRM}}",
				function(answer)
		        {
		            if (answer == 'yes')
		            {
		            	Ametys.plugins.skinfactory.model.SkinModelDAO.unlinkModel([targets[0].getParameters().name, targets[0].getParameters().model], Ext.bind(me._unlinkModelCb, me), {});
		            }
	 	       }
 	       );
		}	
	},

	/**
	 * Callback after unlinking a skin from its model
	 * @private
	 */
	_unlinkModelCb: function()
	{
		Ametys.Msg.show({
			title: "{{i18n PLUGINS_SKINFACTORY_SKIN_MODEL_UNLINK_LABEL}}",
			msg: "{{i18n PLUGINS_SKINFACTORY_SKIN_MODEL_UNLINK_SUCCESS}}",
			buttons: Ext.Msg.OK,
			icon: Ext.MessageBox.INFO
		});
	},

    /**
     * Action called by the controller to apply a model to its skin
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
	applyModel: function (controller)
	{
		var targets = controller.getMatchingTargets();
		if (targets.length > 0)
		{
			var me = this;
			
			Ametys.Msg.confirm("{{i18n PLUGINS_SKINFACTORY_SKIN_MODEL_APPLY_LABEL}}", 
				"{{i18n PLUGINS_SKINFACTORY_SKIN_MODEL_APPLY_CONFIRM}}",
				function(answer)
		        {
		            if (answer == 'yes')
		            {
		            	Ametys.plugins.skinfactory.model.SkinModelDAO.applyModel([targets[0].getParameters().name, targets[0].getParameters().model], Ext.bind(me._applyModelCb, me), {});
		            }
	 	       }
 	       );
		}
	},

	/**
	 * Callback after applying a model to a skin
	 * @param {Boolean} success true if the skin was successfully updated
	 * @private
	 */
	_applyModelCb: function(success)
	{
        if (success)
        {
            Ametys.Msg.show({
	            title: "{{i18n PLUGINS_SKINFACTORY_SKIN_MODEL_APPLY_LABEL}}",
	            msg: "{{i18n PLUGINS_SKINFACTORY_SKIN_MODEL_UNLINK_SUCCESS}}",
	            buttons: Ext.Msg.OK,
	            icon: Ext.MessageBox.INFO
            });
        }
	},
    
    /**
     * Action called by the controller to open the skin factory tool
     */
    open: function ()
    {
        Ametys.plugins.skincommons.helper.SkinHelper.getSkinModel(Ametys.plugins.skinfactory.skin.SkinDAO.SERVER_ROLE, Ametys.getAppParameter('siteName'), null, null, Ext.bind(this._getSkinModelCb, this));
    },
    
    /**
     * @private
	 * Callback for the {#Ametys.plugins.skincommons.helper.SkinHelper.getSkinModel} call
	 * @param {String} skinName The skin name
	 * @param {String} modelName The model of the skin. Can be null if the skin has no model
	 */
	_getSkinModelCb: function (skinName, modelName)
    {
        if (modelName == null)
    	{
    		// No model
    		Ametys.Msg.show({
    			title: "{{i18n PLUGINS_SKINFACTORY_TOOL_LABEL}}",
    			msg: "{{i18n PLUGINS_SKINFACTORY_TOOL_MODEL_NOT_FOUND}}",
    			buttons: Ext.Msg.OK,
    			icon: Ext.MessageBox.WARN
    		});
    		
    		return;
    	}
    	
    	// Check if Skin Editor tool is opened
    	var tool = Ametys.tool.ToolsManager.getTool("uitool-skineditor")
    	if (tool != null)
    	{
    		Ametys.Msg.show({
    			title: "{{i18n PLUGINS_SKINFACTORY_TOOL_LABEL}}",
    			msg: "{{i18n PLUGINS_SKINFACTORY_TOOL_SKIN_EDITOR_OPEN}}",
    			buttons: Ext.Msg.OK,
    			icon: Ext.MessageBox.ERROR
    		});
    		
    		return;
    	}

        Ametys.plugins.skincommons.helper.SkinHelper.getLockParams(Ametys.plugins.skinfactory.skin.SkinDAO.SERVER_ROLE, Ametys.getAppParameter('siteName'), null, Ext.bind(this._getLockParamsCb, this, [modelName], true));
    },

    /**
	 * Callback for the {#Ametys.plugins.skincommons.helper.SkinHelper.getLockParams} call
	 * @param {Object} lockParams the lock parameters
	 * @param {String} modelName The model of the skin.
	 * @private
	 */    
    _getLockParamsCb: function (lockParams, modelName)
    {
        if (lockParams.isLocked || (lockParams.toolId != null && lockParams.toolId != 'uitool-skinfactory'))
    	{
    		if (lockParams.isLocked)
    		{
    			// The skin is locked by another user
    			var msg = "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_USER_LOCKED_CONFIRM_1}}" + "<b>" + lockParams.lockOwner + "</b>" 
    			+ "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_USER_LOCKED_CONFIRM_2}}" + lockParams.toolTitle 
    			+ "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_USER_LOCKED_CONFIRM_3}}" + lockParams.lockDate 
    			+ "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_USER_LOCKED_CONFIRM_4}}";
    	
    			if (lockParams.toolId != 'uitool-skinfactory')
    			{
    				msg += "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_USER_LOCKED_CONFIRM_5}}";
    			}
    			msg += "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_USER_LOCKED_CONFIRM_6}}";
    		}
    		else
    		{
    			// The skin is locked by current user by another tool
    			var msg = "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_TOOL_LOCKED_CONFIRM_1}}" + lockParams.toolTitle 
    					+ "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_TOOL_LOCKED_CONFIRM_2}}" + lockParams.lockDate 
    					+ "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_TOOL_LOCKED_CONFIRM_3}}";
    		}
            
            var me = this;
    		
    		Ametys.Msg.show({
    			   title: "{{i18n PLUGINS_SKINFACTORY_TOOL_LABEL}}",
    			   msg: msg,
    			   buttons: Ext.MessageBox.YESNO,
    			   fn: function(answer)
    		       {
    				   if (answer == 'yes')
    		           {
    		               Ametys.plugins.skincommons.helper.ChooseOpenMode.open({
                                iconCls: 'ametysicon-painter14',
                                title: "{{i18n PLUGINS_SKINFACTORY_OPEN_DIALOG_TITLE}}",
                                helpMessage: "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_CHOOSEOPENMODE_TEMP_HINT}}",
                                lockDate: lockParams.lockDate,
                                lastSave: lockParams.lastSave,
                                callback: Ext.bind(me._chooseModeCb, me, [modelName], true)
                            });
    		           }
    		       },
    			   icon: Ext.MessageBox.WARNING
    		});
    	}
    	else if (lockParams.lockDate != null || lockParams.lastSave != null)
    	{
    		// There are unsave modifications
    		Ametys.plugins.skincommons.helper.ChooseOpenMode.open({
                iconCls: 'ametysicon-painter14',
                title: "{{i18n PLUGINS_SKINFACTORY_OPEN_DIALOG_TITLE}}",
                helpMessage: lockParams.lockDate == null ? "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_CHOOSEOPENMODE_WORK_HINT}}" : "{{i18n plugin.skincommons:PLUGINS_SKINCOMMONS_CHOOSEOPENMODE_TEMP_HINT}}", 
                lockDate: lockParams.lockDate,
                lastSave: lockParams.lastSave,
                callback: Ext.bind(this._chooseModeCb, this, [modelName], true)
            });
    	}
    	else
    	{
    		// Open skin in prod mode
            Ametys.plugins.skinfactory.skin.SkinDAO.openSkin([Ametys.getAppParameter("siteName"), 'prod'], Ext.bind(this._openSkinCb, this), {arguments: {mode: 'prod', modelName: modelName}});
    	}
    },

    /**
     * Callback after choosing the edition mode for the skin
     * @param  {String} mode The open mode
     * @param  {String} modelName The model name
     * @private
     */
    _chooseModeCb: function (mode, modelName)
    {
    	if (mode != null)
    	{
            Ametys.plugins.skinfactory.skin.SkinDAO.openSkin([Ametys.getAppParameter("siteName"), mode], Ext.bind(this._openSkinCb, this), {arguments: {mode: mode, modelName: modelName}});
    	}
    },
    
    /**
     * @private
     * Callback after opening a skin
     * @param {Object} response The skin informations, or the error code
     * @param {String} response.skinId The id of the skin
     * @param {Object} args The callback arguments
     * @param {String} args.mode The opening mode
     * @param {String} args.modelName The name of the model
     */
    _openSkinCb: function (response, args)
    {
        if (response["model-not-found"] == 'true')
		{
			// No model
			Ametys.Msg.show({
				title: "{{i18n PLUGINS_SKINFACTORY_TOOL_LABEL}}",
				msg: "{{i18n PLUGINS_SKINFACTORY_TOOL_MODEL_NOT_EXIST}}",
				buttons: Ext.Msg.OK,
				icon: Ext.MessageBox.WARN
			});
			
			return;
		}
        
        function onRibbonLoaded ()
        {
        	Ametys.tool.ToolsManager.openTool("uitool-skinfactory", {mode: args.mode, modelName: args.modelName, skinId: response.skinId, checksDone: true});  
        }
        
        Ametys.loadScript(Ametys.getPluginDirectPrefix('skinfactory') + '/' + response.skinId + '/' + args.modelName + '/ribbon.js', onRibbonLoaded);
    },
    
    // ----------------------------------- CANCEL ------------------------------------
    /**
     * Action to cancel any changes made to the skin
     */
    cancelChanges: function ()
    {
        var tool = Ametys.tool.ToolsManager.getTool('uitool-skinfactory');
        var skinName = tool.getSkinName();

        Ametys.plugins.skincommons.CommonSkinActions.cancelChanges(Ametys.plugins.skinfactory.skin.SkinDAO.SERVER_ROLE, skinName, false, 'uitool-skinfactory', Ext.bind(this._cancelChangesCb, this));
    },

    /**
     * Callback after the changes were reverted. Refresh the impacted tools
     * @param {Boolean} success True if the changes were reverted
     * @param {Boolean} modelChanged True if the model changed
     */
    _cancelChangesCb: function (success, modelChanged)
    {
        if (!modelChanged)
        {
            // Reload parameters 
            Ametys.plugins.skinfactory.SkinParametersManager.loadParametersValues(Ametys.getAppParameter("siteName"));
            
            // Refresh tool
            var tool = Ametys.tool.ToolsManager.getTool('uitool-skinfactory');
            if (tool)
            {
                tool.showOutOfDate();
            }
        }
        else
        {
            Ametys.Msg.alert("{{i18n PLUGINS_SKINFACTORY_CANCELCHANGES_LABEL}}", 
                "{{i18n PLUGINS_SKINFACTORY_CANCELCHANGES_REDIRECT}}", 
                this._redirect,
                this);
        }
    },
    
    /**
     * Reload the cms
     * @private
     */
    _redirect: function () 
    {
        // Reload application
        window.location.href = Ametys.CONTEXT_PATH + '/' + Ametys.getAppParameter("siteName") + '/' + 'index.html';
    },

    // ----------------------------------- SAVE ------------------------------------
    /**
     * Action to change the current modification of the skin
     */
    saveChanges: function ()
    {
        this._doSave(false);
    },

    /**
     * Action to change the current modification of the skin, and close the editor
     */
    saveChangesAndQuit: function ()
    {
        this._doSave(true);
    },

    /**
     * Save the changes of the skin
     * @param {Boolean} quit True to close the editor after saving
     * @private
     */
    _doSave: function (quit)
    {
        var tool = Ametys.tool.ToolsManager.getTool('uitool-skinfactory');
        var skinName = tool.getSkinName();

        Ametys.plugins.skincommons.CommonSkinActions.saveChanges(Ametys.plugins.skinfactory.skin.SkinDAO.SERVER_ROLE, skinName, quit, Ext.bind(this._saveChangesCb, this));
    },

    /**
     * Callback for the {#_doSave} method.
     * @param {Boolean} success True if the changes were successfully saved
     * @param {Boolean} quit True to close the tools after saving
     */
    _saveChangesCb: function (success, quit)
    {
        if (success && quit)
        {
            // Close tool
            Ametys.tool.ToolsManager.getTool('uitool-skinfactory').close();
        }
    },


    // ----------------------------------- COMMIT ------------------------------------

    /**
     * Action to commit the current modification to the skin
     */
    commitChanges: function ()
    {
        this._startCommit(false);
    },

    /**
     * Action to commit the current modification to the skin, and close the tools after.
     */
    commitChangesAndQuit: function ()
    {
        this._startCommit(true);
    },

    /**
     * Commit the changes into the real skin
     * @param {Boolean} quit True to close the skin after edition
     * @private
     */
    _startCommit: function (quit)
    {
        Ametys.Msg.confirm("{{i18n PLUGINS_SKINFACTORY_COMMITCHANGES_LABEL}}",
            "{{i18n PLUGINS_SKINFACTORY_COMMITCHANGES_CONFIRM}}",
            function (btn)
            {
                if (btn == 'yes')
                {
                    this._doCommit(quit);
                }
            },
            this
        );
    },

    /**
     * Callback for the confirmation button. Do the commit
     * @param {Boolean} quit True to close the tools after commiting
     */
    _doCommit: function (quit)
    {
        var tool = Ametys.tool.ToolsManager.getTool("uitool-skinfactory");

        Ametys.plugins.skincommons.CommonSkinActions.commitChanges(Ametys.plugins.skinfactory.skin.SkinDAO.SERVER_ROLE, tool.getSkinName(), quit, Ext.bind(this._commitCb, this));
    },

    /**
     * Callback for the {#_doCommit} method.
     * @param {Boolean} success True if the commit was successful
     * @param {Boolean} quit True to close all the skin editor tools
     */
    _commitCb: function (success, quit)
    {
        if (this._waitMsg != null)
        {
            this._waitMsg.hide();
            delete this._waitMsg;
        }

        if (success && quit)
        {
            // Close tool
            Ametys.tool.ToolsManager.getTool('uitool-skinfactory').close();
        }
    },
    
    /**
     * Action called by the controller to change the current language
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    selectLang: function (controller)
    {
        var lang = controller.lang;
        
        if (lang != Ametys.plugins.skinfactory.SkinParametersManager.getCurrentLanguage())
        {
            Ametys.plugins.skinfactory.SkinParametersManager.updateCurrentLanguage(lang);
            
            Ext.create("Ametys.message.Message", {
                type: Ametys.message.Message.MODIFIED,
                targets: {
                    id: Ametys.message.MessageTarget.SKIN_LANGUAGE,
                    parameters: {
                        lang: lang
                    }
                }
            });
        }
    },
    
    /**
     * Action called by the controller to restore the default model parameters
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    restoreDefaults: function (controller)
    {
        var tool = Ametys.tool.ToolsManager.getTool("uitool-skinfactory");
        var skinId = tool.getSkinName();
        Ametys.plugins.skinfactory.skin.SkinDAO.restoreDefaults([skinId], Ext.bind(this._skinParametersCb, this), {arguments: {skinId: skinId}});
    },
    
    /**
     * Callback after changing the skin parameters
     * @param {Object} response The skin informations, or an error code.
     * @param {Object} args The callback arguments.
     */
    _skinParametersCb: function (response, args)
    {
        // Check for errors
        if (Ametys.plugins.skincommons.helper.SkinHelper.handleLockError(response) || this.handleUnknowModelError(response))
        {
            return ;
        }
        
        Ametys.plugins.skinfactory.SkinParametersManager.updateParametersValues(response.parameters);
        
        if (response.themeId)
    	{
    		Ametys.plugins.skinfactory.SkinParametersManager.updateColorTheme(response.themeId, response.colors);
    	}
    	else
    	{
    		Ametys.plugins.skinfactory.SkinParametersManager.updateColorTheme(null, []);
    	}
        
        Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.MODIFIED,
            targets: {
                id: Ametys.message.MessageTarget.SKIN_PARAMETER,
                parameters: {
                    id: args.skinId
                }
            }
        });
    },
    
    /**
     * Handler for the "unknow model" responses from server
     * @param {Object} response The response Object
     * @param {String} [response.unknownModel] If exists, the server returned an error.
     * @return {boolean} return True if the model is unknown.
     */
    handleUnknowModelError: function (response)
    {
        if (response != null && response.unknownModel)
        {
            Ametys.Msg.show ({
                title: "{{i18n PLUGINS_SKINFACTORY_UNKNOWN_MODEL_ERROR_TITLE}}",
                msg: "{{i18n PLUGINS_SKINFACTORY_UNKNOWN_MODEL_ERROR_HINT_1}}" + response.modelName + "{{i18n PLUGINS_SKINFACTORY_UNKNOWN_MODEL_ERROR_HINT_2}}",
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
            
            return true;
        }
        
        return false;
    },
    
    /**
     * Action called by the controller to change the model language
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    selectModel: function (controller)
    {
        var model = controller.modelName;
        
        if (Ametys.plugins.skinfactory.SkinParametersManager.getCurrentModel() != model)
        {
            var tool = Ametys.tool.ToolsManager.getTool("uitool-skinfactory");
            var skinId = tool.getSkinName();
            Ametys.plugins.skinfactory.helper.ChangeModelUI.open(model, skinId, Ext.bind(this._selectModelCb, this));
        }
    },
    
    /**
     * Callback after changing the current skin model
     * @param {Object} response The server response object
     * @private
     */
    _selectModelCb: function (response)
    {
        // Check for errors
        if (Ametys.plugins.skincommons.helper.SkinHelper.handleLockError(response) || this.handleUnknowModelError(response))
        {
            return ;
        }
        
        Ametys.Msg.alert("{{i18n PLUGINS_SKINFACTORY_SELECT_MODEL_LABEL}}", "{{i18n PLUGINS_SKINFACTORY_CHANGE_MODEL_REDIRECT}}", this._redirect);
    },
    
    /**
     * Action called by the controller to affect a design to the current skin
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    affectDesign: function (controller)
    {
        var tool = Ametys.tool.ToolsManager.getTool("uitool-skinfactory");
        var skinId = tool.getSkinName();
        var designId = controller.designId;
        Ametys.plugins.skinfactory.skin.SkinDAO.affectDesign([skinId, designId], Ext.bind(this._skinParametersCb, this), {arguments: {skinId: skinId}});
    },
    
    /**
     * Action called by the controller to update the color theme of the current skin.
     * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
     */
    updateColorTheme: function (controller)
    {
        var tool = Ametys.tool.ToolsManager.getTool("uitool-skinfactory");
        var skinId = tool.getSkinName();
        var themeId = controller.theme;
        Ametys.plugins.skinfactory.skin.SkinDAO.updateColorTheme([skinId, themeId], Ext.bind(this._updateColorThemeCb, this));
    },
    
    /**
     * Callback after updating the color theme
     * @param {Object} response The server response object
     */
    _updateColorThemeCb: function (response)
    {
        // Check for errors
        if (Ametys.plugins.skincommons.helper.SkinHelper.handleLockError(response) || this.handleUnknowModelError(response))
        {
            return;
        }
        
        Ametys.plugins.skinfactory.SkinParametersManager.updateColorTheme (response.themeId, response.colors);
    },
    
    /**
     * Update a parameter
     * @param {String} paramId The id of the parameter
     * @param {String} value The new value
     * @param {String} lang The language
     * @param {Object} [additionalParams] Optional additional parameters
     */
    updateParameter: function (paramId, value, lang, additionalParams)
    {
    	if (Ametys.plugins.skinfactory.SkinParametersManager.getParameterValue(paramId) == value)
        {
    		return;
        }
    	
        var tool = Ametys.tool.ToolsManager.getTool("uitool-skinfactory");
        var skinName = tool.getSkinName();
    	if (lang == null)
    	{
    		lang = Ametys.plugins.skinfactory.SkinParametersManager.getCurrentLanguage();
    	}
    	
        additionalParams = additionalParams || {};
        Ametys.plugins.skinfactory.skin.SkinDAO.updateParameter([skinName, lang, paramId, value, additionalParams.uploaded || false], Ext.bind(this._updateParameterCb, this));
    },

    /**
     * @private
     * Callback after updating a parameter
     * @param {Object} response The server's response
     */
    _updateParameterCb: function (response)
    {
        // Check for errors
        if (Ametys.plugins.skincommons.helper.SkinHelper.handleLockError(response) || this.handleUnknowModelError(response))
        {
            return ;
        }

    	Ametys.plugins.skinfactory.SkinParametersManager.updateParametersValues(response);
    },
    
    /**
     * Action to upload an image to the server for a specific skin parameter.
     * @param {String} skinName The skin name
     * @param {String} paramId The parameter id
     */
    uploadImage: function (skinName, paramId)
    {
        Ametys.helper.FileUpload.open({
            title: "{{i18n PLUGINS_SKINFACTORY_UPLOAD_IMAGE_TITLE}}",
            iconCls: 'ametysicon-image2',
            callback: Ext.bind(this._uploadImageCb, this, [skinName, paramId], 2),
            filter: Ametys.helper.FileUpload.IMAGE_FILTER
        });
    },
    
    /**
     * Callback function to be executed after a file has been uploaded.
     * @param {String} id The file id.
     * @param {String} fileName The file name
     * @param {String} skinName The name of the skin edited.
     * @param {String} paramId The id of the skin parameter.
     */
    _uploadImageCb: function (id, fileName, skinName, paramId)
    {
         Ametys.plugins.skinfactory.skin.SkinDAO.uploadLocalImage([id, fileName, skinName, paramId], Ext.bind(this._updateParameterCb, this));
    }
});