/// <reference path="jquery-vsdoc.js" /> 

(function($)
{
	$.fn.addStaticItem = function(text, value)
	{
		/// <summary>
		/// Adds a static item to each matched SELECT list.
		/// </summary>
		/// <param name="text" type="String">
		/// The text of the item to add.
		/// </param>
		/// <param name="value" type="String">
		/// The value of the item to add.
		/// If not specified, an empty string is used.
		/// </param>
		/// <returns type="jQuery" />
	
		if ("string" === typeof(text) && 0 !== text.length)
		{
			if ("string" !== typeof(value)) { value = ""; }
			
			this.filter("select").each(function()
			{
				var opt = document.createElement("OPTION");
				opt.text = text;
				opt.value = value;
				this.options.add(opt, this.options.length);
			});
		}
		
		return this;
	};
	
	var clearListCore = function(list, staticItemCount)
	{
		if (list.options.length > staticItemCount)
		{
			var items = [];
			for (var index = 0; index < staticItemCount; index++)
			{
				items.push(list.options[index]);
			}

			list.innerHTML = "";

			for (var index = 0; index < staticItemCount; index++)
			{
				list.options.add(items[index], index);
			}
		}
	};

	$.fn.clearList = function(staticItemCount)
	{
		/// <summary>
		/// Removes all items from each matched SELECT list.
		/// </summary>
		/// <param name="staticItemCount" type="Number">
		/// The number of static items at the start of the list which should not be removed.
		/// If not specified, all items are removed.
		/// </param>
		/// <returns type="jQuery" />
	
		staticItemCount = parseInt(staticItemCount, 10);
		if (isNaN(staticItemCount) || 0 > staticItemCount) { staticItemCount = 0; }
		
		if (0 === staticItemCount)
		{
			this.filter("select").html("");
		}
		else
		{
			this.filter("select").each(function() { clearListCore(this, staticItemCount); });
		}
		
		return this;
	};
	
	var extractItemFactory = function(field)
	{
		if ("undefined" === typeof(field) || null === field) { return null; }
		if ("function" === typeof(field)) { return field; }
		return function(item) { return item[field] || ""; };
	};
	
	$.fn.loadList = function(data, options)
	{
		/// <summary>
		/// Loads the data into each matched SELECT list.
		/// </summary>
		/// <param name="data">
		/// The list of data to load.
		/// </param>
		/// <param name="options">
		/// The options which specify how the data is loaded:
		/// 
		/// 	staticItemCount:
		/// 	The number of static items at the start of the list to leave.
		/// 	If not specified, all items are removed before the data is loaded.
		/// 
		/// 	dataValueField:
		/// 	The name of the data-item property to use as the list item value,
		/// 	or a function which takes the data item and returns the list item value.
		/// 
		/// 	dataTextField:
		/// 	The name of the data-item property to use as the list item text,
		/// 	or a function which takes the data item and returns the list item text.
		/// 
		/// 	dataGroupField:
		/// 	The name of the data-item property to use as the list item group,
		/// 	or a function which takes the data item and returns the list item group.
		/// 
		/// 	onItemDataBound
		/// 	A function which is called after the list item is created, and before
		/// 	it is added to the list. The first parameter is the SELECT list object;
		/// 	the second contains the event data:
		/// 	
		/// 		Item:			The data item to which the list item is bound;
		/// 		Option:			The new list item;
		/// 		OptionGroup:	The OPTGROUP tag for the list item, if any;
		/// 
		/// </param>
		/// <returns type="jQuery" />
		
		var _options =
		{
			staticItemCount: 0,
			dataValueField: null,
			dataTextField: null,
			dataGroupField: null,
			onItemDataBound: null
		};
		
		$.extend(_options, options);
		
		var count = parseInt(_options.staticItemCount, 10);
		if (isNaN(count) || 0 > count) { count = 0; }
		_options.staticItemCount = count;
		
		var list = this.filter("select");
		if (0 === _options.staticItemCount)
		{
			list.html("");
		}
		else
		{
			list.each(function() { clearListCore(this, _options.staticItemCount); });
		}
		
		if (data && data.length)
		{
			_options.dataValueField = extractItemFactory(_options.dataValueField);
			_options.dataTextField = extractItemFactory(_options.dataTextField);
			_options.dataGroupField = extractItemFactory(_options.dataGroupField);
			
			var haveDataBound = ("function" === typeof(_options.onItemDataBound));
			var isIE = jQuery.browser.msie; // TODO: Depracated in jQuery 1.3
			
			list.each(function()
			{
				var optGroup = null;
				var opt, item, value, text, group, oldGroup;
				for (var index = 0; index < data.length; index++)
				{
					item = data[index];
					
					if (null != _options.dataGroupField)
					{
						group = _options.dataGroupField(item);
						if ("string" === typeof(group) && 0 !== group.length && group !== oldGroup)
						{
							optGroup = document.createElement("OPTGROUP");
							optGroup.label = group;
							this.appendChild(optGroup);
							oldGroup = group;
						}
					}
					
					opt = document.createElement("OPTION");
					opt.value = _options.dataValueField(item);
					opt.text = _options.dataTextField(item);
					
					if (haveDataBound) 
					{
						_options.onItemDataBound(this, 
						{
							Item: item,
							Option: opt,
							OptionGroup: optGroup
						});
					}
					
					if (null === optGroup || isIE)
					{
						this.options.add(opt, this.options.length);
					}
					else
					{
						optGroup.appendChild(opt);
					}
				}
			});
		}
		
		return this;
	};
	
})(jQuery);
