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

/**
 * This controller allows to schedule the publication of the current selected page<br/>
 * The button's icon represents the current publication status of the page.
 * @private
 */
Ext.define(
	'Ametys.plugins.web.page.controller.ScheduledPublicationController', 
	{
		extend: 'Ametys.web.controller.WebButtonController',

		/**
		 * @property {String[]} [_pageIds=[]] List of identifiers of pages concerned by the action of the controller
		 * @private
		 */
        
        /** @cfg {String} icon-glyph The icon when there is a past publication */
        /** @cfg {String} icon-decorator The icon decorator when there is a past publication */
        /** @cfg {String} on-icon-glyph The icon when there is a publication scheduled */
        /** @cfg {String} on-icon-decorator The icon decorator when there is a publication scheduled */
        /** @cfg {String} forthcoming-icon-glyph The icon when there is a forthcoming publication */
        /** @cfg {String} forthcoming-icon-decorator The icon decorator when there is a forthcoming publication */
        /** @cfg {String} outofdate-icon-glyph The icon when there is an outdated publication */
        /** @cfg {String} outofdate-icon-decorator The icon decorator when there is an outdated publication */
		
		constructor: function(config)
		{
			this._pageIds = [];
			this.callParent(arguments);
			
			Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onModified, this);
		},
		
		/**
		 * @private
		 * Listener handler for modified messages
		 * @param {Ametys.message.Message} message the message
		 */
		_onModified: function(message)
		{
			if (this.updateTargetsInCurrentSelectionTargets (message))
			{
	    		this.refresh();
			}
		},
		
		/**
		 * Get the matching targets that match conditions
		 * @return {Ametys.message.MessageTarget[]} targets filling all conditions.
		 */
		getAllRightPageTargets: function ()
		{
			var matchingTargets = this.getMatchingTargets();
			var me = this;
			
			return Ext.Array.filter (matchingTargets, function (target) {
				return Ext.Array.contains(me._pageIds, target.getParameters().id)
			});
		},
		
		updateState: function()
		{
			this._getStatus(this.getMatchingTargets());
		},
		
		
		/**
		 * @private
		 * Get the status
		 * @param targets The page targets
		 */
		_getStatus: function (targets)
		{
            var result = this._calculateStatus(targets);
            this._getStatusCb(result);
		},

        /**
     * Simulation of getStatus server side, done only client-side.
     * @param {Object[]} pageTargets page target see Ametys.ribbon.element.ui.CommonController#getMatchingTargets
     * @return {Object} a map of arrays representing contents in different states that will be sent to _getStatusCb
     */
    _calculateStatus: function(pageTargets)
    {
        var result = {};
        result["nomodifiable-pages"] = [];
        result["noright-pages"] = [];
        result["allright-pages"] = [];
        result["scheduled-pages"] = [];
        result["scheduled-valid-pages"] = [];
        result["scheduled-forthcoming-pages"] = [];
        result["scheduled-outofdate-pages"] = [];
        var now = new Date();
        now.setHours(0, 0, 0, 0);
        var time = now.getTime();

        Ext.Array.each(pageTargets, function(pageTarget)
        {
            var page = null;
            if (pageTarget)
            {
                page = pageTarget.getParameters().page;
            }
            if (page != null)
            {
                var pageParam = this._getPageDefaultParameters(page);
                if (!page.getIsModifiable())
                {
                    var i18nStr = this.getConfig("nomodifiable-page-description");
                    var description = Ext.String.format(i18nStr, page.getTitle());
                    pageParam["description"] = description;
                    result["nomodifiable-pages"].push(pageParam);
                }
                else if (!this.hasRightOnAny([pageTarget]))
                {
                    var i18nStr = this.getConfig("noright-page-description");
                    var description = Ext.String.format(i18nStr, page.getTitle());
                    pageParam["description"] = description;
                    result["noright-pages"].push(pageParam);
                }
                else
                {
                    var startDate = null;
                    var endDate = null;

                    if (page.getPublication())
                    {
                        startDate = page.getPublication().startDate ? Ext.Date.parse(page.getPublication().startDate, Ext.Date.patterns.ISO8601DateTime) : null;
                        endDate = page.getPublication().endDate ? Ext.Date.parse(page.getPublication().endDate, Ext.Date.patterns.ISO8601DateTime) : null;
                    }

                    var isScheduled = startDate != null || endDate != null;
                    if (isScheduled)
                    {
                        if (this._isDateValid(now, startDate, endDate))
                        {
                            var i18nStr = this.getConfig("scheduled-page-valid-description");
                            var description = Ext.String.format(i18nStr, page.getTitle());
                            pageParam["description"] = description;
                            result["scheduled-valid-pages"].push(pageParam);
                        }
                        else if (endDate != null && endDate.getTime() < time)
                        {
                            var i18nStr = this.getConfig("scheduled-page-outofdate-description");
                            var endDateStr = Ext.Date.format(endDate, Ext.Date.patterns.FullDate);
                            var description = Ext.String.format(i18nStr, page.getTitle(), endDateStr);
                            pageParam["description"] = description;
                            result["scheduled-outofdate-pages"].push(pageParam);
                        }
                        else if (startDate != null && startDate.getTime() > time)
                        {
                            var i18nStr = this.getConfig("scheduled-page-forthcoming-description");
                            var startDateStr = Ext.Date.format(startDate, Ext.Date.patterns.FullDate);
                            var endDateStr = endDate != null ? Ext.Date.format(endDate, Ext.Date.patterns.FullDate) : "-";
                            var description = Ext.String.format(i18nStr, page.getTitle(), startDateStr, endDateStr);
                            pageParam["description"] = description;
                            result["scheduled-valid-pages"].push(pageParam);
                        }
                        result["scheduled-pages"].push(pageParam);
                    }

                    result["allright-pages"].push(pageParam);
                }
            }
        }, this);
        return result;
    },

    /**
     * Returns true if the publication date of the given page are valid.
     * @param {Date} date current date
     * @param {Date} start start date of the publication (can be null)
     * @param {Date} end end date of the publication (can be null)
     * @return {boolean} true if the publication dates are valid
     */
    _isDateValid : function (date, start, end)
    {
        var t = date.getTime();
        if (start != null && start.getTime() > t)
        {
            return false;
        }

        if (end != null && end.getTime() < t)
        {
            return false;
        }

        return true;
    },

    /**
     * create a json object representing a page
     * @private
     * @param {Ametys.web.page.Page} page The page to analyse
     * @return {Object} containing id and title
     */
    _getPageDefaultParameters : function(page)
    {
        var pageParams = {};
        pageParams["id"] = page.getId();
        pageParams["title"] = page.getTitle();
        return pageParams;
    },
		
		/**
		 * @private
		 * Callback for the button's status computation process
		 * @param {Object} params the server's response
		 * @param {String} params.scheduled-pages the pages having a scheduled publication
		 * @param {String} params.noright-pages the pages for which the user does not have the right to schedule a publication
		 * @param {String} params.scheduled-valid-pages the pages within publication interval
		 * @param {String} params.scheduled-outofdate-pages the pages outside publication interval
		 * @param {String} params.scheduled-forthcoming-pages the forthcoming pages
		 * @param {Object} args the callback arguments
		 */
		_getStatusCb: function(params, args)
		{
			this._updateTooltipDescription(this.getInitialConfig('default-description'), params);
			this._updateIcons(params);
			
			this.toggle(params['scheduled-pages'].length > 0);
			
			var allRightPages = params['allright-pages'];
			if (allRightPages.length > 0)
			{
				for (var i=0; i < allRightPages.length; i++)
				{
					this._pageIds.push(allRightPages[i].id)
				}
				this.enable();
			}
			else
			{
				this.disable();
			}
		},
		
		
		/**
		 * @private
		 * Update the tooltip description according state of the current selection
		 * @param description The initial description. Can be empty.
		 * @param params The JSON result received
		 */
		_updateTooltipDescription: function (description, params)
		{
			description = this._handlingMultiple(description, "noright", params['noright-pages']);
			description = this._handlingMultiple(description, "nomodifiable", params['nomodifiable-pages']);
			description = this._handlingMultiple(description, "scheduled-page-valid", params['scheduled-valid-pages']);
			description = this._handlingMultiple(description, "scheduled-page-outofdate", params['scheduled-outofdate-pages']);
			description = this._handlingMultiple(description, "scheduled-page-forthcoming", params['scheduled-forthcoming-pages']);
			
			this.setDescription (description);
		},
		
		/**
		 * @private
		 * Add text to description
		 * @param description The initial description to concatenate. Can be empty.
		 * @param {String} prefix The parameters prefix to used to retrieve the start and end description. The start and end description are retrieved from initial configuration with [prefix]-start-description and [prefix]-end-description
		 * @param {Object[]} pages The concerned pages. If empty, no text will be concatenated
		 */
		_handlingMultiple: function(description, prefix, pages)
		{
			if (pages.length > 0)
			{
				if (description != "")
				{
					description += "<br/><br/>";
				}
				
				description += this.getInitialConfig(prefix + "-start-description");
				for (var i=0; i < pages.length; i++)
				{
					if (i != 0) 
					{
						description += ", ";
					}
					description += pages[i].description;
				}
				description += this.getInitialConfig(prefix + "-end-description");
			}
			
			return description;
		},
		
		/**
		 * @private
		 * Set the icons according to the button's status
		 * @param {Object} params the parameters
		 * @param {String} params.scheduled-pages the pages having a scheduled publication
		 * @param {String} params.noright-pages the pages for which the user doesn't have the right to schedule a publication
		 * @param {String} params.scheduled-valid-pages the pages within publication interval
		 * @param {String} params.scheduled-outofdate-pages the pages outside publication interval
		 * @param {String} params.scheduled-forthcoming-pages the forthcoming pages
		 */
		_updateIcons: function (params)
		{
			var nbScheduledPages = params['scheduled-pages'].length;
			var nbValidPages = params['scheduled-valid-pages'].length;
			var nbOutOfDatePages = params['scheduled-outofdate-pages'].length;
			var nbForthComingPages = params['scheduled-forthcoming-pages'].length;
			
			var iconGlyph, iconDecorator;
			
			if (nbScheduledPages > 0 && nbValidPages > 0)
			{
				iconGlyph = this.getInitialConfig()['on-icon-glyph'];
				iconDecorator = this.getInitialConfig()['on-icon-decorator'];
			}
			
			if (nbScheduledPages > 0 && nbForthComingPages > 0)
			{
				iconGlyph = this.getInitialConfig()['forthcoming-icon-glyph'];
				iconDecorator = this.getInitialConfig()['forthcoming-icon-decorator'];
			}
			
			if (nbScheduledPages > 0 && nbOutOfDatePages > 0)
			{
				iconGlyph = this.getInitialConfig()['outofdate-icon-glyph'];
				iconDecorator = this.getInitialConfig()['outofdate-icon-decorator'];
			}
			
			if (nbScheduledPages == 0)
			{
				iconGlyph = this.getInitialConfig()['icon-glyph'];
				iconDecorator = this.getInitialConfig()['icon-decorator'];
			}
			
			this.setGlyphIcon(iconGlyph);
			this.setIconDecorator(iconDecorator);
		}
	}
);