/*
 * Some extensions to this methodology.
 *
 *  1. You'll notice that in the ajax requests, we typically parse the request data for HTML content explictly.
 *  	a. We do this because of the draw methods, which sometimes return scripts.
 *  	b. Usually we don't want to re-download scripts that that have already been included.
 *  	c. EXCEPTION: There are various scripts that bind actions to the HTML we've just throw back. We *need* these!
 *
 * 	SOLUTION:
 * 		i. We need to segregate the scripts we return into static and dynamic scripts.
 * 		ii. Static scripts are the includes. These only need to be downloaded once | modifyProduct.js
 * 		iii. Dynamic scripts are things such as event bindings. These need their own place | jQuery('#some-div-i-just-generated').click(function(){}) *
 * 		iv. We need a methodology backend and frontend for *determining which scripts are static* *which ones are dynamic*.
 * 		v. Our frontend javascript needs to consistently check for dynamic scripts and make sure it attaches them, as well as content.
 *
 *  IMPLEMENTATION:
 *  	1. Dynamic scripts have the attribute 'defer' (HTML 4 / XHTML standard - one of few attributes that script tags accept).
 *  	2. Any ajax requests that generate content, should be conscious of this and secondarily parse 'non-defered' scripts (typically by adding them to the dom).
 *
 *  	1. Provide a core JS function: Shout.parseHTML('selector').
 *  		i. It returns HTML matching the given selector (to curious functions that want to append this request data somewhere/manipulate it/whatever).
 *  		ii. It automatically looks for defered scripts and appends them appropriately.
 *  		iii. It does the same with style tags maybe?
 *
 */
