/**
 * AS4WidgetsLayoutEditor Class
 *
 * Behaviours for the channel component's widgets layout editor
 */

var widgetsLayoutEditor;
var resourceLibrary;

document.observe('dom:loaded', function() {
	if(AS4ResourceLibrary)
	{
		resourceLibrary = new AS4ResourceLibrary();
	
		if(Prototype.Browser.IE && typeof(widgetsLayoutEditor) != 'undefined')
		{
			resourceLibrary.onResourceClicked = widgetsLayoutEditor.onResourceSelected.bind(widgetsLayoutEditor);
		}
		

		// Override the resource library's success callback to make each resource a selectable
		// thing
		resourceLibrary.onFetchResourcesSuccess = function(transport, target)
		{
			// Ignore exceptions
			if(transport.headerJSON && transport.headerJSON.exception)
				return;
		}
	}
});

window.onbeforeunload = function(e) 
{
	if(widgetsLayoutEditor && widgetsLayoutEditor.is_dirty)
	{
	var e = e || window.event;

	if(e)
		e.returnValue = 'You have not saved the current layout. Are you sure you want to leave this page? (Unsaved changes will be lost)';

	return 'You have not saved the current layout. Are you sure you want to leave this page? (Unsaved changes will be lost)';
	}
};

var AS4WidgetsLayoutEditor = Class.create({

	/**
	 * @type {Element} Cache the root element that contains the widget-sortables
	 */
	sortables_container: null,

	/**
	 * @type {Boolean} Indicate if the widgets layout editor is currently saving the page layout
	 */
	isSaving: null,

	/**
	 * @type {integer} Store a reference to the current channel id
	 */
	channel_id: null,

	/**
	 * @type {AS4ResourceLibrary} The local resource library instance for selecting resources
	 */
	resource_library: null,

	/**
	 * @type {Hash} The current channel_widgets_id and options_id into which a selected resource will be injected
	 */
	selected_option: null,

	/**
	 * @type {Boolean} Indicate if the current layout is dirtied and requires saving
	 */
	is_dirty: false,

	/**
	 * Create a widgets layout editor for the given element. The element should contain
	 * an array of widget_column elements
	 *
	 * @param {Element} The root element for the widgets layout editor
	 */
	create:function(element)
	{
		this.sortables_container = $(element);
		this._createSortables();
		
		this.isSaving = false;
		this.is_dirty = false;

		if(resourceLibrary && AS4ResourceLibrary)
			resourceLibrary.onResourceClicked = this.onResourceSelected.bind(this);

		// Trigger unload warnings
		var self = this;
	},

	/**
	 * Return the containment elements for draggables
	 *
	 * @return Array
	 */
	_containmentElements: function()
	{
		columns = this.sortables_container.select('.widget_column', '.widget_column_primary_editable', '.widget_column_secondary_editable', '.widget_column_tertiary_editable' );
		columns.invoke('identify');

		containment = columns.clone();
		containment.push('widget_header');
		containment.push('widget_footer');

		return containment;
	},


	/**
	 * Private method to create the sortables in the current
	 * sortables_container
	 */
	_createSortables: function()
	{
		columns = this.sortables_container.select('.widget_column', '.widget_column_primary_editable', '.widget_column_secondary_editable', '.widget_column_tertiary_editable' );
		columns.invoke('identify');

		// Fix IE6's buggy drag-dropping
		Position.includeScrollOffsets = true;	

		var sortable_options = {
			tag: 'div',
			//only: 'widget',
			handle: ['toolbar'],
			constraint: null,
			hoverclass: 'active_drop',
			dropOnEmpty: true,
			scroll: window,
			containment: this._containmentElements(),
			onChange: this.onPanelDragged.bind(this),
			onUpdate: this.onPanelDropped.bind(this)
		}
        
		columns.each(function(column) {
			Sortable.destroy(column.identify());
			Sortable.create(column.identify(), sortable_options);
		});

		// Create header and footer sortables
		Sortable.destroy('widget_header');
		Sortable.destroy('widget_footer');

		Sortable.create('widget_header', sortable_options);
		Sortable.create('widget_footer', sortable_options);
	},
	
	/**
	 * Returns all the sortable (droppable) elements as an array
	 *
	 * @return {Array}
	 */
	_getSortableElements: function()
	{
		sortables = this.sortables_container.select('.widget_column', '.widget_column_primary_editable', '.widget_column_secondary_editable', '.widget_column_tertiary_editable' );

		sortables.push($('widget_header'));
		sortables.push($('widget_footer'));

		return sortables;
	},

	/**
	 * Display an inline resource selector to allow the user
	 * to select a resource to be associated to the widget
	 * 
	 * @param {integer} channel_widgets_id The channel_widgets_id that will receive the selected resource
	 * @param {integer} options_id The option identifier within the channel widget
	 * @param {Array} [resource_types] Optional array of the resource types that the media selector will show. Default is an empty array (all resource types)
	 *
	 */
	showResourceSelector: function(channel_widgets_id, options_id, resource_types)
	{
		var resource_types = (resource_types ? resource_types : $A());

		/**
		this.resourceValueTarget = target.down('div.current_value');
		this.resourceValueHTML = target.down('input.'+target.down('input.metaType').value);
		this.resourceValueHolder = target.down('div.current_item');
		*/

		resourceLibrary.searchTypes = resource_types;

		this.selected_option = {
			channel_widgets_id: channel_widgets_id,
			options_id: options_id
		};

		AS4Shell.getInstance().showLightbox({
			callback: this.onShowResourceSelector.bind(this),
			width: 613,
			height: 645
		});
	},

	/**
	 * Callback for the resource selector lightbox
	 */
	onShowResourceSelector: function()
	{
		var url = '/channel/resource_selector_lightbox';

		var params = {
			renderMode: 'lightbox',
			folder_id: this.channel_id
		};
		
		AS4Shell.getInstance().ajaxUpdate(url, params, 'add_panel_container', $A([this.onImagesSelectorShown.bind(this)]), {showIndicator: false});
		
		return	'<div id="add_panel_container">' +
					'<div class="centre" style="padding-top: 40%">' +
						'<img src="/app/common/assets/images/ajax-loader.gif" alt="Loading..>" width="24" height="24" /><br />Loading...' +
					'</div>' +
				'</div>';
	},

	/**
	 * Trigger a load of the resource selector once it is loaded into the lightbox!
	 */
	onResourceSelectorShown: function(transport, target)
	{
		resourceLibrary.channelId = AS4ResourceBrowser.MY_RESOURCES_PATH;

		// Bind lightbox interface
		if($('ml_search_terms'))
			$('ml_search_terms').observe('keyup', function(e) {
				resourceLibrary.searchTerms = $F(this);
				resourceLibrary.setResourcesPage(1, {refresh: false});
				resourceLibrary.startSearch.bind(resourceLibrary, $F(this)).delay(2); // Delay the search by 2 seconds, allowing typing to catch up
			});

		// Smart folder filters
		if($('smart_folder'))
		{
			$('smart_folder').observe('change', function(e) {
				resourceLibrary.setResourcesPage(1, {refresh: false});
				resourceLibrary.currentFolderId = $F(this);
				resourceLibrary.fetchResources();
			});

			
			// Default search should match the current selection
			resourceLibrary.currentFolderId = $F('smart_folder');
		}
		
		resourceLibrary.setResourcesPage(1, {refresh: false});
		resourceLibrary.searchTerms = '';

		// Run a search
		resourceLibrary.fetchResources();
	},
	
	/**
	 * Display an inline resource selector to allow the user
	 * to select images for the slide show panel
	 * 
	 * @param {integer} channel_widgets_id The channel_widgets_id that will receive the selected resource
	 * @param {integer} options_id The option identifier within the channel widget
	 * @param {Array} [resource_types] Optional array of the resource types that the media selector will show. Default is an empty array (all resource types)
	 *
	 */
	showImagesSelector: function(channel_widgets_id, options_id, resource_types)
	{
		var resource_types = (resource_types ? resource_types : $A());

		/**
		this.resourceValueTarget = target.down('div.current_value');
		this.resourceValueHTML = target.down('input.'+target.down('input.metaType').value);
		this.resourceValueHolder = target.down('div.current_item');
		*/

		resourceLibrary.searchTypes = resource_types;
		resourceLibrary.multiple = true;
				
		
		this.selected_option = {
			channel_widgets_id: channel_widgets_id,
			options_id: options_id
		};

		AS4Shell.getInstance().showLightbox({
			callback: this.onShowImagesSelector.bind(this),
			width: 415,
			height: 335
		});
	},

	/**
	 * Callback for the resource selector lightbox
	 */
	onShowImagesSelector: function()
	{
		var url = '/channel/resource_selector_lightbox';

		var params = {
			renderMode: 'lightbox',
			folder_id: this.channel_id
		};
		
		AS4Shell.getInstance().ajaxUpdate(url, params, 'add_panel_container', $A([this.onImagesSelectorShown.bind(this)]), {showIndicator: false});
		
		return	'<div id="add_panel_container">' +
					'<div class="centre" style="padding-top: 40%">' +
						'<img src="/app/common/assets/images/ajax-loader.gif" alt="Loading..>" width="24" height="24" /><br />Loading...' +
					'</div>' +
				'</div>';
	},

	/**
	 * Trigger a load of the resource selector once it is loaded into the lightbox!
	 */
	onImagesSelectorShown: function(transport, target)
	{
		resourceLibrary.channelId = AS4ResourceBrowser.MY_RESOURCES_PATH;

		// Bind lightbox interface
		if($('ml_search_terms'))
			$('ml_search_terms').observe('keyup', function(e) {
				resourceLibrary.searchTerms = $F(this);
				resourceLibrary.setResourcesPage(1, {refresh: false});
				resourceLibrary.startSearch.bind(resourceLibrary, $F(this)).delay(2); // Delay the search by 2 seconds, allowing typing to catch up
			});

		// Smart folder filters
		if($('smart_folder'))
		{
			$('smart_folder').observe('change', function(e) {
				resourceLibrary.setResourcesPage(1, {refresh: false});
				resourceLibrary.currentFolderId = $F(this);
				resourceLibrary.fetchResources();
			});

			
			// Default search should match the current selection
			resourceLibrary.currentFolderId = $F('smart_folder');
		}
		
		resourceLibrary.setResourcesPage(1, {refresh: false});
		resourceLibrary.searchTerms = '';

		// Run a search
		resourceLibrary.fetchResources();
	},
	
	/**
	 * Adds the selection of widgets from a lightbox to the
	 * current page
	 * 
	 */
	addSelectedWidgets: function()
	{
		var checked = $('available_widgets_form').getInputs('checkbox', 'selected_widgets[]').findAll(function(item) {
	 		return item.checked; 
		}).pluck("value");

		var url = '/channel/add_widgets_to_layout';
		var params = {
			channel_id: this.channel_id,
			widget_ids: checked.toJSON()
		};

		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onAddSelectedWidgets.bind(this)]));

		// Close the lightbox
		AS4Shell.getInstance().closeLightbox();
	},

	onAddSelectedWidgets: function(transport, target)
	{
		AS4Shell.getInstance().reload();	
	},

	/**
	 * Perform an AJAX copy of the channel's parent widget layout schema into this channel's
	 * widget schema
	 */
	copyParentChannelWidgetsLayout: function()
	{
		var url = '/channel/copy_parent_channel_widget_schema';
		var params = {
			channel_id: this.channel_id
		};

		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onCopyParentChannelWidgetsLayout.bind(this)]), {message: 'Copying...'});
	},

	/**
	 * Show the add widgets lightbox
	 */
	showAddWidgets: function()
	{
		var params = {
			renderMode: 'lightbox'
		}

		AS4Shell.getInstance().showLightbox({
			callback: this.onShowWidgetsSelector.bind(this),
			width: 415,
			height: 335
		});
	},

	/**
	 * Callback for the widget selector lightbox
	 */
	onShowWidgetsSelector: function()
	{
		var url = '/channel/widget_selector_lightbox';

		var params = {
			renderMode: 'lightbox'
		};
		
		AS4Shell.getInstance().ajaxUpdate(url, params, 'add_panel_container', $A([this.onResourceSelectorShown.bind(this)]), {showIndicator: false});
		
		return	'<div id="add_panel_container">' +
					'<div class="centre" style="padding-top: 40%">' +
						'<img src="/app/common/assets/images/ajax-loader.gif" alt="Loading..>" width="24" height="24" /><br />Loading...' +
					'</div>' +
				'</div>';
	},


	/**
	 * Perform an AJAX delete of the channel's widget layout schema
	 */
	deleteChannelWidgetsLayout: function()
	{
		if(!confirm('Are you sure you want to delete this channel\'s layout? This cannot be undone'))
			return;

		var url = '/channel/delete_channel_widget_schema';
		var params = {
			channel_id: this.channel_id
		};

		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onDeleteChannelWidgetsLayout.bind(this)]), {message: 'Deleting...'});
	},

	onDeleteChannelWidgetsLayout: function(transport, target)
	{
		this.onCopyParentChannelWidgetsLayout(transport, target);
	},

	onCopyParentChannelWidgetsLayout: function(transport, target)
	{
		if(transport.headerJSON.exception)
			return;

		AS4Shell.getInstance().reload();
	},

	/**
	 * Perform an AJAX save of a channel's widget layout schema
	 */
	saveChannelWidgetsLayout: function()
	{
			
		if(this.isSaving)
			return;

		var element = $(this.sortables_container);
		var serialized = $A();

		columns = this.sortables_container.select('.widget_column', '.widget_column_primary_editable', '.widget_column_secondary_editable', '.widget_column_tertiary_editable' );
		
		var count = 0;
		columns.each(function(column) {
				serialized.push(Sortable.sequence(column));
		});

		// Append any widgets in the header and footer columns
		schema = $H({
			columns: serialized,
			header: Sortable.sequence('widget_header'),
			footer: Sortable.sequence('widget_footer')
		});

		var url = '/channel/save_channel_widget_schema'; 

		var params = {
			channel_id: this.channel_id,
			schema: schema.toJSON()
		};

		this.isSaving = true;
		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onSaveChannelWidgetsLayoutComplete.bind(this)]), {message: 'Saving...'});
	},

	onSaveChannelWidgetsLayoutComplete: function(transport, target)
	{
		this.isSaving = false;
		this.is_dirty = false;
	},
	
	/**
	 * Perform an AJAX save of a channel_widget's options
	 *
	 * @param {Element(Form)} form The form element containing the channel_widget's options
	 */
	saveChannelWidgetOptions: function(strform, channel_widgets_id)
	{
		var form = $(strform);

		var url = '/channel/save_channel_widget_options';
		var opts = $H();
		var params = form.serialize();
	
		jQuery.noConflict();
		//channel_widgets_id = jQuery("#"+strform).children("#channel_widgets_id").attr("value");
			
		thisClass = this; //because this get overwritten by jQuery
		
		 jQuery.ajax({
		   type: "POST",
		   url: url,
		   data: params,
		   success: function(msg){
		   	
		   	if(msg != '')
		   	{
		     	var jsonT = eval('('+ msg +')');
		     	channel_widgets_id = jsonT.channel_widgets_id;
		     
		    	var url = '/channel/load_channel_widget';
				
				var params = {
					renderMode: 'update',
					channel_widgets_id: channel_widgets_id
				};

				element = $('channel_widgets_' + channel_widgets_id); // The widget's panel to be replaced

				AS4Shell.getInstance().ajaxUpdate(url, params, element, $A([thisClass.onReloadWidgetComplete.bind(thisClass)]));
		   	}
		   }
		 });

		
	//	AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onSaveChannelWidgetOptionsComplete.bind(this)]), {message: 'Saving...',	method: 'post'});
	},

	/**
	 * Ajax callback for the saveChannelWidgetOptions method
	 *
	 */
	onSaveChannelWidgetOptionsComplete: function(transport, target)
	{
		// Chained AJAX request to now go and load in the widget's new content!
		var url = '/channel/load_channel_widget';
		var channel_widgets_id = transport.headerJSON.channel_widgets_id;

		var params = {
			renderMode: 'update',
			channel_widgets_id: channel_widgets_id
		};

		element = $('channel_widgets_' + channel_widgets_id); // The widget's panel to be replaced

		AS4Shell.getInstance().ajaxUpdate(url, params, element, $A([this.onReloadWidgetComplete.bind(this)]));
	},

	/**
	 * Ajax callback to rebuild sortables onces a widget has been reloaded
	 *
	 */
	onReloadWidgetComplete: function(transport, target)
	{
		this._createSortables();
				
	},

	/**
	 * Remove a channels_widget from the page schema
	 *
	 * @param {integer} channel_widgets_id The id of the channel_widget to remove
	 */
	removeWidget: function(channel_widgets_id)
	{
		if(!confirm("Are you sure you want to remove this panel?\n\n (This cannot be undone)"))
			return;

		var url = '/channel/remove_channel_widget';

		var params = {
			channel_widgets_id: channel_widgets_id
		};

		AS4Shell.getInstance().ajaxUpdate(url, params, null, $A([this.onRemoveWidgetComplete.bind(this)]));
	},

	/**
	 * Callback for the removeWidget AJAX method
	 */
	onRemoveWidgetComplete: function(transport, target)
	{
		$('channel_widgets_' + transport.headerJSON.channel_widgets_id).remove();
		this._updateBlankColumns();
	},

	/**
	 * Toggle the display of a widget's control panel
	 *
	 * @param {integer} channel_widgets_id The id of the channel_widget to toggle
	 */
	toggleWidgetOptions: function(channel_widgets_id)
	{
		/*
		element = $('channel_widgets_' + channel_widgets_id_container); // The widget's content

		element.down('.toolbar').toggle();
		if(element.down('.widget_content'))
			element.down('.widget_content').toggle();
		element.down('form.options_panel').toggle();
		*/
		
		e = jQuery('#widget_options_' + channel_widgets_id + '_container');
		if(jQuery(e).is(":hidden"))
			jQuery(e).slideDown();
		else
			jQuery(e).slideUp();
			
		c = jQuery('#channel_widgets_' + channel_widgets_id + ' .widget_content');
		if(jQuery(c).is(":hidden"))
			jQuery(c).slideDown();
		else
			jQuery(c).slideUp();
	},

	
	/**
	 * Toggle the display of a widget's control panel
	 *
	 * @param {integer} channel_widgets_id The id of the channel_widget to toggle
	 */
	toggleOptionsTabs: function(active_tab,channel_widgets_id)
	{	
		if(active_tab != ''){
			e = jQuery('#widget_options_' + channel_widgets_id + '_container span');
				jQuery(e).hide();
				
				jQuery('#widget_options_' + channel_widgets_id + '_container .tab_container').children("a").each(function(i, ele)
					{
						if(jQuery(ele).attr("class") == 'active_options_tab'){
							jQuery(ele).attr("class","button");	
						}
					}); 
				
			n =	jQuery('#widget_options_' + channel_widgets_id + '_container #' + active_tab + '_button');
				jQuery(n).attr("class","active_options_tab");
				
				
			t = jQuery('#widget_options_' + channel_widgets_id + '_container span.' + active_tab);
				jQuery(t).show();	
		}
	},	
	
	/**
	 * Callback occurs when a Sortable drag causes a reordering
	 *
	 * @param {Element} container The sortable container
	 */
	onPanelDragged: function(container)
	{
		this._updateBlankColumns(container);
	},

	/**
	 * Callback occurs when a Sortable element is changed
	 * @param {Element} container The sortable container
	 */
	onPanelDropped: function(container)
	{
		this._updateBlankColumns(container);
		this.is_dirty = true;

		// Save the channel widgets layout
		this._createSortables();
		this.saveChannelWidgetsLayout();
	},

	_updateBlankColumns: function(container)
	{
		var container = $(container);

		sortables = this._getSortableElements();
		sortables.each(function(container) {
			// Update any empty containers
			if(container.select('.panel').length == 0)
			{
				if(!container.hasClassName('blank_column')) 
					container.addClassName('blank_column');
			}
			else 
				container.removeClassName('blank_column');
		});
	},

	/**
	 * Event triggered by a resource being selected in the 
	 *
	 * options can be 
	 * {
	 *  title: string Title of the selected resource
	 *  [type]: {string} One of 'resource' or 'folder'. Default is resource.
	 * }
	 * @param {integer} id Id of the resource to insert
	 * @param {Hash} type Type of the resource, either 'resource' or 'folder'. Default is 'resource'.
	 */

	onResourceSelected: function(id, options)
	{
		options = Object.extend({
			title: null,
			type: 'resource',
      event: null
		}, options || {});

    var event = options.event;

		if(resourceLibrary.multiple == true)
		{
			// We need to be selecting multiple images here and adding the names to the select box and the ids to the hidden field in a pipe seperated list.
			var opt = document.createElement('option');
      opt.text = options.title;
      opt.value = id;
		
      // Check that the image hasn't been added already
      if($("images_id_list").value.indexOf(id) == -1)
      {
        $("images_id_list").value = $("images_id_list").value + "|" + id;
        $("images_list").options.add(opt);

        if(event)
        {
          var element = $(event.element());
          element.src = '/app/common/assets/images/icons/14/selected.png';
        }
      }
      else
        alert("The selected image has already been added to the slide show.");
		}
		else
		{
			AS4Shell.getInstance().closeLightbox();
	
			// Request that server sends us the HTML to insert for this resource
			// Determine the element into which the selected resource will be set
			var cwid = this.selected_option.channel_widgets_id;
			var opid = this.selected_option.options_id;
	
			$('widget_options_' + cwid).down('input[id="resource_title_' + opid +'"]').value = (options.title || ''); 
			$('widget_options_' + cwid).down('input[id="options[' + opid +']"]').value = id; 
		}
	},
	
	/**
	* Remove the selected images from the slide show image list. Also remove them from the hidden id list
	**/
	removeOptions: function()
	{
		var i;
		var selectbox = $("images_list");

			
		for(i=selectbox.options.length-1;i>=0;i--)
		{
			if(selectbox.options[i].selected)
			{
				
				selectedId = selectbox.options[i].value;
				$("images_id_list").value = $("images_id_list").value.replace(eval("/"+selectedId+"/gi"),'');
				$("images_id_list").value = $("images_id_list").value.replace("||",'|');
				selectbox.remove(i);
			}
		}
	},
	
	/**
	*	Add new filter type 
	**/
	
	addFilterType: function(widget_id)
	{
    if(jQuery("#selected_resource_filters").val() == null)
      return;

    jQuery("#selected_resource_filters").val(jQuery("#filter_selector_list_" + widget_id).val().join("|"));
	},
	/**
	*	Add new filter type 
	**/
	
	addSelectedFolder: function()
	{
		var i;
		var selectbox = $("channel_selector_list");
		
		$("selected_channels").value = "";
		
		for(i=selectbox.options.length-1;i>=0;i--)
		{
			if(selectbox.options[i].selected)
			{
				
				selectedId = selectbox.options[i].value;
				if(selectedId > "0")
				{
					$("selected_channels").value = $("selected_channels").value+"|"+selectedId;
				}
				else
				{
					$("selected_channels").value = "|0";
					if(selectedId > "0")
						selectbox.remove(i);
				}
			}
		}
	}
});


AS4WidgetsLayoutEditor.WIDGETS_HEADER_COLUMN_INDEX = 10;
AS4WidgetsLayoutEditor.WIDGETS_FOOTER_COLUMN_INDEX = 20;
