﻿// Array.merge(array1, array2, …, arrayN)
// returns Array of all elements
Array.merge = function()
{
	var result = new Array();
	for (var argumentIndex = 0, argumentLength = arguments.length; argumentIndex < argumentLength; argumentIndex++) 
		for (var arrayIndex = 0, array = arguments[argumentIndex], arrayLength = array.length; arrayIndex < arrayLength; arrayIndex++)
			result.push(array[arrayIndex]);
				
	return result;
}


if (!Array.prototype.indexOf)
{
	Array.prototype.indexOf = function(elt /*, from*/)
	{
		var len = this.length;

		var from = Number(arguments[1]) || 0;
		from = (from < 0) ? Math.ceil(from) : Math.floor(from);
		if (from < 0) from += len;

		for (; from < len; from++)
		{
			if (from in this && this[from] === elt)
				return from;
		}
		return -1;
	};
}

if (!Array.prototype.doForEach)
{
	Array.prototype.doForEach = function(delegate /*, from */)
	{
		var len = this.length;

		var from = Number(arguments[1]) || 0;
		from = (from < 0) ? Math.ceil(from) : Math.floor(from);
		if (from < 0) from += len;

		for (; from < len; from++)
		{
			if (from in this) this[from] = delegate(this[from]);
		}
		return this;
	};
}

Array.prototype.createIndexByKey = function(key)
{
	if (!this.indexes) this.indexes = new Object();
	var newIndex = this.indexes[key] = new Object();
	
	for (var index = 0, length = this.length; index < length; index++)
		if (this[index] && this[index][key])
			newIndex[this[index][key]] = index;
}

Array.prototype.indexOfKeyValue = function(key, value)
{
	if (!key || !value) return false;
	
	if (this.indexes && this.indexes[key])
	{
		 if (this.indexes[key][value] >= 0) return this.indexes[key][value];
	}
	else
	for (var index = 0, length = this.length; index < length; index++)
		if (this[index] && this[index][key] == value)
			return index;

	return -1;
}

Array.prototype.findByKeyValue = function(key, value)
{
	var index = this.indexOfKeyValue(key, value);
	return index < 0 ? null : this[index];
}

// needs findByKeyValue
Array.prototype.connectByKey = function(newKey, foreignKey, array, key)
{
	for (var index = 0, length = this.length; index < length; index++)
	{
		this[index][newKey] = array.findByKeyValue(key, this[index][foreignKey]);
	}
}



function Hashtable()
{
	this.items = new Object();
	
	this.add = function(key, value)
	{
		this.items[key] = value;
	}

	this.contains = this.containsKey = function(keyToContain)
	{
		for (var key in this.items) if (key == keyToContain) return true;
		return false;
	}

	this.containsValue = function(valueToContain)
	{
		for (var key in this.items) if (this.items[key] == valueToContain) return true;
		return false;
	}

	this.remove = this.removeKey = function(keyToRemove)
	{
		for (var key in this.items) if (key == keyToRemove) delete(this.items[key]);
	}

	this.removeValue = function(valueToRemove)
	{
		for (var key in this.items) if (this.items[key] == valueToRemove) delete(this.items[key]);
	}

	this.clear = function()
	{
		delete(this.items);
		this.items = new Object();
	}
	
	this.findBySubKeyValue = function(subKey, subValue)
	{
		for (var key in this.items) if (this.items[key] && this.items[key][subKey] == subValue) return key;
		return null;
	}


	this.connectToHashtable = function(foreignHashtable, foreignKey, newKey)
	{
		for (var key in this.items)
		{
			var item = this.items[key];
			item[newKey] = foreignHashtable.items[item[foreignKey]];
		}
	}
	
	this.toArray = function(keyToUse, includeEmptyValues)
	{
		var array = new Array();
		
		for (var key in this.items)
			if (includeEmptyValues || this.items[key])
			{
				value[keyToUse] = key;
				array.push(value);
			}
			
		return array;
	} 
	
	this.toUrl = function(includeEmptyValues, valueFunction)
	{
		var url = "";
		
		for (var key in this.items)
			if (includeEmptyValues || this.items[key])
				url += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(valueFunction ? valueFunction(this.items[key]) : this.items[key]);
			
		return url.substring(1);
	}
}

Hashtable.fromUrl = function(url)
{
	var hashtable = new Hashtable();

	if (url.substring(0, 1) == "?" || url.substring(0, 1) == "#") url = url.substring(1);
	var elementSeparator = "&";
	var keyValueSeparator = "=";

	var elements = url.split(elementSeparator); // Array of elements
	for (var index = 0, length = elements.length; index < length; index++)
	{
		var parts = elements[index].split(keyValueSeparator);
		if (parts.length == 2) hashtable.add(decodeURIComponent(parts[0]), decodeURIComponent(parts[1]));
	}
		
	return hashtable;
}

Hashtable.fromArray = function(array, keyToUse, indexToSet)
{
	if (!array || !keyToUse) return null;

	hashtable = new Hashtable();
	for (var index = 0, length = array.length; index < length; index++)
		if (array[index] && array[index][keyToUse])
		{
			hashtable.add(array[index][keyToUse], array[index]);
			if (indexToSet) array[index][indexToSet] = index;
		}
		
	return hashtable;
}

/*
var Test =
{
	abc : 1
}

Test.prototype = new Object();


	var max = 10000;

	var ar = new Array();
	var ht = new Object();

	var start = new Date();

	for (var index = 0; index < max; index++)
	{
		var o = new Object();
		o.ID = index;
		ar.push(o);
	}

	ar.createIndexByKey("ID");

	var time0 = new Date() - start;

	for (var index = 0; index < max; index++)
	{
		var o = new Object();
		o.ID = index;
		ht[index] = o;
	}
	
	var time1 = new Date() - start;
	
	for (var index = 0; index < max; index++)
	{
		var foo = ar.findByKeyValue("ID", index);
	}

	var time2 = new Date() - start;

	for (var index = 0; index < max; index++)
	{
		var foo = ht[index];
	}

	var time3 = new Date() - start;

	alert (time0 + "/" + time1 + "/" + time2 + "/" + time3);
	
	*/