(function(jQuery)
{
ShoutBrowser = function(name)
{
	if(!ShoutBrowser.browsers[name])
	{
		ShoutBrowser.browsers[name] = ShoutBrowserInstance(name);
	}

	return ShoutBrowser.browsers[name];
};

ShoutBrowser.browsers = {};

window.ShoutBrowser = ShoutBrowser;

var ShoutBrowserInstance = function (name)	{

return {
	params:
	{
		treeName: name,
		currentNodes:[],
		filterText:'',
		restrict:''
	},

	$element: null,
	$$treeElement: null,
	callback: null,
	queue:{},
	minChars:3,

	uiElements: {
		selectors: {
			clearButton:'.treeview-trash',
			helpButton: '.treeview-help',
			expandAll: '.treeview-expand',
			collapseAll: '.treeview-collapse',
			filter:'input[name=treeview-filter]'
		},
		elements : {
			$clearButton:null,
			$helpButton:null,
			$expandAll:null,
			$collapseAll:null,
			$filter:null
		}
	},

	init: function($content)
	{
		var self = this;

		if(!$content)
		{
			self.$element = jQuery(self.getId());
		}
		else
		{
			self.$element = jQuery($content);
		}

		self.uiElements.elements = {
			$clearButton: self.$element.find(self.uiElements.selectors.clearButton),
			$helpButton: self.$element.find(self.uiElements.selectors.helpButton),
			$expandAll: self.$element.find(self.uiElements.selectors.expandAll),
			$collapseAll: self.$element.find(self.uiElements.selectors.collapseAll),
			$clearButton: self.$element.find(self.uiElements.selectors.clearButton),
			$filter: self.$element.find(self.uiElements.selectors.filter)
		};

		self.uiElements.elements.$filter.keyup(function(event)
		{
			self.filter(jQuery(this),event);
		})
		.qtip({
			content: 'Press enter to <strong>search</strong>.',
			position: {
				corner: {
					tooltip: 'bottomLeft',
					target: 'topRight'
				}
			},
			show: {
				when: { event: 'focus' }
			},
			hide:{
				when: { event: 'unfocus' }
			},
			style : {
				width:200,
				background: '#FFFFFF',
				tip: 'bottomLeft',
				border: {
					width: 7,
					radius: 5,
					color: '#B7BEC8'
				}
			}
		});

		self.uiElements.elements.$clearButton.click(function(event)
		{
			self.uiElements.elements.$filter.val('');
			self.filterBrowser({filterText:''});
			self.$element.trigger('onTreeReset',{});
			jQuery(this).hide();

		});

		self.uiElements.elements.$expandAll.click(function(event)
		{
			self.$$treeElement.Tree.expandAll();
		});


		self.uiElements.elements.$collapseAll.click(function(event)
		{
			self.$$treeElement.Tree.collapseAll();
		});

		self.$element.unbind('onTreeFilter');

		self.$element
		.bind('onTreeFilter',function(evt,evtData)
		{
			// Make the clear button available after filtering.
			self.uiElements.elements.$clearButton.show('slow');
			self.filterBrowser(evtData);
		});
	},

	// TODO Take a look at this and drawSecurity labels.
	// I think there is room for unification.
	drawPathLabels: function(data, $field)
	{
		var self = this;

		var $field = jQuery($field);

		var result = [];

		var params = {nodes:{}};

		jQuery.each(data, function()
		{
			if(this.node)
			{
				params.nodes[this.node.id] = this.node.id;
			}
		});


		if(this.params)
		{
			this.params = jQuery.extend(this.params,params);
		}

		var searchObj =
		{
			module :'Core',
			submodule :'NavigationTreeBuilder',
			mode : 'drawPathLabels',
			action: Shout.configuration.action
		};

		if(this.params)
		{
			searchObj = jQuery.extend(searchObj, Shout.flattenFields(this.params,'actionParams') );
		}

		jQuery.post(
			Shout.configuration.location,
			searchObj,
			function(data)
			{
				$field.html(jQuery(data).filter('.sui-field-summary').html());
			},'html'
		);
	},

	configure: function(params)
	{
		if(this.params)
		{
			this.params = jQuery.extend(this.params,params);
		}
		else
		{
			this.params = params;
		}
	},

	/**
	 * @param triggerOn The element on which to trigger the onBrowseConfirm action. Interested parties should listen for the event on this element.
	 * @param params Additional parameters passed over to PHP.
	 */
	drawBrowser: function(params, triggerOn)
	{
		var self = this;

		this.configure(params);

		// Clear any old search filter text.
		delete this.params.filterText;

		var searchObj =
		{
			module :'Core',
			submodule :'NavigationTreeBuilder',
			mode : 'drawBrowser',
			treeName: 'treeview',
			action: Shout.configuration.action
		};

		if(this.params)
		{
			searchObj = jQuery.extend(searchObj, Shout.flattenFields(this.params,'actionParams'));
		}

		if(self.$element)
		{
			self.$element.remove();
		}

		jQuery.post(
			Shout.configuration.location,
			searchObj,
			function(data)
			{
				var $data = jQuery(data);

				var $content = $data.filter('div');

				var $script = $data.filter('script[defer]');

				self.init($content);

				self.$element.dialog(
				{
					bgiframe: true,
					resizable: true,
					width:600,
					height:500,
					modal: true,
					title:'Select a Placement for This Item',
					overlay:
					{
						backgroundColor: '#000',
						opacity: 0.5
					},

					buttons:
					{
						Cancel: function()
						{
							self.$element.dialog('close');
						},
						'Okay': function()
						{
							var selection = self.getSelection();

							if(selection)
							{
								jQuery(triggerOn).trigger('onBrowseConfirm',selection);
							}

							self.$element.dialog('close');
						}

					}

				});

				jQuery(document).append($script);

				self.initTree();

			}, "html"
		);

	},

	getSelection: function()
	{
		var self = this;

		var selection = {};

		this.$element.find(' input:checked').each(function(i)
		{
			selection[i] = jQuery.evalJSON( jQuery(this).val() );
		});

		return selection;
	},

	getPlacementParams: function(fieldSelector)
	{
		var existingPlacement = jQuery(fieldSelector).val();

		var params = { currentParent: null };

        if(existingPlacement)
        {
            // Format existing placement information into a value the browser RPC understands.

            existingPlacement = jQuery.evalJSON(existingPlacement);

            var currentParents = {};

            jQuery.each(existingPlacement, function()
            {
                if(this && this.node)
                {
                    currentParents[this.node.id] = this.node.id;
                }
                else
                {
                    currentParents[this] = this;
                }
            });

            params.currentParents = jQuery.extend(params.currentParents, currentParents);
        }

        return params;
	},

	filterBrowser: function(filterData)
	{
		var self = this;

		searchObj =
		{
			module :'NavigationTreeBuilder',
			mode : 'filterTree',
			action: Shout.configuration.action
		};

		// Set our search criteria
		this.params.filterText = filterData.filterText;

		// Merge data into our ajax post object, flatten parameters for PHP.
		searchObj = jQuery.extend(searchObj,Shout.flattenFields(this.params,'actionParams'));

		if(this.params.filterText.length < 0)
		{
			searchObj.mode = 'drawBrowser';
		}

		jQuery.post(
			Shout.configuration.location,
			searchObj,

			function(data)
			{
				var $dataList = jQuery('<div>');

				var $data = jQuery(data);


				// Filter out the content element in our data which also contains
				// script and link elements.
				var $newTree = $data.filter(self.getId()).find('.sui-tree-root');

				$newScripts = $data.filter('script[defer]');

				// Hide the tree until it's finished initalization.
				$newTree.hide("slow");
				self.$element.find(' .sui-tree-root').replaceWith($newTree);
				self.initTree();
				$newTree.show();

				jQuery('body').append($newScripts);

			} , "html" );
	},

	filter: function($formElement, event)
	{
		$formElement = jQuery($formElement);

		var self = this;

		// 'Quantize' filter requests into xxx ms intervals, if additional filter calls are made, cancel the
		// previous one and only proceed with the latest.
		if(this.filterTimeout)
		{
			clearTimeout(this.filterTimeout);
		}

		queryString = $formElement.val();

		if(queryString.length > 0)
		{
//			self.setMessage($formElement,'Press enter to search.');
		}
		else
		{
//			self.setMessage($formElement,'Reset the Search.');
		}

		if(event.keyCode == 13)
		{
			data = {};
			data.filterText = queryString;
			self.$element.trigger('onTreeFilter',data);
			self.clearMessage($formElement);
		};
	},

	clearMessage: function($formElement)
	{
		$formElement.qtip('hide');
	},

	getId: function()
	{
		return '#' + this.params.treeName;
	},

	initTree: function()
	{
		var self = this;

		if(self.$element)
		{
			self.$$treeElement = Shout(this.getId() + ' .sui-tree-root ').tree('li',' > .content');
		}

		// Monkeypatch the getBranch function inside of tree. It is intended for monkeypatching.
		// fn is a post ajax callback function.
		self.$$treeElement.Tree.getBranch = function($treeElement,fn, all)
		{
			self.getBranch($treeElement,fn,all);
		}
	},

	getBranch: function($treeElement,fn,all)
	{
		var self = this;

		var params = this.params;

		all = all ? 1 : 0;

		params.nodeId = $treeElement.find('> input.sui-query').val();
		params.all = all;

		var searchObj =
		{
			module :'Core',
			submodule :'NavigationTreeBuilder',
			mode : 'getBranch',
			action: Shout.configuration.action
		}

		if(this.params)
		{
			searchObj = jQuery.extend(searchObj, Shout.flattenFields(params,'actionParams'));
		}

		jQuery.post(
			Shout.configuration.location,
			searchObj,
			function(data)
			{
				var $data = jQuery(data);

				$newItems = $data.filter('ul');

				$newScripts = $data.filter('script[defer]');

				$treeElement.find(' > ul').replaceWith($newItems);
				$treeElement.find(' > ul').addClass('sui-tree-nested');
				self.$$treeElement.Tree.make($treeElement.find('li'));
				$treeElement.find(' > input.sui-query').remove();

				jQuery('body').append($newScripts);
				// Run the post callback.
				fn();
			}
		);
	},

	locate: function()
	{
		jQuery.each(this.params.currentNodes,function()
		{
			var $item = jQuery("input[value*='node\":{\"id\":\""+parseInt(this)+"\"']");
			$item.closest('.sui-tree-nested').siblings('.sui-tree-toggle').click();
			$item.siblings('.sui-tree-text').effect("highlight", {}, 3000);

		});
	}
}};

})(jQuery);





