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

/**
 * Singleton class defining the actions related to pages.
 * @private
 */
Ext.define('Ametys.plugins.web.page.PageActions', {
	singleton: true,
	
	/**
	 * @private
	 * @property {Ext.Template} _linkPageConfirmTpl Template for confirm message when setting page as a page of redirection
	 */
	_linkPageConfirmTpl: Ext.create('Ext.XTemplate', 
			"<div>",
				"{{i18n PLUGINS_WEB_PAGE_LINKPAGE_CONFIRM3}}",
				"<br/>{{i18n PLUGINS_WEB_PAGE_LINKPAGE_CONFIRM4}} <span style='font-weight: bold'>{[Ext.String.escapeHtml(values.pageTitle)]}</span> {{i18n PLUGINS_WEB_PAGE_LINKPAGE_CONFIRM5}}", 
				"<br/><br/><span style='font-style: italic'>{{i18n PLUGINS_WEB_PAGE_LINKPAGE_CONFIRM6}}</span>.",
			"</div>"
	),
	
	/**
	 * @private
	 * @property {Ext.XTemplate} _linkPagesConfirmTpl Template for confirm message when setting pages as pages of redirection
	 */
	_linkPagesConfirmTpl: Ext.create('Ext.XTemplate',
		 "{{i18n PLUGINS_WEB_PAGE_LINKPAGE_CONFIRM1}}",
   		 '<ul style="margin: 5px; padding-left: 25px;">',
   		 	'<tpl for=".">',
   		 		'<li>{[Ext.String.escapeHtml(values.pageTitle)]}</li>',
   		 	'</tpl>',
   		 '</ul>',
		"<br/><br/><span style='font-style: italic'>{{i18n PLUGINS_WEB_PAGE_BLANKPAGE_CONFIRM2}}</span>."
	),
	
	/**
	 * @private
	 * @property {Ext.Template} _blankPageConfirmTpl Template for confirm message when setting page as blank page
	 */
	_blankPageConfirmTpl: Ext.create('Ext.XTemplate', 
			"<div>",
				"{{i18n PLUGINS_WEB_PAGE_BLANKPAGE_CONFIRM5}}",
				"<span style='font-weight: bold'>{[Ext.String.escapeHtml(values.pageTitle)]}</span> ?",
				"<br/><br/>{{i18n PLUGINS_WEB_PAGE_BLANKPAGE_CONFIRM6}}", 
				"<br/>{{i18n PLUGINS_WEB_PAGE_BLANKPAGE_CONFIRM7}}",
				"<br/><br/><span style='font-style: italic'>{{i18n PLUGINS_WEB_PAGE_BLANKPAGE_CONFIRM4}}</span>.",
			"</div>"
	),
	
	/**
	 * @private
	 * @property {Ext.XTemplate} _blankPagesConfirmTpl Template for confirm message when setting pages as blank pages
	 */
	_blankPagesConfirmTpl: Ext.create('Ext.XTemplate',
		 "{{i18n PLUGINS_WEB_PAGE_BLANKPAGE_CONFIRM1}}",
   		 '<ul style="margin: 5px; padding-left: 25px;">',
   		 	'<tpl for=".">',
   		 		'<li>{[Ext.String.escapeHtml(values.pageTitle)]}</li>',
   		 	'</tpl>',
   		 '</ul>',
   		"<br/>{{i18n PLUGINS_WEB_PAGE_BLANKPAGE_CONFIRM2}}", 
		"<br/>{{i18n PLUGINS_WEB_PAGE_BLANKPAGE_CONFIRM3}}",
		"<br/><br/><span style='font-style: italic'>{{i18n PLUGINS_WEB_PAGE_BLANKPAGE_CONFIRM4}}</span>."
	),
	
	/**
	 * @private
	 * @property {Ext.Template} _templatePageConfirmTpl Template for confirm message when setting template on a page
	 */
	_templatePageConfirmTpl: Ext.create('Ext.XTemplate', 
			"<div>",
				"{{i18n PLUGINS_WEB_PAGE_TEMPLATESMENU_AFFECT_CONFIRM3}}",
				"<span style='font-weight: bold'>{[Ext.String.escapeHtml(values.pageTitle)]}</span> ?",
				"<br/><br/><span style='font-style: italic'>{{i18n PLUGINS_WEB_PAGE_TEMPLATESMENU_AFFECT_CONFIRM4}}</span>.",
			"</div>"
	),
	
	/**
	 * @private
	 * @property {Ext.XTemplate} _templatePagesConfirmTpl Template for confirm message when setting template on pages
	 */
	_templatePagesConfirmTpl: Ext.create('Ext.XTemplate',
		 "{{i18n PLUGINS_WEB_PAGE_TEMPLATESMENU_AFFECT_CONFIRM1}}",
   		 '<ul style="margin: 5px; padding-left: 25px;">',
   		 	'<tpl for=".">',
   		 		'<li>{[Ext.String.escapeHtml(values.pageTitle)]}</li>',
   		 	'</tpl>',
   		 '</ul>',
		"<br/><br/><span style='font-style: italic'>{{i18n PLUGINS_WEB_PAGE_TEMPLATESMENU_AFFECT_CONFIRM2}}</span>."
	),
	
	/**
	 * Open page
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
	 */
	open: function(controller)
	{
		var pageTarget = controller.getMatchingTargets()[0];
		Ametys.tool.ToolsManager.openTool(pageTarget.getId() == Ametys.message.MessageTarget.PAGE ? 'uitool-page' : 'uitool-sitemappage', {id: pageTarget.getParameters().id});
	},
	
	/**
	 * Update page as a redirection towards an external web page
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
	 */
	linkWeb: function(controller)
	{
		this._confirmSetLink (controller.getMatchingTargets(), Ext.bind(this._doLinkWeb, this));
	},
	
	/**
	 * @private
	 * Do web link on selected page after user has confirmed
	 * @param {Ametys.message.MessageTarget} targets The concerned page targets
	 */
	_doLinkWeb: function (targets)
	{
		Ametys.helper.EnterURL.open({
            iconCls: ["ametysicon-website38", "decorator-ametysicon-arrow73"],
            title: "{{i18n PLUGINS_WEB_PAGE_LINKPAGE_WEBREDIRECTTITLE}}",
            helpmessage: "{{i18n PLUGINS_WEB_PAGE_LINKPAGE_WEBREDIRECTDESCRIPTION}}",
			footermessage: null,
			callback: Ext.bind(this._linkWebCB, this, [targets], 1),
			defaultValue: targets[0].getParameters().urlType == Ametys.web.page.Page.URL_TYPE_EXTERNAL ? targets[0].getParameters().url : '',
			regex: '^(https?://|/).+$' // Copy of the regexp in Ametys.plugins.web.page.AddPageWizard.PageTypeCard#_createExternalLinkRedirectionPanel4SelectPageTypeCard
        });
	},
	
	/**
	 * @private
	 * Ask for user confirmation before setting page(s) as redirection page(s).
	 * @param {Ametys.message.MessageTarget} targets The concerned page targets
	 * @param {Function} confirmCb The function to call if user confirms his choice
	 */
	_confirmSetLink: function (targets, confirmCb)
	{
		if (targets.length == 1)
		{
			Ametys.Msg.confirm("{{i18n PLUGINS_WEB_PAGE_LINKPAGE_CONFIRM_LABEL2}}", 
					this._linkPageConfirmTpl.applyTemplate({pageTitle: targets[0].getParameters().title}), 
					Ext.bind(this._confirmSetLinkCB, this, [targets, confirmCb], 1), 
					this
			);
		}
		else if (targets.length > 1)
		{
			var pages = [];
			for (var i=0; i < targets.length; i++)
			{
				pages.push({pageTitle: targets[i].getParameters().title});
			}
			Ametys.Msg.confirm("{{i18n PLUGINS_WEB_PAGE_LINKPAGE_CONFIRM_LABEL}}", 
					this._linkPagesConfirmTpl.applyTemplate(pages), 
					Ext.bind(this._confirmSetLinkCB, this, [targets, confirmCb], 1), 
					this
			);
		}
	},
	
	/**
	 * @private
	 * Callback function invoked after the confirm box for set link process is closed
	 * @param {String} answer the user answer
	 * @param {Ametys.message.MessageTarget[]} targets the page targets
	 * @param {Function} confirmCb callback function to invoke if confirm
	 */
	_confirmSetLinkCB: function (answer, targets, confirmCb)
	{
		if (answer == 'yes')
		{
			confirmCb (targets);
		}
	},
	
	/**
	 * @private
	 * Callback function after entering redirection url
	 * @param {String} url the external url
	 * @param {Ametys.message.MessageTarget[]} targets the page targets
	 */
	_linkWebCB: function (url, targets)
	{
		if (url)
		{
			var ids  = [];
			Ext.Array.each (targets, function (target) {
				ids.push(target.getParameters().id)
			});
			
			Ametys.web.page.PageDAO.setLink ([ids, url, Ametys.web.page.Page.URL_TYPE_EXTERNAL], null, {});
		}
	},
	
	/**
	 * Update page as a redirection towards another page
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
	 */
	linkPage: function (controller)
	{
		var parentControllerId = controller['parent-controller'];
		var parentController = Ametys.ribbon.RibbonManager.getUI(parentControllerId);
		
		this._confirmSetLink (parentController.getAllRightPageTargets(), Ext.bind(this._doLinkPage, this));
	},
	
	/**
	 * @private
	 * Do page link on selected page(s) after user has confirmed
	 * @param {Ametys.message.MessageTarget} targets The concerned page targets
	 */
	_doLinkPage: function (targets)
	{
		Ametys.web.helper.ChoosePage.open ({
			iconCls: 'ametysicon-website38 decorator-ametysicon-arrow73',
			title: "{{i18n PLUGINS_WEB_PAGE_LINKPAGE_REDIRECTTITLE}}",
			helpMessage: "{{i18n PLUGINS_WEB_PAGE_LINKPAGE_REDIRECTDESCRIPTION}}",
			siteContext: Ametys.web.helper.ContextToolbar.SITE_CONTEXT_ALL,
			sitemapContext: Ametys.web.helper.ContextToolbar.SITEMAP_CONTEXT_ALL,
			defaultSiteName: targets[0].getParameters().siteName,
			defaultSitemapName: targets[0].getParameters().lang,
			values: targets[0].getParameters().urlType == Ametys.web.page.Page.URL_TYPE_PAGE ? [targets[0].getParameters().url] : [],
			multiple: false,
			allowCreation: true,
			callback: Ext.bind(this._choosePageCB, this, [targets], 1)
		})
	},
	
	/**
	 * @private
	 * Callback function after choosing page of redirection
	 * @param {String} redirectPageId the id of page redirection
	 * @param {Ametys.message.MessageTarget[]} targets the page targets
	 */
	_choosePageCB: function (redirectPageId, targets)
	{
		if (redirectPageId)
		{
			var ids  = [];
			Ext.Array.each (targets, function (target) {
				if (target.getParameters().id == redirectPageId)
				{
					Ametys.Msg.show({
			            title: "{{i18n PLUGINS_WEB_PAGE_LINKPAGE_ERRORTITLE}}",
			            msg: "{{i18n PLUGINS_WEB_PAGE_LINKPAGE_REDIRECT_ITSELF_ERROR}}",
			            buttons: Ext.Msg.OK,
			            icon: Ext.MessageBox.ERROR
			        });
					return;
				}
				
				ids.push(target.getParameters().id)
			})
			
			Ametys.web.page.PageDAO.setLink ([ids, redirectPageId, Ametys.web.page.Page.URL_TYPE_PAGE], null, {});
		}
	},
	
	/**
	 * Set page as blank page
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
	 */
	setBlank: function (controller)
	{
		var targets = controller.getAllRightPageTargets();
		if (targets.length == 1)
		{
			Ametys.Msg.confirm("{{i18n PLUGINS_WEB_PAGE_BLANKPAGE_CONFIRMTITLE}}", 
					this._blankPageConfirmTpl.applyTemplate({pageTitle: targets[0].getParameters().title}), 
					Ext.bind(this._confirmSetBlankCB, this, [[targets[0].getParameters().id]], 1), 
					this
			);
		}
		else
		{
			var ids = [];
			var pages = [];
			for (var i=0; i < targets.length; i++)
			{
				ids.push(targets[i].getParameters().id);
				pages.push({pageTitle: targets[i].getParameters().title});
			}
			
			Ametys.Msg.confirm("{{i18n PLUGINS_WEB_PAGE_BLANKPAGE_CONFIRMTITLE}}", 
					this._blankPagesConfirmTpl.applyTemplate(pages), 
					Ext.bind(this._confirmSetBlankCB, this, [ids], 1), 
					this
			);
		}
	},
	
	/**
	 * @private
	 * Callback function invoked after the confirm box for set blank process is closed
	 * @param {String} answer the user answer
	 * @param {String} ids the page ids
	 */
	_confirmSetBlankCB: function (answer, ids)
	{
		if (answer == 'yes')
		{
			Ametys.web.page.PageDAO.setBlank ([ids], null, {});
		}
	},
	
	/**
	 * Affect template to matching pages
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
	 */
	setTemplate: function (controller)
	{
		var parentControllerId = controller['parent-controller'];
		var parentController = Ametys.ribbon.RibbonManager.getUI(parentControllerId);
		
		var targets = parentController.getAllRightPageTargets();
		
		if (targets.length == 1)
		{
			Ametys.Msg.confirm("{{i18n PLUGINS_WEB_PAGE_TEMPLATESMENU_AFFECT_CONFIRMTITLE}}", 
					this._templatePageConfirmTpl.applyTemplate({pageTitle: targets[0].getParameters().title}), 
					Ext.bind(this._confirmSetTemplateCB, this, [[targets[0].getParameters().id], controller.name], 1), 
					this
			);
		}
		else
		{
			var ids = [];
			var pages = [];
			for (var i=0; i < targets.length; i++)
			{
				ids.push(targets[i].getParameters().id);
				pages.push({pageTitle: targets[i].getParameters().title});
			}
			
			Ametys.Msg.confirm("{{i18n PLUGINS_WEB_PAGE_TEMPLATESMENU_AFFECT_CONFIRMTITLE}}", 
					this._templatePagesConfirmTpl.applyTemplate(pages), 
					Ext.bind(this._confirmSetTemplateCB, this, [ids, controller.name], 1), 
					this
			);
		}
	},
	
	/**
	 * @private
	 * Callback function invoked after the confirm box for set template process is closed
	 * @param {String} answer the user answer
	 * @param {String} ids the page ids
	 * @param {String} template the template name
	 */
	_confirmSetTemplateCB: function (answer, ids, template)
	{
		if (answer == 'yes')
		{
			Ametys.web.page.PageDAO.setTemplate ([ids, template], null, {});
		}
	},
	
	/**
	 * Exclude or include pages for robots.
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
     * @param {Boolean} state the press-state of the controller
	 */
	editRobots: function (controller, state)
	{
		var me = this;
		var exclude = state;
		var pageIds = exclude ? controller.getIncludedPageIds() : controller.getExcludedPageIds();
		
		Ametys.Msg.confirm("{{i18n PLUGINS_WEB_PAGE_SEO_ROBOTS_TITLE}}",
				exclude ?  "{{i18n PLUGINS_WEB_PAGE_SEO_ROBOTS_DISALLOW_CONFIRM}}" : "{{i18n PLUGINS_WEB_PAGE_SEO_ROBOTS_ALLOW_CONFIRM}}",
				Ext.bind (this._editRobotsConfirmCb, this, [controller, pageIds, exclude], 1),
				this);
	},
	
	/**
	 * @private
	 * Function invoked on confirm dialog box is closed
	 * @param {String} answer The user answer
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
	 * @param {String[]} pageIds the ids of concerned pages
	 * @param {Boolean} exclude `true` to exclude pages from robots or `false` to include pages.
	 */
	_editRobotsConfirmCb: function (answer, controller, pageIds, exclude)
	{
		if (answer == 'yes')
		{
			controller.serverCall('editRobots',
					[pageIds, exclude], 
					Ext.bind(this._editRobotsCb, this),
					{ 
						errorMessage: { 
							msg: exclude ? "{{i18n PLUGINS_WEB_PAGE_SEO_ROBOTS_DISALLOW_ERROR}}" : "{{i18n PLUGINS_WEB_PAGE_SEO_ROBOTS_ALLOW_ERROR}}", 
							category: this.self.getName() 
						},
						arguments: {
							pageIds: pageIds
						},
                        refreshing: true
					}
			);
		}
	},
	
	/**
	 * @private
	 * Callback invoked after robots editing
	 * @param {Object} response The server response.
	 * @param {Object} args The callback arguments
	 */
	_editRobotsCb: function (response, args)
	{
        var pageIds = [];
        
        Ext.Array.each (response["allright-pages"] || [], function (id) {
            if (Ext.String.startsWith(id, "sitemap://"))
            {
                Ext.create('Ametys.message.Message', {
	                type: Ametys.message.Message.MODIFIED,
	                parameters: {major: false},
	                targets: [{
	                    id: Ametys.message.MessageTarget.SITEMAP,
	                    parameters: {
	                        id: id
	                    }
	                }]
	            });
            }
            else
            {
                pageIds.push(id);
            }
        });
        
        if (pageIds.length > 0)
        {
            Ext.create('Ametys.message.Message', {
	            type: Ametys.message.Message.MODIFIED,
	            parameters: {major: false},
	            targets: [{
	                id: Ametys.message.MessageTarget.PAGE,
	                parameters: {
	                    ids: pageIds
	                }
	            }]
	        });
        }
        
        this._showError(
        	response["noright-pages"] || response["locked-pages"] || [],
        	"{{i18n PLUGINS_WEB_PAGE_SEO_ROBOTS_NORIGHT_ERROR_TITLE}}",
        	response["noright-pages"] ? "{{i18n PLUGINS_WEB_PAGE_SEO_ROBOTS_NORIGHT_ERROR}}" : "{{i18n PLUGINS_WEB_PAGE_SEO_ROBOTS_LOCKED_ERROR}}")
	},
	
	/**
	 * Copy the selected page and its hierarchy
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
	 */
	copyPage: function(controller)
	{
		var pageTargets = controller.getMatchingTargets();
		if (pageTargets.length > 0)
		{
			// keep title too for the button's tooltip
			Ametys.clipboard.Clipboard.setData (Ametys.message.MessageTarget.PAGE, pageTargets[0].getParameters().page);
		}
	},
	
	/**
	 * Paste the clipboard's page and its hierarchy under the selected page, with duplication of contents
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
	 */
	pastePage: function (controller)
	{
		var pageTargets = controller.getMatchingTargets();
		if (pageTargets.length > 0)
		{
			this._pastePage (pageTargets[0].getParameters().id, false);
		}
	},	
	
	/**
	 * Paste the clipboard's page and its hierarchy under the selected page, keeping references to contents, ie. without duplicating contents
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
	 */
	pastePageWithReferences: function (controller)
	{
		var pageTargets = controller.getMatchingTargets();
		if (pageTargets.length > 0)
		{
			this._pastePage (pageTargets[0].getParameters().id, true);
		}
	},	
	
	/**
	 * @private
	 * Paste the clipboard's page and its hierarchy under the given target page
	 * @param {String} targetPageId The id of target page
	 * @param {Boolean} keepReferences true to keep references
	 */
	_pastePage: function (targetPageId, keepReferences)
	{
		var clipboardData = Ametys.clipboard.Clipboard.getData();
		if (clipboardData.length > 0 && Ametys.clipboard.Clipboard.getType() == Ametys.message.MessageTarget.PAGE)
		{
			var pageToCopy = clipboardData[0];
			
			Ametys.data.ServerComm.callMethod({
				role: "org.ametys.web.repository.page.PageDAO",
				methodName: "copyPage",
				parameters: [pageToCopy.getId(), targetPageId, keepReferences],
				callback: {
					scope: this,
					handler: this._pastePageCb
				},
				errorMessage: {
					category: this.self.getName(),
					msg: "{{i18n PLUGINS_WEB_COPYPAGE_ERROR}}"
				},
				waitMessage: true
			});
		}
	},

	/**
	 * @private
	 * Callback for the page pasting process
	 * @param {Object} response the server's response
	 * @param {String} response.id the id of the created page
	 * @param {Object} args the callback arguments
	 */
	_pastePageCb: function(response, args)
	{
		Ametys.clipboard.Clipboard.setData (Ametys.message.MessageTarget.PAGE, null);
		
		Ext.create('Ametys.message.Message', {
			type: Ametys.message.Message.CREATED,
			targets: {
				id: Ametys.message.MessageTarget.PAGE,
				parameters: { ids: [response.id] }
			}
		});
	},
	
	/**
	 * Open preview
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
	 */
	openPreview: function (controller)
	{
		var targets = controller.getAllRightPageTargets();
		
		if (targets.length > 0)
		{
			var liveUrl = Ametys.getPluginDirectPrefix('web') + '/page/preview?id=' + encodeURIComponent(targets[0].getParameters().id);
			window.open(liveUrl);
		}
		
	},
	
	/**
	 * Open live preview
	 * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
	 */
	openLivePreview: function (controller)
	{
		var targets = controller.getAllRightPageTargets();
		
		if (targets.length > 0)
		{
			var liveUrl = Ametys.getPluginDirectPrefix('web') + '/page/live?id=' + encodeURIComponent(targets[0].getParameters().id);
			window.open(liveUrl);
		}
	},
    
    /**
     * Edit the visibility of a page
     * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
     * @param {Boolean} state the press-state of the controller
     */
    setVisibility: function (controller, state)
    {
        var me = this;
        var invisible = state;
        
        var pageIds = invisible ? controller.getVisiblePageIds() : controller.getInvisiblePageIds();
        
        Ametys.web.page.PageDAO.setVisibility ([pageIds, !invisible], null, {});
    },
    
    /**
     * @private
     * @param {Object[]} pagesInError pages in errors
     * @param {String} errorTitle title of the error
     * @param {String} errorMsg error message
     */
    _showError: function (pagesInError, errorTitle, errorMsg)
    {
        if (pagesInError.length)
        {
            var msg = errorMsg;
            msg += Ext.Array.map(pagesInError, p => "<strong>" + p.title + "</strong>").join(", ");
            
            Ametys.Msg.show({
                title: errorTitle,
                msg: msg,
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
        }
    }
});