/*
 *  Copyright 2016 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.
 */

/**
 * This tool displays the steps to perform to configured Ametys after a fresh installation.
 * It is meant to be the first tool displayed to the administrator user, helping him/her in the configuration.
 * It is opened at admin workspace startup when there are unperformed steps (if userpref 'display-admin-welcome-tool' is not explicitly false)
 */
Ext.define('Ametys.plugins.web.administration.AdminWelcomeTool', {
    extend: 'Ametys.tool.Tool',
    
    statics: {
        /**
         * Checks if the tool can be opened and if so, dot it.
         */
        open: function()
        {
            Ametys.data.ServerComm.callMethod({
                role: "org.ametys.core.ui.UIToolsFactoriesManager",
                id: "uitool-admin-welcome",
                methodName: "canOpenTool",
                parameters: [],
                callback: {
                    handler: this._openCb,
                    scope: this
                },
                waitMessage: false,
                errorMessage: true
            });
        },
        
        /**
         * @private
         * Opens the tool if necessary after retrieving from the server if the tool can be opened
         * @param {Number} canBeOpened Server told it can be opened
         */
        _openCb: function(canBeOpened)
        {
            if (Ametys.tool.ToolsManager.getTool("uitool-admin-welcome") == null // not already open
                && Ametys.userprefs.UserPrefsDAO.getValue("display-admin-welcome-tool") != "false" // user did not explictly say to not open this tool
                && canBeOpened) // server told it can be opened
            {
                Ametys.tool.ToolsManager.openTool("uitool-admin-welcome");
            }
        }
    },
    
    /**
     * @private
     * @property {Number} _currentStep The index of the current step
     */
    
    /**
     * @private
     * @property {Object} _targetIds The target ids (per message type) which lead to a refresh of the tool. Fo instance, can be equals to {"modified": ["^profile$"], "deleted": ["^profile$", "^site$"]}
     */
    _targetIds: {},
    
    createPanel: function ()
    {
        this._panel = Ext.create('Ext.container.Container', {
            cls: 'admin-tool-welcome',
            scrollable: true,
            
            items: [{
                xtype: 'container',
                itemId: 'steps',
                items: [],
                flex: 1
            }, {
                xtype: 'checkbox',
                cls: 'checkbox-do-not-display',
                boxLabel: '{{i18n PLUGINS_WEB_ADMINISTRATOR_UITOOL_ADMIN_WELCOME_DO_NOT_DISPLAY}}',
                checked: !(Ametys.userprefs.UserPrefsDAO.getValue("display-admin-welcome-tool") == 'true'),
                handler: function(checkbox, checked)
                {
                    Ametys.userprefs.UserPrefsDAO.saveValues( { "display-admin-welcome-tool": [(!checked).toString()] }, Ext.emptyFn, "/admin");
                }
            }]
        });
        
        return this._panel;
    },
    
    /**
     * @private
     * Function called after retrieving the steps from the server.
     * @param {Object[]} steps The steps given by the server
     */
    _getStepsCb: function(steps)
    {
        this._displaySteps(steps);
        this._setTargetIds(steps);
        
        this.showRefreshed();
    },
    
    /**
     * @private
     * Displays the steps of the tool
     * @param {Object[]} steps The steps given by the server
     */
    _displaySteps: function(steps)
    {
        var stepsContainer = this._panel.items.get("steps");
        stepsContainer.removeAll();
        stepsContainer.add({
            xtype: 'component',
            html: "{{i18n PLUGINS_WEB_ADMINISTRATOR_UITOOL_ADMIN_WELCOME_INTRO_MESSAGE}}",
            cls: 'welcome-intro'
        });
        
        var count = steps.length;
        Ext.Array.forEach(steps, function(step, index) {
            var cls = 'welcome-step ' + ((this._currentStep == index) ? 'welcome-step-current' : (step.performed ? 'welcome-step-performed' : 'welcome-step-todo')),
                stepNumber = index + 1,
                title = '{{i18n PLUGINS_WEB_ADMINISTRATOR_UITOOL_ADMIN_WELCOME_NUMBER_STEP_1}}' + stepNumber + '{{i18n PLUGINS_WEB_ADMINISTRATOR_UITOOL_ADMIN_WELCOME_NUMBER_STEP_2}}' + count + ' : ' + step.title,
                desc = this._insertImages(this._insertActions(step.description, step.actions), step.images),
                html = '<h1 class="welcome-step-title">' + title + '</h1>' + '<p>' + desc + '</p>',
                isLast = (index == count - 1),
                attachListener = this._currentStep != -1 && isLast; // attach a listener for scrolling to the current only if it is the last component rendered
            stepsContainer.add({
                xtype: 'component',
                itemId: 'step' + index,
                html: html,
                cls: cls,
                listeners: attachListener ? {
                    'afterrender': Ext.bind(function(component, eOpts) {
                        this._scrollToCurrent();
                    }, this)
                } : {}
            });
        }, this);
        
        if (this._currentStep == -1)
        {
            // All steps were performed
            stepsContainer.add({
                xtype: "image",
                itemId: 'image',
                src: Ametys.getPluginDirectPrefix('core-ui') + '/app_logo.jpg',
                alt: 'Ametys'
            }, {
                xtype: 'component',
                html: "{{i18n PLUGINS_WEB_ADMINISTRATOR_UITOOL_ADMIN_WELCOME_COMPLETED}}",
                listeners: {
                    'afterrender': Ext.bind(function(component, eOpts) {
                        this._scrollToCurrent();
                    }, this)
                }
            });
        }
    },
    
    /**
     * @private
     * Scrolls the tool to the current step
     */
    _scrollToCurrent: function()
    {
        this._panel.getScrollable().scrollTo({y: 0}, false);
        var cmp;
        if (this._currentStep != -1)
        {
            cmp = this._panel.items.get('steps').items.get('step' + this._currentStep);
        }
        else
        {
            cmp = this._panel.items.get('steps').items.get('image');
        }
        var posTopTool = this._panel.getY(),
            posTopStep = cmp.getY(),
            diff = posTopStep - posTopTool;
        this._panel.getScrollable().scrollTo({y: diff - 1 /* plus one pixel to be prettier */}, false);
    },
    
    /**
     * @private
     * Inserts the actions of steps into the &lt;a&gt; elments of the HTML text as href javascript actions
     * @param {String} initialText The HTML text
     * @param {String[]} actions The JS actions
     * @return {String} The HTML text with href attributes on &lt;a&gt; elements
     */
    _insertActions: function(initialText, actions)
    {
        var result = '';
                
        var cursor = 0;
        var linkIndex = initialText.indexOf("<a>", 0);
        var actionIndex = 0;
        while (linkIndex != -1 || actionIndex > actions.length)
        {
            result += initialText.substring(cursor, linkIndex);
            result += "<a href=\"javascript:void(0)\" onclick=\""+ actions[actionIndex] + "\">";
            
            cursor = linkIndex + 3;
            linkIndex = initialText.indexOf("<a>", linkIndex + 3);
            actionIndex++;
        }
        
        result += initialText.substring(cursor);
        
        return result;
    },
    
    /**
     * @private
     * Inserts the image paths of steps into the &lt;img/&gt; elments of the HTML text as src attributes
     * @param {String} initialText The HTML text
     * @param {String[]} images The image paths
     * @return {String} The HTML text with src attributes on &lt;img/&gt; elements
     */
    _insertImages: function(initialText, images)
    {
        var result = '';
                
        var cursor = 0;
        var tagIndex = initialText.indexOf("<img/>", 0);
        var imageIndex = 0;
        while (tagIndex != -1 || imageIndex > images.length)
        {
            result += initialText.substring(cursor, tagIndex);
            result += "<img src=\""+ images[imageIndex] + "\"/>";
            
            cursor = tagIndex + 6;
            tagIndex = initialText.indexOf("<img/>", tagIndex + 6);
            imageIndex++;
        }
        
        result += initialText.substring(cursor);
        
        return result;
    },
    
    /**
     * @private
     * Sets the target ids.
     * @param {Object[]} steps The steps given by the server
     */
    _setTargetIds: function(steps)
    {
        Ametys.message.MessageBus.unAll(this);
        
        this._targetIds = {};
        Ext.Array.forEach(steps, function(step) {
            Ext.Object.each(step.targetIds || {}, function(messageType, targetIds) {
                var regExpTargetIds = targetIds.map(function(targetId) {return new RegExp(targetId, "g");});
                this._targetIds[messageType] = Ext.Array.merge(this._targetIds[messageType] || [], regExpTargetIds);
            }, this);
        }, this);
        
        Ext.Object.each(this._targetIds, function(messageType) {
            Ametys.message.MessageBus.on(messageType, Ext.bind(this._messageListener, this), this);
        }, this);
    },
    
    refresh: function()
    {
        this.showRefreshing();

        this.serverCall("getCurrentStep", [], function(currentStep) {
            this._currentStep = currentStep;
            this.serverCall("getSteps", [], this._getStepsCb);
        });
    },
    
    setParams: function(params)
    {
        this.callParent(arguments);
        
        this.showOutOfDate();
    },
    
    getMBSelectionInteraction: function() 
    {
        return Ametys.tool.Tool. MB_TYPE_LISTENING;
    },
    
    /**
     * @private
     * Listener on message
     * @param {Ametys.message.Message} message The message
     */
    _messageListener: function(message)
    {
        var targetIds = this._targetIds[message.getType()] || [];
        var targets = message.getTargets(function(target) {
            return Ext.Array.filter(targetIds, function(regExp) {return regExp.exec(target.getId()) != null;})
                            .length > 0;
        });
        
        if (targets.length > 0)
        {
            this.showOutOfDate();
        }
    }
});

/*
 * Calls the open static method at startup
 */
Ametys.message.MessageBus.on(Ametys.message.Message.SELECTION_CHANGED, function(message) {
    Ametys.plugins.web.administration.AdminWelcomeTool.open();
    Ametys.message.MessageBus.unAll(Ametys.plugins.web.administration.AdminWelcomeTool);
    
}, Ametys.plugins.web.administration.AdminWelcomeTool);