Type.registerNamespace("Trinet.UI");

Trinet.UI.ListView = function()
{
	Trinet.UI.ListView.initializeBase(this);
	
	this._itemPlaceholderId = "itemPlaceholder";
	this._groupPlaceholderId = "groupPlaceholder";
	
	this._layoutTemplate = "";
	this._itemTemplate = "";
	this._itemSeparatorTemplate = "";
	
	this._groupItemCount = 1;
	this._groupTemplate = "";
	this._groupSeparatorTemplate = "";
	
	this._itemCallback = null;
};

Trinet.UI.ListView.prototype =
{
	get_itemCallback: function()
	{
		if (arguments.length !== 0) { throw Error.parameterCount(); }
		return this._itemCallback;
	},
	set_itemCallback: function(value)
	{
		/// <param name="value" type="Function" mayBeNull="true"></param>
		var e = Function._validateParams(arguments, [{ name: "value", type: Function, mayBeNull: true }]);
		if (e) { throw e; }
		
		this._itemCallback = value;
	},
	
	get_itemPlaceholderId: function()
	{
		if (arguments.length !== 0) { throw Error.parameterCount(); }
		return this._itemPlaceholderId;
	},
	set_itemPlaceholderId: function(value)
	{
		/// <param name="value" type="String" mayBeNull="true"></param>
		var e = Function._validateParams(arguments, [{ name: "value", type: String, mayBeNull: true }]);
		if (e) { throw e; }
		
		if ("string" !== typeof(value) || 0 === value.length) { value = "itemPlaceholder"; }
		this._itemPlaceholderId = value;
	},
	
	get_groupPlaceholderId: function()
	{
		if (arguments.length !== 0) { throw Error.parameterCount(); }
		return this._groupPlaceholderId;
	},
	set_groupPlaceholderId: function(value)
	{
		/// <param name="value" type="String" mayBeNull="true"></param>
		var e = Function._validateParams(arguments, [{ name: "value", type: String, mayBeNull: true }]);
		if (e) { throw e; }
		
		if ("string" !== typeof(value) || 0 === value.length) { value = "groupPlaceholder"; }
		this._groupPlaceholderId = value;
	},
	
	get_layoutTemplate: function()
	{
		if (arguments.length !== 0) { throw Error.parameterCount(); }
		return this._layoutTemplate;
	},
	set_layoutTemplate: function(value)
	{
		/// <param name="value" type="String" mayBeNull="true"></param>
		var e = Function._validateParams(arguments, [{ name: "value", type: String, mayBeNull: true }]);
		if (e) { throw e; }
		
		this._layoutTemplate = value;
	},
	
	get_itemTemplate: function()
	{
		if (arguments.length !== 0) { throw Error.parameterCount(); }
		return this._itemTemplate;
	},
	set_itemTemplate: function(value)
	{
		/// <param name="value" type="String" mayBeNull="true"></param>
		var e = Function._validateParams(arguments, [{ name: "value", type: String, mayBeNull: true }]);
		if (e) { throw e; }
		
		this._itemTemplate = value;
	},
	
	get_itemSeparatorTemplate: function()
	{
		if (arguments.length !== 0) { throw Error.parameterCount(); }
		return this._itemSeparatorTemplate;
	},
	set_itemSeparatorTemplate: function(value)
	{
		/// <param name="value" type="String" mayBeNull="true"></param>
		var e = Function._validateParams(arguments, [{ name: "value", type: String, mayBeNull: true }]);
		if (e) { throw e; }
		
		this._itemSeparatorTemplate = value;
	},
	
	get_groupTemplate: function()
	{
		if (arguments.length !== 0) { throw Error.parameterCount(); }
		return this._groupTemplate;
	},
	set_groupTemplate: function(value)
	{
		/// <param name="value" type="String" mayBeNull="true"></param>
		var e = Function._validateParams(arguments, [{ name: "value", type: String, mayBeNull: true }]);
		if (e) { throw e; }
		
		this._groupTemplate = value;
	},
	
	get_groupSeparatorTemplate: function()
	{
		if (arguments.length !== 0) { throw Error.parameterCount(); }
		return this._groupSeparatorTemplate;
	},
	set_groupSeparatorTemplate: function(value)
	{
		/// <param name="value" type="String" mayBeNull="true"></param>
		var e = Function._validateParams(arguments, [{ name: "value", type: String, mayBeNull: true }]);
		if (e) { throw e; }
		
		this._groupSeparatorTemplate = value;
	},
	
	get_groupItemCount: function()
	{
		if (arguments.length !== 0) { throw Error.parameterCount(); }
		return this._groupItemCount;
	},
	set_groupItemCount: function(value)
	{
		/// <param name="value" type="Number" integer="true"></param>
		var e = Function._validateParams(arguments, [{ name: "value", type: Number, integer: true }]);
		if (e) { throw e; }
		
		if (1 > value) { throw Error.argumentOutOfRange("value", value, "groupItemCount cannot be less than 1."); }
		
		this._groupItemCount = value;
	},
	
	bindElement: function(domElement, data, itemCallback)
	{
		/// <param name="domElement" domElement="true"></param>
		/// <param name="data" type="Array" mayBeNull="true"></param>
		/// <param name="itemCallback" type="Function" mayBeNull="true" optional="true"></param>
		var e = Function._validateParams(arguments, 
		[
			{ name: "domElement", domElement: true },
			{ name: "data", type: Array, mayBeNull: true },
			{ name: "itemCallback", type: Function, mayBeNull: true, optional: true }
		]);
		if (e) { throw e; }
		
		var text = this.bind(data, itemCallback);
		domElement.innerHTML = text;
	},
	
	bind: function(data, itemCallback)
	{
		/// <param name="data" type="Array" mayBeNull="true"></param>
		/// <param name="itemCallback" type="Function" mayBeNull="true" optional="true"></param>
		var e = Function._validateParams(arguments, 
		[
			{ name: "data", type: Array, mayBeNull: true },
			{ name: "itemCallback", type: Function, mayBeNull: true, optional: true }
		]);
		if (e) { throw e; }
		
		if ("undefined" == typeof(itemCallback)) { itemCallback = this.get_itemCallback(); }
		return this._generate(data, itemCallback);
	},
	
	_generate: function(data, itemCallback)
	{
		var template = this.get_layoutTemplate();
		if ("string" !== typeof(template) || 0 === template.length) { return ""; }
		
		var groupTemplate = this.get_groupTemplate();
		if ("string" === typeof(groupTemplate) && 0 !== groupTemplate.length)
		{
			var groupItemCount = this.get_groupItemCount();
			var groupPattern = Trinet.UI.ListView._createRequiredTemplatePattern(template, this.get_groupPlaceholderId());
			var text = this._createItemsInGroups(data, itemCallback, groupItemCount, groupTemplate);
			return template.replace(groupPattern, text);
		}
		
		var text = this._createItems(data, itemCallback, template);
		return text;
	},
	
	_createItemsInGroups: function(data, itemCallback, groupItemCount, template)
	{
		var itemPattern = Trinet.UI.ListView._createRequiredTemplatePattern(template, this.get_itemPlaceholderId());
		
		var result = "";
		if (data && 0 !== data.length)
		{
			var itemTemplate = this.get_itemTemplate();
			var separator = this.get_itemSeparatorTemplate();
			
			var groupSeparator = this.get_groupSeparatorTemplate();
			if ("string" !== typeof(groupSeparator) || 0 === groupSeparator.length) { groupSeparator = null; }
			
			var text;
			var builder = new Sys.StringBuilder();
			for (var i = 0; i < data.length; i += groupItemCount)
			{
				if (0 !== i && null !== groupSeparator) { builder.append(groupSeparator); }
				text = this._createItemsCore(data, itemCallback, itemTemplate, separator, i, groupItemCount);
				builder.append(template.replace(itemPattern, text));
			}
			
			result = builder.toString();
		}
		
		return result;
	},
	
	_createItems: function(data, itemCallback, template)
	{
		var itemPattern = Trinet.UI.ListView._createRequiredTemplatePattern(template, this.get_itemPlaceholderId());
		var itemTemplate = this.get_itemTemplate();
		var separator = this.get_itemSeparatorTemplate();
		var length = (data) ? data.length : 0;
		var text = this._createItemsCore(data, itemCallback, itemTemplate, separator, 0, length);
		return template.replace(itemPattern, text);
	},
	
	_createItemsCore: function(data, itemCallback, template, separator, startIndex, length)
	{
		if (isNaN(startIndex) || 0 > startIndex) { startIndex = 0; }
		if (isNaN(length)) { length = 0; }
		
		var result = "";
		if (data && 0 !== data.length)
		{
			var item = null;
			var matchEvaluator;
			if ("function" === typeof(itemCallback))
			{
				matchEvaluator = function(word)
				{
					var memberName = word.slice(1);
					return itemCallback(memberName, item);
				};
			}
			else
			{
				matchEvaluator = function(word)
				{
					var memberName = word.slice(1);
					return item[memberName];
				};
			}
			
			var text;
			var pattern = /#\w+/g;
			if (startIndex + length > data.length) { length = data.length - startIndex; }
			if ("string" !== typeof(separator) || 0 === separator.length) { separator = null; }
			
			var builder = new Sys.StringBuilder();
			for (var index = 0; index < length; index++)
			{
				if (0 !== index && null !== separator) { builder.append(separator); }
				
				item = data[startIndex + index];
				text = template.replace(pattern, matchEvaluator);
				builder.append(text);
			}
			
			result = builder.toString();
		}
		
		return result;
	}
};

