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

/**
 * DAO for zone.
 */
Ext.define("Ametys.plugins.web.zone.ZoneDAO", {
	singleton: true,
	
	/**
	 * Remove a zone item
	 * @param {String} pageId The id of page
	 * @param {String} zoneName The name of zone
	 * @param {String} zoneItemId The id of zone item to remove
	 * @param {String} [contentId] The id of content to remove from zone item
     * @param {Boolean} [deleteContent] true if the content should be deleted
	 * @param {String} [serviceId] The id of the service that will be deleted
	 * @param {Function} [callback] the callback function. Arguments are:
	 * @param {Boolean} callback.success true if removal has succeeded
	 * @param {String} callback.pageId The affected page's id
	 * @param {String} callback.zoneName The affected zone's name
	 */
	removeZoneItem: function (pageId, zoneName, zoneItemId, contentId, deleteContent, serviceId, callback)
	{
		Ametys.data.ServerComm.callMethod({
			role: "org.ametys.web.repository.page.ZoneDAO",
			methodName: "removeZoneItem",
			parameters: [ zoneItemId],
			callback: {
				scope: this,
				handler: this._removeZoneItemCb,
				arguments: {
					callback: callback,
					pageId: pageId,
					zoneName: zoneName,
                    deleteContent: deleteContent,
					contentId: contentId,
					serviceId: serviceId
				}
			},
			errorMessage: {
				category: this.self.getName(),
				msg: "{{i18n PLUGINS_WEB_CONTENT_REMOVEZONEITEM_ERROR}}"
			}
		});
	},
	
	/**
	 * @private
	 * Callback function after zone item deletion.
	 * @param {Object} response The server response (void)
	 * @param {Object} args The callback arguments
	 * @param {String} args.pageId the concerned page
	 * @param {String} args.zoneName the concerned zone
	 * @param {String} args.contentId The id of content to delete after zone item removal. Can be null.
     * @param {String} args.serviceId The id of the service that was in the zone item if any.
	 * @param {String} [args.callback] the callback function
	 */
	_removeZoneItemCb: function (response, args)
	{
		// Send a modified then a selection change event
		this._fireModifiedPageEvent (args.pageId, args.zoneName);
		
		if (args.contentId && args.deleteContent)
		{
			// Delete the content
			Ametys.cms.content.ContentDAO.getContent(args.contentId, Ext.bind (this._getContentCb, this, [args.pageId, args.zoneName, args.callback], 1));
		}
		else
		{
            if (args.contentId)
            {
                Ametys.cms.content.ContentDAO.getContent(args.contentId, Ext.bind (this._notifyContentDeletion, this, [args.pageId], 1));
            }
            
		    if (args.serviceId)
	        {
		        this._notifyServiceDeletion(args.pageId, args.serviceId);
	        }
		    
			if (Ext.isFunction (args.callback))
			{
				args.callback(true, args.pageId, args.zoneName);
			}
		}
	},
	
	/**
	 * @private
	 * Send a modified event on message bus for given page/zone or page/zoneitem
	 * @param {String} pageId The page's id / sitemap's id
	 * @param {String} [zoneName] The zone's name concerned by the modification. Have to be null if the zoneItemId is not null. 
	 * @param {String} [zoneItemId] The zone item's id concerned by the modification. Have to be null if the zoneName is not null. 
	 * @param {Function} [callback] The callback function to invoked after firing message
	 */
	_fireModifiedPageEvent: function (pageId, zoneName, zoneItemId, callback)
	{
		function sendPageMessage (page)
		{
			Ext.create('Ametys.message.Message', {
				type: Ametys.message.Message.MODIFIED, // TODO zoningChanged ?
				targets: [{
                    id: Ametys.message.MessageTarget.PAGE,
					parameters: {
					    'pages': [page], 
						'zone-name': zoneName,
						'zoneitem-id': zoneItemId
					}
				}]
			});
			
			if (Ext.isFunction (callback))
			{
				callback (page);
			}
		}
        function sendSitemapMessage (page)
        {
            Ext.create('Ametys.message.Message', {
                type: Ametys.message.Message.MODIFIED, // TODO zoningChanged ?
                targets: [{
                    id: Ametys.message.MessageTarget.SITEMAP,
                    parameters: { 
                        'sitemap': page, 
                        'zone-name': zoneName,
                        'zoneitem-id': zoneItemId
                    }
                }]
            });
            
            if (Ext.isFunction (callback))
            {
                callback (page);
            }
        }
		
		if (pageId.startsWith('sitemap://'))
		{
    		Ametys.web.sitemap.SitemapDAO.getSitemap(pageId, sendSitemapMessage);
		}
		else
		{
    		Ametys.web.page.PageDAO.getPage(pageId, sendPageMessage);
		}
	},
	
	/**
	 * @private
	 * Callback function after retrieving content. Delete the content.
	 * @param {Ametys.cms.content.Content} content The content to delete
	 * @param {String} pageId the page's id
	 * @param {String} zoneName The zone's name
	 * @param {Function} callback The callback function
	 * @returns
	 */
	_getContentCb: function (content, pageId, zoneName, callback)
	{
		var me = this;
		function prep (targets)
		{
			// Delete content
			Ametys.cms.content.ContentDAO.trashContents ([content.getId()], targets, Ext.bind(me._deleteContentCb, me, [pageId, zoneName, callback], false));
		}
		
		// Prepare content target
		Ametys.message.MessageTargetFactory.createTargets({id: Ametys.message.MessageTarget.CONTENT,
			parameters: {
				contents: [content]
			}
		}, prep);
	},
	
	/**
	 * @private
	 * Callback function after deleting content. 
	 * @param {String} pageId the page's id
	 * @param {String} zoneName The zone's name
	 * @param {Function} callback The callback function
	 */
	_deleteContentCb: function (pageId, zoneName, callback)
	{
        if (Ext.isFunction (callback))
        {
            callback(true, pageId, zoneName);
        }
	},
	
    /**
     * @protected
     * Notify that to content was remove from a page
     * @param {String} content The content removed from page
     * @param {String} pageId The page id
     */
    _notifyContentDeletion: function(content, pageId)
    {
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.web.repository.page.PageDAO",
            methodName: 'getPagesInfos',
            parameters: [[pageId]],
            callback: {
                handler: function(pagesInfos) {
                     Ametys.notify({
                        type: 'info',
                        iconGlyph: 'ametysicon-text70',
                        title: "{{i18n plugin.cms:PLUGINS_CMS_NOTIFICATION_DELETE_CONTENT_TITLE}}",
                        description: Ext.String.format("{{i18n plugin.web:PLUGINS_WEB_NOTIFICATION_REMOVE_CONTENT_FROM_PAGE}}", Ext.String.escapeHtml(content.getTitle()), Ext.String.escapeHtml(pagesInfos.pages[0].title)),
                        action: Ext.bind(Ametys.tool.ToolsManager.openTool, Ametys.tool.ToolsManager, ['uitool-page', {id: pageId}], false)
                    });
                }
            },
            errorMessage: true
        });
    },
    
	/**
	 * @protected
	 * Notify the deletion of the service
	 * @param {String} pageId The page id
	 * @param {String} serviceId The service id
	 */
	_notifyServiceDeletion: function(pageId, serviceId)
	{
        var i18nDesc = "{{i18n PLUGINS_WEB_NOTIFICATION_DELETE_SERVICE_DESCRIPTION}}";
        
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.web.repository.page.PageDAO",
            methodName: 'getServiceInfo',
            parameters: [pageId, serviceId],
            callback: {
                handler: function(serviceInfo) {
                    Ametys.notify({
                        type: 'info',
                        iconGlyph: serviceInfo.iconGlyph,
                        icon: serviceInfo.iconGlyph != null ? null : Ametys.CONTEXT_PATH + serviceInfo.mediumIcon,
                        title: "{{i18n PLUGINS_WEB_NOTIFICATION_DELETE_SERVICE_TITLE}}",
                        description: Ext.String.format(i18nDesc, serviceInfo.label, serviceInfo['page-title']),
                        action: Ext.bind(Ametys.tool.ToolsManager.openTool, Ametys.tool.ToolsManager, ['uitool-page', {id: pageId}], false)
                    });
                }
            },
            errorMessage: true
        });
	},
	
	/**
	 * Insert a shared content into the zone
	 * @param {String} pageId The id of page
	 * @param {String} zoneName The name of zone
	 * @param {String} contentId The id of content to insert
	 * @param {String} [viewName=main] The view name.
	 * @param {Function} [callback] the callback function. Arguments are:
	 * @param {Boolean} callback.success true if removal has succeeded
	 * @param {String} callback.pageId The affected page's id
	 * @param {String} callback.zoneName The affected zone's name
	 */
	addSharedContent: function (pageId, zoneName, contentId, viewName, callback)
	{
		Ametys.data.ServerComm.callMethod({
			role: "org.ametys.web.repository.page.ZoneDAO",
			methodName: "addSharedContent",
			parameters: [ pageId, zoneName, contentId, viewName || 'main' ],
			callback: {
				scope: this,
				handler: this._addSharedContentCb,
				arguments: {
					callback: callback,
					pageId: pageId,
					zoneName: zoneName
				}
			},
			errorMessage: {
				category: this.self.getName(),
				msg: "{{i18n PLUGINS_WEB_CONTENT_ADDSHAREDCONTENT_ERROR}}"
			}
		});
	},
	
	/**
	 * @private
	 * Callback function after adding shared content
	 * @param {Object} response The server response (void)
	 * @param {Object} args The callback arguments
	 * @param {String} args.pageId The id of page
	 * @param {String} args.zoneName The zone name
	 * @param {Function} [args.callback] The callback function
	 */
	_addSharedContentCb: function (response, args)
	{
		if (response.error)
		{
			if (response['invalid-contenttype'])
			{
				Ametys.Msg.show ({
		    		title: "{{i18n PLUGINS_WEB_CONTENT_ADDSHAREDCONTENT_ERROR_IMPOSSIBLE}}",
		    		msg: "{{i18n PLUGINS_WEB_CONTENT_ADDSHAREDCONTENT_ERROR_INVALID_CTYPE_1}}" + '(' + response['invalid-contenttype'] + ')<br/>' + "{{i18n PLUGINS_WEB_CONTENT_ADDSHAREDCONTENT_ERROR_INVALID_CTYPE_2}}",
		    		buttons: Ext.Msg.OK,
		    		icon: Ext.MessageBox.ERROR
		    	});
			}
			
			if (response['unpublished-content'])
			{
				Ametys.Msg.show ({
		    		title: "{{i18n PLUGINS_WEB_CONTENT_ADDSHAREDCONTENT_ERROR_IMPOSSIBLE}}",
		    		msg: "{{i18n PLUGINS_WEB_CONTENT_ADDSHAREDCONTENT_ERROR_CONTENT_NOT_VALIDATED}}",
		    		buttons: Ext.Msg.OK,
		    		icon: Ext.MessageBox.ERROR
		    	});
			}
			
			if (Ext.isFunction (args.callback))
			{
				args.callback(false, args.pageId, args.zoneName);
			}
			return;
		}

		// Send a modified then a selection changed event on page
		this._fireModifiedPageEvent (args.pageId, null, response.zoneItemId);
		
		if (Ext.isFunction (args.callback))
		{
			args.callback(true, args.pageId, args.zoneName);
		}
	},
    
    
    /**
     * Insert a shared content into the zone
     * @param {String} zoneItemId The identifier of the zone item to move
     * @param {String} zoneName The destination zone name
     * @param {Boolean} beforeOrAfter true if before or false after
     * @param {String} beforeOrAfterItemId The target zone item can be null
     * @param {String} pageId The concerned page id
     * @param {Function} [callback] the callback function. Arguments are:
     * @param {Boolean} callback.success true if removal has succeeded
     * @param {String} callback.pageId The affected page's id
     * @param {String} callback.zoneName The affected zone's name
     */
    moveZoneItem: function (zoneItemId, zoneName, beforeOrAfter, beforeOrAfterItemId, pageId, callback)
    {
        Ametys.data.ServerComm.callMethod({
            role: "org.ametys.web.repository.page.ZoneDAO",
            methodName: "moveZoneItemTo",
            parameters: [ zoneItemId, zoneName, beforeOrAfter, beforeOrAfterItemId, pageId ],
            callback: {
                scope: this,
                handler: this._moveZoneItemCb,
                arguments: {
                    callback: callback,
                    pageId: pageId,
                    zoneName: zoneName
                }
            },
            errorMessage: {
                category: this.self.getName(),
                msg: "{{i18n PLUGINS_WEB_CONTENT_MOVEZONEITEM_ERROR}}"
            }
        });
    },
    
    /**
     * @private
     * Callback function after adding shared content
     * @param {Object} response The server response (void)
     * @param {Object} args The callback arguments
     * @param {String} args.pageId The id of page
     * @param {String} args.zoneName The zone name
     * @param {Function} [args.callback] The callback function
     */
    _moveZoneItemCb: function (response, args)
    {
        if (!response)
        {
            if (Ext.isFunction (args.callback))
            {
                args.callback(false, args.pageId, args.zoneName);
            }
            return;
        }

        // Send a modified then a selection changed event on page
        this._fireModifiedPageEvent (args.pageId, null, null);
        
        if (Ext.isFunction (args.callback))
        {
            args.callback(true, args.pageId, args.zoneName);
        }
        
    }    
});