var DEBUG = false;

function Loader()
{
	this.load = function(thisObject, callback)
	{		
		callback.call(thisObject);
	}
}

function SequencialLoader(loaders)
{
	this.loaders = loaders;
	this.loaderIndex = 0;

	this.load = function(thisObject, callback)
	{
		this.thisObject = thisObject;
		this.callback = callback;
		
		this.internalCallBack();
	}	
	
	this.internalCallBack = function()
	{
		// If is the last loader, i call the principal callback
		if (this.loaderIndex == this.loaders.length - 1)
		{
			this.loaders[this.loaderIndex].load(this.thisObject, this.callback);			
		}
		// If not, i call the next loader using myself as callback, and increment the LoaderIndex
		else if (this.loaderIndex < this.loaders.length)
		{
			this.loaderIndex++;
			this.loaders[this.loaderIndex-1].load(this, this.internalCallBack);
		}	
	}
}

function URLArrayLoader(url, array, params)
{
	this.load = function(thisObject, callback)
	{
		this.loadIntern(thisObject, callback, array, params);
	}
	
	this.loadIntern = function(thisObject, callback, result, params)
	{
		var myAjax = new Ajax(
		url, 
		{
			method: 'get', 
			parameters: params, 
			onComplete: function(res)
			{
				try
				{
					var response = myAjax.response.text;
					var time = new Date().getTime();
					eval(response);
					if (DEBUG)
					{
						alert( url + ": " + (new Date().getTime()-time)/1000 );
					}
					callback.call(thisObject);
				}
				catch (e)
				{
					throw e;
				}
			}
		}).request();
	}
}

var templateCache = new Object();

Template.fromFunction = function(func)
{
	var template = new Template();
	template.parse = func;
	return template;
}

Template.fromDiv = function(divName)
{
	if (templateCache[divName])
	{
		return templateCache[divName];
	}
	var template = new Template();
	var div = document.getElementById(divName);
	var source = div.innerHTML;
	source = source.replace(/[\n\r]/g,"");
	while (source.indexOf('&lt;') >= 0)
	{
		source = source.replace("&lt;", "<");
	}
	while (source.indexOf('&gt;') >= 0)
	{
		source = source.replace("&gt;", ">");
	}	
	template.source = source;	
	templateCache[divName] = template;	
	return template;
}

Template.fromURL = function(url, loaded, params)
{
	var myAjax = new Ajax(
	url, 
	{
		method: 'get', 
		parameters: params, 
		onComplete: function(res)
		{
			try
			{
				var returnValue = new Template();
				var response = myAjax.response.text;	
				
				returnValue.source = response.replace(/[\n\r]/g,"");				
				if (loaded)
				{
					loaded.call(returnValue, params);
				}
				
			}
			catch (e)
			{
				if (e.message)
				{
					alert(e.message);
				}
				else if (e.description)
				{
					alert(e.description);
				}
			}
		}
	}).request();
}

Template.VARIABLE = '$';

function Template()
{
	var blockTypes = [];
	var blocks = [];
	
	this.processBlocks = function()
	{
		var inVariable = false;
		var block = "";
		var variableName = "";

		for (var x = 0; x < this.source.length; x++)
		{
			var sourceChar = this.source.charAt(x);
						
			if (inVariable && sourceChar == Template.VARIABLE) // Finished a VARIABLE block
			{
				blockTypes.push("var");
				blocks.push(block);				
				inVariable = false;
				block = "";
			}
			else if (inVariable)
			{
				block += sourceChar;
			}
			else if (sourceChar == Template.VARIABLE) // Started a VARIABLE Block
			{
				if (block.length > 0)
				{
					blockTypes.push("txt");
					blocks.push(block);
					block = "";
				}
				inVariable = true;
			}
			else
			{
				block += sourceChar;
			}			
		}
		
		assert(!inVariable, "Closing " + Template.VARIABLE + " not found.");		
		
		if (block.length > 0)
		{
			blockTypes.push("txt");
			blocks.push(block);		
		}
	}

	this.parse = function(object)
	{
		assert(this.source, "Template source not defined.");		
		
		var returnValue = "";
		
		if (blocks.length == 0)
		{
			this.processBlocks();
		}

		for (var i = 0; i < blocks.length; i++)
		{
			if (blockTypes[i] == "txt")
			{
				returnValue += blocks[i];
			}
			else
			{
				returnValue += eval ("object." + blocks[i]);
			}			
		}
		
		return returnValue;
	}
}

var tabbedPanes = new Object();

TabbedPane.create = function(id, array)
{	
	var tabbedPane = new TabbedPane();
	tabbedPanes[id] = tabbedPane;
	tabbedPane.array = array;
}

TabbedPane.show = function(id, panelName)
{
	tabbedPanes[id].show(panelName);
	return false;
}

function TabbedPane()
{
	this.array;
	
	this.show = function(panelName)
	{
		for (var i = 0; i < this.array.length; i++)
		{
			document.getElementById(this.array[i]).style.display = 'none';
		}
		document.getElementById(panelName).style.display = 'inline';
	}
}

function assert(bool, error)
{
	if (!bool)
	{
		throw new Error(error);
	}
}

function replace(text, toReplace, newText)
{
	var index = text.indexOf(toReplace);
	if (!newText)
		newText = "";
	if (index < 0)
		return text;
	var result = text.substr(0,index) + newText + text.substr(index+toReplace.length,text.length);
	return result;
}

function setChild(element, child)
{
	element.innerHTML = "";
	element.appendChild(child);
}

Function.getSourceElement = function(event)
{
	if (event.srcElement)
	{
		return event.srcElement;
	}
	else if(event.target)
	{
		return event.target;
	}
}

Function.createDelegate = function(a,b)
{
	return function()
	{
		return b.apply(a,arguments);
	}
};

Function.createCallback = function(b,a)
{
	return function()
	{
		var e=arguments.length;
		if ( e > 0 )
		{
			var d=[];
			for(var c = 0; c < e; c++)
				d[c]=arguments[c];
			d[e] = a;
			return b.apply(this,d);
		}
		return b.call(this,a)
	}
};

Function.addEventListener = function(element, name, eventHandler, bool)
{
	if (element && element.addEventListener)
	{
		element.addEventListener(name, eventHandler, bool);
	}
	else if (element && element.attachEvent)
	{
		element.attachEvent('on' + name, eventHandler); 
	}
}

Function.simpleSearch = function(elements, propertyName, toSearch)
{
	var returnValue = [];
	for (var i = 0; i < elements.length; i++)
	{
		var element = elements[i];
		var property = element[propertyName].toUpperCase();
		var search = toSearch.toUpperCase();
		if (property.indexOf(search) >= 0)
		{
			returnValue.push(element);
		}
	}
	return returnValue;
}

function categorize(items, propertyName)
{
	var map = new Object();
	var categories = new Array();
	
	for (var i = 0; i < items.length; i++)
	{	
		var property = items[i][propertyName];
		if (property)
		{
			if (!map[property])
			{
				map[property] = new Object();
				categories.push(map[property]);				
				map[property][propertyName] = property;
				map[property].items = new Array();
				map[property].getItems = function()
				{
					return this.items;
				};
			}
			map[property].items.push(items[i]);			
		}
	}
	
	return categories;
}