Trinet.UI.ListView._createRequiredTemplatePattern = function(template, controlId)
{
	var result = new RegExp("<([a-zA-Z][a-zA-Z0-9]+)\\s+id=([\\\"\\\'])" + controlId + "\\2[^>]*>[.\\s]*</\\1>", "g");
	if (!result.test(template))
	{
		result = new RegExp("<([a-zA-Z][a-zA-Z0-9]+)\\s+id=([\\\"\\\'])" + controlId + "\\2[^>]*/>", "g");
		if (!result.test(template))
		{
			throw Error.invalidOperation("The template must contain a control with the ID \"" + controlId + "\".\n\nTemplate:\n" + template);
		}
	}
	
	return result;
};

Trinet.UI.ListView.loadTemplate = function(domElement)
{
	/// <param name="domElement" domElement="true" optional="true" mayBeNull="true"></param>
	var e = Function._validateParams(arguments, [{ name: "domElement", domElement: true, mayBeNull: true }]);
	if (e) { throw e; }
	
	if (null === domElement) { return ""; }
	
	var result = domElement.innerHTML;
	if ("string" !== typeof(result) || 0 === result.length) { return ""; }
	
	result = result.trim();
	if (7 < result.length && result.startsWith("<!--") && result.endsWith("-->"))
	{
		result = result.substr(4, result.length - 7);
	}
	
	return result;
};

Trinet.UI.ListView.registerClass("Trinet.UI.ListView");