/*
 *  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
 * This tool displays the entries of a form
 */
Ext.define('Ametys.plugins.forms.content.tool.FormsTool', {
	
	extend: 'Ametys.tool.Tool',
	
	/**
	 * @private
	 * @property {Ext.grid.Panel} _grid the results grid panel
	 */
	
	/**
	 * @private
	 * @property {String} _contentId the id of the content holding the form
	 */
		
	/**
	 * @private
	 * @property {String} _formId the id of the current form
	 */
	
	/**
	 * @private
	 * @property {String} _workflowName the name of the workflow used for the entries of this form. Can be null.
	 */
	
	/**
	 * @private
	 * @property {String} _formLabel the label of the form
	 */
	
	/**
	 * @private
	 * @property {Object[]} _fields the fields of the grid
	 */
	
    /**
     * @property {Number} [PAGE_SIZE=50] The number of records to display by 'page'
     * @readonly
     */
    PAGE_SIZE: 50,
    
    constructor: function(config)
    {
        this.callParent(arguments);
        
        Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onEntryDeleted, this);
        Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onModified, this);
        Ametys.message.MessageBus.on(Ametys.message.Message.WORKFLOW_CHANGED, this._onModified, this);
    },
	
	createPanel: function()
	{
		var store = Ext.create('Ext.data.Store', {
		    fields: [],
		    data: [],
		    pageSize: this.PAGE_SIZE,
            totalProperty: 'total' 
		});
		
		this._grid = Ext.create('Ext.grid.Panel', {
			store: store,
			columns: [],
			scrollable: true,
			
			dockedItems: [{
                xtype: 'pagingtoolbar',
                store: store,
                dock: 'bottom',
                displayInfo: true,
                displayMsg: "{{i18n plugin.forms:PLUGINS_FORMS_UITOOL_ENTRY_CONTENT_RESULT_1}}{0}{{i18n plugin.forms:PLUGINS_FORMS_UITOOL_ENTRY_CONTENT_RESULT_2}}{1}{{i18n plugin.forms:PLUGINS_FORMS_UITOOL_ENTRY_CONTENT_RESULT_3}}{2}",
                emptyMsg: "{{i18n plugin.forms:PLUGINS_FORMS_UITOOL_ENTRY_NO_RESULT}}"
            }],
			
			selModel : {
                mode: 'MULTI'
            },
			listeners: {
			    selectionchange: Ext.bind(this.sendCurrentSelection, this)
			}
		});
		
		return this._grid;
	},
	
	getMBSelectionInteraction: function() 
	{
		return Ametys.tool.Tool.MB_TYPE_ACTIVE;
	},
	
	setParams: function(params)
	{
		this.callParent(arguments);
		
		this._formId = params.id;
		this._formLabel = params.label;
		this._workflowName = params.workflowName;
		this._contentId = params.contentId;
		
		if (params.label)
	    {
		    this.setTitle(this.getInitialConfig("title") + ": " + params.label);
	    }
		
		this.refresh();
	},
	
	sendCurrentSelection : function()
    {
		var me = this;
        var subtargets = [];
        var hasEntries = this._grid.getStore().getTotalCount() > 0;
        
        Ext.each (this._grid.getSelectionModel().getSelection(), function (record) {
        	subtargets.push({
        		id: Ametys.message.MessageTarget.CONTENT_FORM_ENTRY,
                parameters: {
                	id: record.getId(),
                    form: me._formId
                }
        	});
        });
        
        Ext.create("Ametys.message.Message", {
            type: Ametys.message.Message.SELECTION_CHANGED,
            targets: {
                id: Ametys.message.MessageTarget.CONTENT_FORM,
                parameters: {
                    id: me._formId,
                    label: me._formLabel,
                    hasEntries: hasEntries,
                    workflowName: me._workflowName,  
					contentId: me.contentId
                },
                subtargets: subtargets
            }
        });
    },
	
	refresh: function()
	{
		this.showRefreshing();
		
		Ametys.data.ServerComm.callMethod({
			role: "org.ametys.plugins.forms.content.table.FormTableManager",
			methodName: "getColumns",
			parameters: [Ametys.getAppParameter('siteName'), this._contentId, this._formId],
			callback: {
				scope: this,
				handler: this._getColumnsCb
			},
			errorMessage: "{{i18n PLUGINS_FORMS_UITOOL_GET_COLUMNS_ERROR}}"
		});
	},
	
	/**
	 * Callback function invoked after retrieving form's properties (columns and fields).
	 * Loads entries after reconfiguring the grid.
	 * @param {Object} data The form's fields
	 * @private
	 */
	_getColumnsCb: function (data)
	{
        var oldPage = this._grid.getStore() && this._grid.getStore().currentPage || 1;
        var oldSelection = this._grid.getSelection();
        
		var columns = [
		    {text: "{{i18n PLUGINS_FORMS_UITOOL_COLUMN_ID}}", dataIndex: 'id', sortable: true, hideable: false, width: 50, align: 'center'},
		    {text: "{{i18n PLUGINS_FORMS_UITOOL_COLUMN_SUBMISSION_DATE}}", dataIndex: 'submission-date', sortable: true, hideable: true, width: 150, renderer: Ametys.grid.GridColumnHelper.renderDateTime},
		    {text: "{{i18n PLUGINS_FORMS_UITOOL_COLUMN_SUBMISSION_USER}}", dataIndex: 'user', sortable: true, hideable: true, width: 150, renderer: Ametys.grid.GridColumnHelper.renderUser}
        ];
		
		var me = this;
		Ext.Array.each (data, function (column) {
			columns.push (me._getColumnConfig(column))
		});
		
		// Workflow step
		columns.push({
			text: "{{i18n PLUGINS_FORMS_UITOOL_COLUMN_WORKFLOW}}",
			dataIndex: "workflowStep",
			renderer: Ametys.plugins.cms.search.SearchGridHelper.renderWorkflowStep,
			sortable: true,
			hideable: true,
			width: 120,
			align: 'center'
		});
		
		this._fields = [];
		
		this._fields.push({'name': 'entryId', type: 'int', mapping: 'id'});
		this._fields.push({'name': 'submission-date', type: 'date', mapping: 'submission-date'});
		
		Ext.Array.each (data, function (column) {
			this._fields.push (me._getFieldConfig(column));
		}, this);
		
		this._fields.push({name: 'workflowStep', convert: Ametys.plugins.cms.search.SearchGridHelper.convertWorkflowStep});
	    
		var store = Ext.create('Ext.data.Store', {
		    autoLoad: false,
		    proxy: {
                type: 'ametys',
                url: 'form-content/entries.json',
                plugin: 'forms',
                reader: {
                    type: 'json',
                    rootProperty: 'entries',
                    totalProperty: 'total'
                },
                extraParams: {
                    siteName: Ametys.getAppParameter("siteName"), 
                    id: this._formId,
					contentId: this._contentId
                }
            },
	        pageSize: this.PAGE_SIZE,
	        
    		fields: this._fields
		});

		this._grid.reconfigure(store, columns);
		this._grid.getDockedItems('toolbar[dock="bottom"]')[0].bindStore(store);
		
		store.loadPage(oldPage, {
	        callback: function(){
                var newSelections = [];
                for (var i = 0; i < oldSelection.length; i++)
                {
                    var newSelection = this._grid.getStore().getById(oldSelection[i].getId());
                    if (newSelection)
                    {
                        newSelections.push(newSelection);
                    }
                }
                if (newSelections.length > 0)
                {
                    this._grid.getSelectionModel().select(newSelections);
                }
                else
                {
	        	    this.sendCurrentSelection();
                }
	        	this.showRefreshed();
		    },
	        scope: this
	    });
	},
	
	/**
	 * @private
	 * Return a column configuration from a definition described in JSON
	 * @param {Object} column the column definition object
	 * @return {Object} The column configuration
	 */
	_getColumnConfig: function (column)
	{
		var cfg = {
			text: "<img style='vertical-align:middle;' src='" + this._getIconPath(column) + "' alt=''/> " + (column.label != '' ? column.label : column.name),
			dataIndex: column.id,
			align: 'left',
			width: 200
		};
		
		var type = column.type.toLowerCase();
        switch (type) {
            case 'checkbox':
                cfg.xtype = 'booleancolumn';
                cfg.renderer = Ametys.grid.GridColumnHelper.renderBooleanIcon;
                break;
            case 'password':
            	cfg.renderer = this._renderPassword;
            	break;
            case 'file':
	        	cfg.renderer = Ext.bind(this._renderFile, this);
	        	break;
            case 'text':
            case 'textarea':
            case 'select':
            case 'radio':
            case 'hidden':
            default:
                break;
        }
        
        var regexptype = column.properties.regexptype;
        switch (regexptype) {
        	case 'date':
        		cfg.xtype = 'datecolumn';
	            cfg.format = Ext.Date.patterns.LongDate;
	            cfg.width = 120;
	            break;
        	case 'datetime':
	            cfg.xtype = 'datecolumn';
	            cfg.format = Ext.Date.patterns.FriendlyDateTime;
	            cfg.width = 120;
	            break;
        	case 'time':
	        	cfg.align = 'right';
	        	cfg.width = 80;
                break;
        	case 'int':
        		cfg.xtype = 'numbercolumn';
                cfg.align = 'right';
                cfg.width = 80;
                cfg.format = '0';
                break;
        	case 'float':
        		cfg.xtype = 'numbercolumn';
                cfg.align = 'right';
                cfg.width = 80;
                break;
        	default:
                break;
        }
        
        return cfg;
	},
	
	/**
	 * @private
     * Return a field configuration from a definition described in JSON
     * @param {Object} data The field definition
     * @return {Object} The configuration object
     */
	_getFieldConfig: function (data)
	{
		var cfg = {
			name: data.id,
			type: 'string'
		}
		
		var regexptype = data.properties.regexptype;
		switch (regexptype) {
	    	case 'date':
	    	case 'datetime':
	    		cfg.type = 'date';
	            break;
	    	case 'int':
	    		cfg.type = 'int';
	            break;
	    	case 'float':
	    		cfg.type = 'float';
	            break;
	    	default:
	            break;
	    }
		
		return cfg;
	},
	
	/**
	 * @private
	 * Get the path of the icon of a column
	 * @param {Object} column the column's properties
	 * @return the path of the node's icon
	 */
	_getIconPath: function (column)
	{
		var type = column.type;
		if (type == "TEXT" || type == "RADIO" || type == "CHECKBOX" || type == "PASSWORD" || type == "FILE" || type == "HIDDEN")
		{
			return Ametys.getPluginResourcesPrefix('forms') +  "/img/edition/input_" + type.toLowerCase() + "_16.png";
		}
		else if (type == "TEXTEREA")
		{
			return Ametys.getPluginResourcesPrefix('forms') +  "/img/edition/textarea_16.png";
		}
		else if (type == "SELECT")
		{
			return Ametys.getPluginResourcesPrefix('forms') +  "/img/edition/select_16.png";
		}
		return Ametys.getPluginResourcesPrefix('forms') +  "/img/edition/input_text_16.png";
	},
	
	/**
	 * @private
	 * Renderer function for a password
	 * @param {String} value the value
	 * @return the html string for the given password value
	 */
	_renderPassword: function (value)
	{
		var pwd = "";
		for (var i = 0; i < value.length; i++)
		{
			pwd += "*"
		}
		return pwd;
	},
	
	/**
	 * @private
	 * Renderer function for a file
	 * @param {String} value the value
	 * @param {Object} metaData A collection of metadata about the current cell
	 * @param {Ext.data.Model} record The record for the current row
	 * @param {Number} rowIndex The index of the current row
	 * @param {Number} colIndex The index of the current column
	 * @param {Ext.data.Store} store The data store
	 * @param {Ext.view.Table} view The data view
	 * @return the html string for the given file value
	 */
	_renderFile: function (value, metaData, record, rowIndex, colIndex , store, view)
	{
		if (value == null || value == '')
		{
			return value;
		}
		
		var extension = "unknown";
		var index = value.lastIndexOf('.');
		if (index > 0)
		{
			extension = value.substring(index + 1).toLowerCase();
		}
		
		var iconPath = Ametys.getPluginDirectPrefix('explorer') + "/icon/" + extension + ".png"
		
		var fieldId = metaData.column.dataIndex || this._fields[colIndex - 1].name;
		var entryId = record.data.id;
		return "<a class='download' href='" + Ametys.getPluginDirectPrefix('forms') + "/" + Ametys.getAppParameter('siteName') + "/download/" + this._formId + "/" + entryId + "/" + fieldId + "/" + value + "'>" + "<img src='" + iconPath  + "'/> " + value + "</a>";
	},
	
	/**
	 * @private
	 * Retrieve the form id
	 * @return the form id
	 */
	getFormId: function ()
	{
	    return this._formId;
	},
	
    /**
     * @private
     * Listener upon reception of a deletion message
     * @param {Ametys.message.Message} message the deletion message
     */
	_onEntryDeleted: function(message)
    {
        var targets = message.getTargets(Ametys.message.MessageTarget.CONTENT_FORM_ENTRY);
        if (targets.length > 0)
        {
            Ext.Array.forEach(targets, function(target) {
                if (this._formId == target.getParameters().form)
                {
                    this.showOutOfDate();
                }
            }, this);
        }
    },
    
    /**
     * @private
     * Listener upon reception of a modification message
     * @param {Ametys.message.Message} message the deletion message
     */
    _onModified: function (message)
    {
    	var target = message.getTarget(Ametys.message.MessageTarget.CONTENT_FORM);
    	if (target != null && this._formId == target.getParameters().id)
        {
            this.showOutOfDate();
        }
    }
});

Ext.define("Ametys.message.FormMessageTarget", {
	override: "Ametys.message.MessageTarget",
	
	statics: 
	{
		/**
		 * @member Ametys.message.MessageTarget
		 * @readonly
		 * @property {String} CONTENT_FORM The target type is a form contained in a rich-text of a content. Parameters are:
		 * @property {String} CONTENT_FORM.id The unique identifier of the form
		 * @property {String} CONTENT_FORM.label The label of the form
		 * @property {Boolean} CONTENT_FORM.hasEntries does this form have any entries ?  
		 * @property {String} CONTENT_FORM.workflowName the name of the workflow used for the submissions of this form
		 */
		CONTENT_FORM: "content-form",
		
		/**
		 * @member Ametys.message.MessageTarget
		 * @readonly
		 * @property {String} CONTENT_FORM_ENTRY The target type is a entry of a content's form. Parameters are:
		 * @property {Number} CONTENT_FORM_ENTRY.id The identifier of the entry
		 * @property {String} CONTENT_FORM_ENTRY.form The identifier of the parent form
		 */
		CONTENT_FORM_ENTRY: "content-form-entry"
	}
});