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

/**
 * @private
 * Singleton gathering forms-related action and the grid listing the forms of a selection of contents
 */
Ext.define('Ametys.plugins.forms.content.tool.FormsActions' , {
	
	singleton: true,
	
	/**
	 * @private
	 * @property {Boolean} _initialized is the form initialized ?
	 */
	
	/**
	 * @private
	 * @property {Ametys.window.DialogBox} _box the dialog box
	 */
	
	/**
	 * @private
	 * @property {Ext.grid.Panel} _grid the forms grid
	 */
	
	/**
	 * @private
	 * @property {Function} _callback the callback function
	 */
	
	
	/**
	 * Export the selected form to XLS format
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
	 */
	'export': function(controller)
	{
		var contentFormTarget = controller.getMatchingTargets()[0];
		
		if (contentFormTarget.length == 0)
	    {
	        Ametys.Msg.show({
	           title: '{{i18n PLUGINS_FORMS_CHOOSE_FORM_DIALOG_CAPTION}}',
	           msg: '{{i18n PLUGINS_FORMS_CHOOSE_FORM_DIALOG_NO_FORM_SELECTED}}',
	           buttons: Ext.Msg.OK,
	           icon: Ext.MessageBox.INFO
	        });
	        return;
	    }
		
	    var formId = contentFormTarget.getParameters().id;
	    var formLabel = contentFormTarget.getParameters().label;

	    Ametys.openWindow(Ametys.getPluginDirectPrefix('forms') + '/' + Ametys.getAppParameter('siteName') + '/export/' + formId + '.xls');
	},
	
	/**
	 * Display the selected form in a grid
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
	 */
	show: function(controller)
	{
		this._act(controller, "{{i18n PLUGINS_FORMS_CHOOSE_FORM_DIALOG_TITLE_SHOW}}", this._showForm)
	},
	
	/**
     * Open the selected form
     * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
     */
    openForm: function(controller)
    {
    	var contentFormTarget = controller.getMatchingTargets()[0];
		var params = contentFormTarget.getParameters();
    	this._showForm(params.id, params.name, params.workflowName, params.contentId);
    },
	
	/**
	 * @private
	 * Display the selected form
	 * @param {String} id the id of the form
	 * @param {String} label the label of the form
	 * @param {String} workflowName the name of the workflow used for this form's entries
	 * @param {String} contentId the id of content holding the form
	 */
	_showForm: function(id, label, workflowName, contentId)
	{
		Ametys.tool.ToolsManager.openTool('uitool-form-content-entries', { id: id, label: label, workflowName: workflowName, contentId: contentId});
	},
	
	/**
	 * @private
	 * Displays a dialog box listing forms 
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller the button's controller
	 * @param {String} title the title of the dialog box
	 * @param {Function} callback the callback invoked when clicking the 'Ok' button, can either be an XLS export or the display of the forms values in a grid
	 */
	_act: function(controller, title, callback)
	{
		var contentTargets = controller.getMatchingTargets();
		var contentIds = []; 

		for (var i=0; i < contentTargets.length; i++)
		{
			contentIds.push(contentTargets[i].getParameters().id);
		}
		
	    this._currentForm = null;
	    this._callback = callback;

	    if (!this._delayedInitialize())
	    {
	        return;
	    }
	    
	    this._box.setTitle(title);
	    
	    this._getForms(contentIds);
	},

	/**
	 * @private
	 * Initialize the panel
	 * @param {String} title the title of the dialog box
	 */
	_delayedInitialize: function ()
	{
	    if (this._initialized)
	    {
	        return true;
	    }
	    
	    this._grid = Ext.create('Ext.grid.Panel', {
	    	id: 'select-form-list',
	    	scrollable: false,
	    	
	    	columns: 
    		[
    	          {header: "{{i18n PLUGINS_FORMS_UI_NAME}}", width: 380, menuDisabled: true, sortable: true, dataIndex: 'displayName', doNotEscapeHtml: true}
            ],

	        store: Ext.create('Ext.data.Store', {
	            fields: [
	               {id: 'id', name: 'name', label: 'label', displayName: 'displayName', workflowName: 'workflowName', contentId: 'contentId'}
	            ]
	        }),
	        hideHeaders : true
	    });
	    
	    this._box = Ext.create('Ametys.window.DialogBox', 
		{
	        iconCls: "ametysicon-list6",
	        width: 420,
	        height: 300,

	        scrollable: true,
	        border: false,
	        
	        items: [ this._grid ],
	        
	        referenceHolder: true,
	        defaultButton: 'okButton',
	        
	        closeAction: 'hide',
	        
	        buttons: [{
            	reference: 'okButton',
	            text: "{{i18n PLUGINS_FORMS_CHOOSE_FORM_DIALOG_BUTTON_OK}}",
	            handler: this._ok,
	            scope: this
	        }, 
	        {
	            text: "{{i18n PLUGINS_FORMS_CHOOSE_FORM_DIALOG_BUTTON_CANCEL}}",
	            handler: this._cancel,
	            scope: this
	        }]
	    });
	    
	    this._initialized = true;
	    
	    return true;
	},

	/**
	 * @private
	 * Load the grid
	 * @param {String[]} contentIds the ids of the selected contents
	 */
	_getForms: function(contentIds)
	{
        var pageTarget = Ametys.message.MessageBus.getCurrentSelectionMessage().getTarget(Ametys.message.MessageTarget.PAGE);
        var lang = pageTarget != null ? pageTarget.getParameters().lang : Ametys.cms.language.LanguageDAO.getCurrentLanguage();
        
		Ametys.data.ServerComm.callMethod({
			role: "org.ametys.plugins.forms.content.table.FormTableManager",
			methodName: "getContentForms",
			parameters: [contentIds, lang],
			callback: {
				scope: this,
				handler: this._getFormsCb
			},
			errorMessage: "{{i18n PLUGINS_FORMS_CHOOSE_FORM_DIALOG_FORM_LIST_ERROR}}"
		});
	},

	/**
	 * @private
	 * Callback function for the forms retrieving process
	 * Adds the forms into the grid
	 * @param {Object} contents the contents and theirs forms
     * @param {Object} args The arguments received from the serverCall
	 */
	_getFormsCb: function(contents, args)
	{
		var me = this;
		me._grid.getStore().removeAll();
	    
		var formsAmount = 0;
		
	    Ext.Array.each (contents, function (content) {
	    	
	    	var forms = content.forms;
	    	Ext.Array.each (forms, function (form) {
	    		me._grid.getStore().add({
	    			id: form.id, 
	    			label: form.label, 
	    			workflowName: form.workflowName, 
	    			displayName: Ext.String.escapeHtml(form.label) + ' <em>(' + Ext.String.escapeHtml(content.title) + ')</em>',
					contentId: content.id
	    		});
	    	});
	    	
	    	formsAmount += forms.length;
	    });
	    
	    if (formsAmount == 0)
	    {
	        Ametys.Msg.show({
	           title: "{{i18n PLUGINS_FORMS_CHOOSE_FORM_DIALOG_CAPTION}}",
	           msg: "{{i18n PLUGINS_FORMS_CHOOSE_FORM_DIALOG_NORESULT}}",
	           buttons: Ext.Msg.OK,
	           icon: Ext.MessageBox.INFO
	        });
	    }
	    
	    if (formsAmount == 1)
		{
	    	// Do not bother displaying a selection pop-up when there is only one form to select
	        // Select the first form "artificially", since the list view is never going to be rendered
	        var firstRecord = this._grid.getStore().getAt(0);
	        this._grid.setSelection(firstRecord);
	    	
	    	this._ok();
		}
	    
	    if (formsAmount > 1)
		{
	    	this._box.show();

	    	// Select the first record of the grid when the view is ready
	    	if (!this._grid.rendered)
			{
	    		this._grid.on('viewready', this._selectAndFocusFirstRow, this);
			}
	    	else
			{
	    		this._selectAndFocusFirstRow();
			}
		}
	},
	
	/**
	 * @private
	 * Select the first row of the grid as well as focusing it
	 */
	_selectAndFocusFirstRow: function()
	{
		var nodeToFocus = this._grid.getStore().getAt(0);
		
		this._grid.getSelectionModel().select(0);
		
		var gridView = this._grid.getView();
		Ext.defer(gridView.focusNode, 1, gridView, [nodeToFocus], false);
	},
	
	/**
	 * @private
	 * Handler invoked when clicking the 'ok' button
	 */
	_ok: function()
	{
	    if (this._callback != null)
	    {
	        var selection = this._grid.getSelection();
	        if (selection.length == 0 || selection.length > 1)
	        {
	            Ametys.Msg.show({
	               title: "{{i18n PLUGINS_FORMS_CHOOSE_FORM_DIALOG_CAPTION}}",
	               msg: "{{i18n PLUGINS_FORMS_CHOOSE_FORM_DIALOG_NO_FORM_SELECTED}}",
	               buttons: Ext.Msg.OK,
	               icon: Ext.MessageBox.INFO
	            });
	            return;
	        }
	        
	        this._box.hide();
	        
	        var formId = selection[0].id;
	        var formLabel = selection[0].get('label');
	        var workflowName = selection[0].get('workflowName');
			var contentId = selection[0].get('contentId');
	        
	        this._callback(formId, formLabel, workflowName, contentId);
	    }
	    else
	    {
	    	this._box.hide();
	    }
	},

	/**
	 * @private
	 * Handler invoked when clicking the 'cancel' button.Closes the dialog box
	 */
	_cancel: function ()
	{
	    this._box.hide();
	},
	
	// -----------------------------------------------------------------------------
	/**
	 * Delete the selected entries of the current selected form
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
	 */
	deleteEntry: function(controller)
	{
	    var formTarget = controller.getMatchingTargets()[0];
	    
	    if (formTarget != null)
	    {
	    	var entryTargets = formTarget.getSubtargets(Ametys.message.MessageTarget.CONTENT_FORM_ENTRY);
	    	
	    	if (entryTargets.length)
	    	{
	    		var ids = [];
		    	Ext.Array.each (entryTargets, function (target) {
		    		ids.push (target.getParameters().id);
		    	})
		    	
		    	Ametys.Msg.confirm ("{{i18n PLUGINS_FORMS_DELETE_ENTRY_CONFIRM_TITLE}}", 
	                "{{i18n PLUGINS_FORMS_DELETE_ENTRY_CONFIRM}}",
	                function (answer)
	                {
	                    if (answer == 'yes')
	                    {
	                    	Ametys.data.ServerComm.callMethod({
	        					role: "org.ametys.plugins.forms.content.table.FormTableManager",
	        					methodName: "deleteEntry",
	        					parameters: [Ametys.getAppParameter('siteName'), formTarget.getParameters().id, ids],
	        					callback: {
	        						scope: this,
	        						handler: this._deleteEntryCb,
	        						arguments: {
	        							ids: ids,
	        							form: formTarget.getParameters().id
	        						}
	        					},
	        					errorMessage: "{{i18n PLUGINS_FORMS_DELETE_ENTRY_ERROR}}"
	        				});
	                    }
	                },
	                this
	            );
		    	
	    	}
	    }
	},
	
	/**
	 * Callback after deleting one or more entries
	 * @param {String} response The response from the server
	 * @param {Object} args The arguments received from the serverCall
	 * @private
	 */
	_deleteEntryCb: function (response, args)
	{
		var targets = [];
		
		Ext.Array.each (args.ids, function (id) {
			targets.push({
			    id: Ametys.message.MessageTarget.CONTENT_FORM_ENTRY,
                parameters: {
                	id: id,
                    form: args.form
                }
        	});
    	})
    	
	    Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.DELETED,
            targets: targets
        });
	},
	
	// -----------------------------------------------------------------------------
    /**
     * Clear all entries of the selected form
     * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
     */
	clearEntries: function (controller)
	{
		var contentFormTargets = controller.getMatchingTargets();
		if (contentFormTargets.length > 0)
	    {
			var formIds = [],
				formLabels = [];
			Ext.each(contentFormTargets, function(contentFormTarget){
				formIds.push(contentFormTarget.getParameters().id);
				formLabels.push(contentFormTarget.getParameters().label);
			});
			
	    	Ametys.Msg.confirm ("{{i18n PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM_TITLE}}", 
	                "{{i18n PLUGINS_FORMS_CLEAR_ENTRIES_CONFIRM}}",
	                function (answer)
	                {
	                    if (answer == 'yes')
	                    {
	                    	Ametys.data.ServerComm.callMethod({
	        					role: "org.ametys.plugins.forms.content.table.FormTableManager",
	        					methodName: "clearEntries",
	        					parameters: [Ametys.getAppParameter('siteName'), formIds],
	        					callback: {
	        						scope: this,
	        						handler: this._clearEntriesCb,
	        						arguments: {
	        							formIds: formIds,
	        							formLabels: formLabels
	        						}
	        					},
	        					errorMessage: "{{i18n PLUGINS_FORMS_CLEAR_ENTRIES_ERROR}}"
	        				});
	                    }
	                },
	                this
	            );
	    }
	},
	
    /**
     * @private
     * Callback function invoked after clearing all the entries of a form
     * @param {String} response The response from the server
     * @param {Object} args The arguments received from the serverCall
     * @param {Object} args.formIds The ids of the forms whose entries have been removed
     * @param {Object} args.formLabels The labels of the forms whose entries have been removed
     */
	_clearEntriesCb: function (response, args)
    {
	    var formIds = args.formIds;
	    var formLabels = args.formLabels;
	    var targets = [];
	    
	    Ext.each(formIds, function(formId, idx){
	    	targets.push({
			    id: Ametys.message.MessageTarget.CONTENT_FORM,
                parameters: {
                	id: formId,
                	label: formLabels[idx],
                	hasEntries: false
                }
        	});
	    });
		
		Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.MODIFIED,
            targets: targets
        });
    },

    // -----------------------------------------------------------------------------
    /**
     * View the SELECT statement used to list the entries of the form from the database
     * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
     */
    viewSelectStatement: function(controller)
    {
    	var formTarget = controller.getMatchingTargets()[0];
	    if (formTarget != null)
	    {
	    	Ametys.data.ServerComm.callMethod({
				role: "org.ametys.plugins.forms.content.table.FormTableManager",
				methodName: "getSelectStatement",
				parameters: [Ametys.getAppParameter('siteName'), formTarget.getParameters().id],
				callback: {
					scope: this,
					handler: this._getSelectStatementCb,
					arguments: {
						form: formTarget.getParameters().id
					}
				},
				errorMessage: "{{i18n PLUGINS_FORMS_GET_SELECT_STATEMENT_ERROR}}"
			});
	    }
    },
    
    /**
     * @private
     * Callback invoked after retrieving the SELECT query
     * @param {Object} response The data received from the server
     * @param {String} response.tableName The SQL table name
     * @param {String} response.query The SELECT query
     */
    _getSelectStatementCb: function (response)
    {
        if (!this._selectStatementDelayedInitialize())
        {
            return;
        }
        
        this._initSelectStatementForm(response);
        this._selectStatementBox.show();
    },

    /**
     * @private
     * Creates the dialog if necessary
     * @return {Boolean} true if the initialization is complete
     */
    _selectStatementDelayedInitialize: function ()
    {
        if (this._selectStatementInitialized)
        {
            return true;
        }
        
        this._selectStatementForm = Ext.create('Ext.form.Panel', {
            border: false,
            defaults : {
                cls: 'ametys',
                labelWidth: 100,
                anchor:'90%',
                xtype: 'textfield'
            },
            
            items : [{
                        readOnly: true,
                        name: "tableName",
                        fieldLabel: "{{i18n PLUGINS_FORMS_GET_SELECT_STATEMENT_DIALOG_TABLENAME_FIELD}}"
                    },
                    {
                        xtype: 'textarea',
                        readOnly: true,
                        fieldLabel :"{{i18n PLUGINS_FORMS_GET_SELECT_STATEMENT_DIALOG_REQUEST_FIELD}}",
                        name: 'query',
                        height: 140
                    }
            ]
        });
        
        this._selectStatementBox = Ext.create('Ametys.window.DialogBox', 
        {
            title :"{{i18n PLUGINS_FORMS_GET_SELECT_STATEMENT_DIALOG_TITLE}}",
            iconCls: "ametysicon-data110 ametysicon-decorator-question13",
            
            width: 500,

            scrollable: true,
            border: false,
            
            items : [ this._selectStatementForm ],
            
            referenceHolder: true,
            defaultButton: 'okButton',
            
            closeAction: 'hide',
            buttons: [{
            	defaultButton: 'okButton',
                text: "{{i18n PLUGINS_FORMS_GET_SELECT_STATEMENT_DIALOG_BUTTON_OK}}",
                handler: function () { this._selectStatementBox.close() },
                scope: this
            }]
        });
        
        this._selectStatementInitialized = true;
        return true;
    },
    
    /**
     * @private
     * Initialize the form in the dialog with the data received from the server
     * @param {Object} data The data
     * @param {String} data.tableName The SQL table name
     * @param {String} data.query The SELECT query
     */
    _initSelectStatementForm: function (data)
    {
        var form = this._selectStatementForm.getForm();
        form.findField("tableName").setValue(data.tableName);
        form.findField("query").setValue(data.query);
    },
    
    /**
     * Delete the selection of orphan tables
     * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
     */
    removeTables: function(controller)
    {
    	var severalTables = controller.getMatchingTargets().length > 1;
    	
    	Ametys.Msg.confirm(
    			"{{i18n PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_TITLE}}", 
    			severalTables ? "{{i18n PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_TITLE_TEXT_SEVERAL}}"
    						  : "{{i18n PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_TITLE_TEXT}}", 
    			Ext.bind(this._doRemove, this, [controller], 1), 
    			this
    	);
    },
    
    /**
     * Actually remove the selection of orphan tables
     * @param {String} button the button clicked
     * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller of the button
     */
    _doRemove: function (button, controller)
    {
    	if (button == 'yes')
    	{
    		var tableTargets = controller.getMatchingTargets();
    		var tableNames = [];
    		Ext.each(tableTargets, function(tableTarget){
    			tableNames.push(tableTarget.getParameters().name);
    		});
    		
	    	Ametys.data.ServerComm.callMethod({
				role: "org.ametys.plugins.forms.content.table.FormTableManager",
				methodName: "removeTables",
				parameters: [tableNames],
				callback: {
					scope: this,
					handler: this._doRemoveCb,
					arguments: {
						tableNames: tableNames
					}
				},
				errorMessage: "{{i18n PLUGINS_FORMS_ADMINISTRATOR_ORPHAN_FORMS_ACTIONS_DELETE_TABLE_ERROR}}"
			});
    	}
    },
    
    /**
     * Callback for the orphan tables removal process
     * @param {Object} response the server's response
     * @param {Object} args the callback arguments
     * @param {Object} args.tableNames The table names
     */
    _doRemoveCb: function (response, args)
    {
    	var targets = [];
    	Ext.each(args.tableNames, function(tableName){
    		targets.push({
    				id: Ametys.message.MessageTarget.TABLE,
                    parameters: {
                        name: tableName
                    }
    		});
    	});
    	
    	Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.DELETED,
            targets: targets
        });
    }
});