﻿(function($)
{
	//********************************************	
	//********************************************
	// utility to prevent event default actions
	//********************************************
	var stopEventDefaults = function(e)
	{
		if (e && e.preventDefault)
		{
			e.preventDefault();
		}
		else
		{
			window.event.returnValue = false;
		}
		
		return false;
	};
	
	//********************************************	
	//********************************************
	// wrapper for select and its options
	//********************************************
	var SelectStore = function(select)
	{
		var getOption = function(index)
		{
			return select.children('option:eq('+index+')');
		};
		
		var getItems = function()
		{
			var items = [];
			
			$.each(select.children('option'), function()
			{
				var option = $(this);
				var item = convertOptionToItem(option);
				items.push(item);
			});
			
			return items;
		};
		
		var getItem = function(index)
		{
			var option = getOption(index);
			return convertOptionToItem(option);
		};
		
		var convertOptionToItem = function(option)
		{
			return {
				text: option.text(),
				value: option.val(),
				selected: option.is(':selected')
			};
		};
		
		var markItemSelected = function(index, setSelected)
		{
			var option = getOption(index);
			if (setSelected)
			{
				option.attr('selected','selected');
			}
			else
			{
				option.removeAttr('selected');
			}
		};

		var clearSelection = function()
		{
			select.children('option').removeAttr('selected');
		};
		
		return {
			getItems: getItems,
			getItem: getItem,
			selectItem: function(index)
			{
				markItemSelected(index, true);
			},
			unselectItem: function(index)
			{
				markItemSelected(index, false);
			},
			clearSelection: clearSelection
		};
	};

	//********************************************	
	//********************************************
	// Multiple Selection List
	//********************************************	
	var MultipleSelectionList = function(select, config)
	{		
		// ui elements
		var container = null;
		var dropButton = null;
		var title = null;
		var snag = null;
		var snagContent = null;
		var selectedItems = null;
		
		// data 
		var selectStore = null;
		
		// consts
		var selectedItemIndexRefAttr = 'indexRef';
		var selectedItemInSelectionListClass = 'active';
		
		var options = {
			title: 'Select from the list',
			containerClass: '',
			columns: 3,
			expanded: false,
			debug: false,
			template: '<div>'
						+'<a href="#" title="" class="buttonDrop">+</a>'
						+'<div class="headBlock"><span class="title"></span><span class="selectedItems"></span></div>'
						+'<div><div class="snag" style="display:none;"><div class="point"></div><div class="snagContent"></div></div></div>'
					+'</div>'
		};		
		
		//******************
		// init helpers		
		//******************
		
		var init = function()
		{
			options = $.extend(true, options, config);
			
			selectStore = new SelectStore(select);
			
			if (!options.debug) 
			{
				select.hide();
			}
			select.after(options.template);
			container = select.next();
			
			initElements(config);
			initEventHandlers();
			
			fillItems();
						
			// apply ui options
			var titleText = select.attr('title') || options.title;
			title.text(titleText);
			container.addClass(options.containerClass);
			
			if (options.expanded)
			{
				expand();
			}
			else
			{
				collapse();
			}
		};

		var initElements = function(config)
		{
			dropButton = container.find('.buttonDrop');
			title = container.find('.headBlock .title');
			selectedItems = container.find('.headBlock .selectedItems');

			snag = container.find('.snag');
			snagContent = container.find('.snagContent');
		};
	
		var initEventHandlers = function()
		{
			dropButton.click(function(e)
			{
				if (snag.is(':hidden'))
				{
					expand();
				}
				else
				{				
					collapse();
				}							
				
				return stopEventDefaults(e);
			});	
		};
	
		//******************
		// data helpers		
		//******************
		
		var fillItems = function()
		{
			var items = selectStore.getItems();
							
			fillSelectionList(items);
			fillSelectedItems(items);			
		};		
	
		var toggleItemSelection = function(index)
		{
			var item = selectStore.getItem(index);
			if (item.selected)
			{
				removeSelectedItem(index);
				markItemInSelectionList(index, false);
				selectStore.unselectItem(index);
			}
			else
			{
				addSelectedItem(item.text, index);
				markItemInSelectionList(index, true);
				selectStore.selectItem(index);
			}
		}
		//******************
		// ui helpers		
		//******************
	
		var expand = function()
		{
		    dropButton.addClass('openDrop');
			if ($.browser.msie)
			{
				snag.show('fast');
			}
			else
			{
				snag.slideDown('fast');		
			}		
		};
	
		var collapse = function()
		{
			dropButton.removeClass('openDrop');
			if ($.browser.msie)
			{
				snag.hide('fast');
			}
			else
			{
				snag.slideUp('fast');
			}
		};
	
		//---
		
		var fillSelectedItems = function(items)
		{
			//clean container
			selectedItems.empty();
						
			$.each(items, function(index, item)
			{				
				if (item.selected)
				{				
					addSelectedItem(item.text, index);
				}
			});		
		};
	
		var addSelectedItem = function(text, index)
		{		 
			var selectedItem = createSelectedItem(text, index);
			if (selectedItems.children('a').length > 0)
			{
				selectedItems.append('<span>, </span>');
			}
			selectedItems.append(selectedItem);	
		};
	
		var createSelectedItem = function(text, index)
		{						
			return $('<a href="#"></a>')
						.text(text)
						.attr(selectedItemIndexRefAttr, index)
						.click(function(e)
						{							
							//get index of selected item
							var index = $(this).attr(selectedItemIndexRefAttr);
							
							toggleItemSelection(index);
							return stopEventDefaults(e);
						});		
		};
		
		var removeSelectedItem = function(index)
		{
			//find selected item link
			var a = selectedItems.children("a["+selectedItemIndexRefAttr+"='"+index+"']");
			
			//get position in list of selected items links
			var pos = selectedItems.children('a').index(a[0]);
							
			//remove span with separator which follows the link
			if (pos == 0)
			{
				a.next('span').remove();
			}
			else
			{
				a.prev('span').remove();
			}
			//remove the link itself
			a.remove();
		};
	
		//---
		
		var fillSelectionList = function(items)
		{
			//clean container			
			snagContent.empty();
						
			var itemsPerColumn = Math.ceil(items.length / options.columns);		
			
			for (i=0; i<options.columns; i++)
			{
				var column = createColumn(items, i*itemsPerColumn, itemsPerColumn);
				snagContent.append(column);
			}
		};
	
		var createColumn = function(items, start, count)
		{
			var column = $('<div class="colm"></div>');
					
			for (var i=start; (i<start+count) && (i<items.length); i++)
			{
				var line = createLine(items[i]);
				column.append(line);
			}
			
			return column;
		};
	
		var createLine = function(item)
		{
			var link = $('<a href="#"></a>')
				.text(item.text)
				.click(function(e)
				{
					var index = snagContent.find('a').index(this);
					
					toggleItemSelection(index);					
					
					return stopEventDefaults(e);
				});
				
			if (item.selected)
			{
				link.addClass(selectedItemInSelectionListClass);
			}
			
			return $('<p></p>').append(link);
		};								
		
		var markItemInSelectionList = function(index, markSelected)
		{
			var link = snagContent.find('a:eq('+index+')');
			if (markSelected)
			{
				link.addClass(selectedItemInSelectionListClass);
			}
			else
			{
				link.removeClass(selectedItemInSelectionListClass);
			}
		};
		
		//***************************
		// prepare object for use
		//***************************		
		init();
	};
	
	//*********************************************************************************************

	$.fn.multiSelection = function(config)
	{		
		for(var i=0; i<this.length; i++)
		{
			var el = this[i];
			if (el.tagName.toLowerCase() != 'select')
			{
				continue;
			}
			
			var select = $(el);
			
			if (!select.attr('multiple'))
			{
				continue;
			}
			
			new MultipleSelectionList(select, config);
		}		
	}
})(jQuery);