
/*
 * Creates a new map. This method simply initializes the internal array
 * backing this map.
 *
 * A map keeps an internal list of keys and their corresponding values.
 * Once a key/value pair is added using put(), the key can then be used to
 * retrieve its corresponding value using get(). Keys must be defined and
 * non-null, and a map does not allow duplicate keys. An attempt to add a
 * key/value pair when the key is already present results in the current
 * key/value pair being replaced by the new one. The values themselves must
 * be defined, but can be null. Multiple duplicate values are permitted.
 */
function Map()
{	this.elements = new Array();
}

/*
 * Gets the size of the map, the number of key/value pairs it contains.
 */
Map.prototype.size = function()
{	return this.elements.length;
}

/*
 * Tests whether this map is currently empty (has no key/value pairs).
 */ 
Map.prototype.isEmpty = function()
{	return (this.elements.length == 0);
}

/*
 * Gets an array of the keys in this map.
 */
Map.prototype.keys = function()
{	var a = new Array();
	
	with(this)
	{	for(var i = 0; i < elements.length; i++)
			a[i] = elements[i][0];
	}
		
	return a;
}

/*
 * Gets an array of the values in this map.
 */
Map.prototype.values = function()
{	var a = new Array();
	
	with(this)
	{	for(var i = 0; i < elements.length; i++)
			a[i] = elements[i][1];
	}
		
	return a;
}

/*
 * Tests whether this map contains the specified key.
 */
Map.prototype.containsKey = function(key)
{	if(key && key != null)
	{	with(this)
		{	for(var i = 0; i < elements.length; i++)
				if(elements[i][0] == key)
					return true;
		}
	}
			
	return false;
}

/*
 * Tests whether this map contains the specified value.
 */
Map.prototype.containsValue = function(value)
{	if(value)
	{	with(this)
		{	for(var i = 0; i < elements.length; i++)
				if(elements[i][1] == value)
					return true;
		}
	}
	
	return false;
}

/*
 * Adds a key/value pair to this map. The key must be defined
 * and non-null. The value must be defined, but can be null.
 *
 * If a key is currently contained in this map that is the same
 * as the key to be added, the new key/value pair is inserted in place of
 * the old pair and the old pair is then returned. If the new key is not
 * already present, this method returns null.
 */
Map.prototype.put = function(key, value)
{	var c = null;
	
	if(key && key != null && value)
	{	var a = new Array();
		a.length = 2;
		a[0] = key;
		a[1] = value;
	
		with(this)
		{	var index = elements.length;
			
			if(containsKey(key))
			{	var b;
				for(var i = 0; i < elements.length; i++)
				{	b = elements[i];
					if(b[0] == key)
					{	c = b[1];
						index = i;
						break;
					}
				}
			}
			
			elements[index] = a;
		}
	}
	
	return c;
}

/*
 * Gets the value associated with the specified key, if any.
 * Otherwise, this method returns null.
 */
Map.prototype.get = function(key)
{	with(this)
	{	if(containsKey(key))
		{	var a;
			for(var i = 0; i < elements.length; i++)
			{	a = elements[i];
				if(a[0] == key)
					return a[1];
			}
		}
	}
	
	return null;
}

/*
 * Removes the key/value pair with the specified key from this map, if any
 * such key is present. The removed key/value pair is then returned. If no such
 * key is present in this map, this method returns null. If a key/value pair is
 * successfully removed, ths size of this map decreases by 1.
 */
Map.prototype.remove = function(key)
{	var value = null;	

	if(key && key != null)
	{	with(this)
		if(containsKey(key))
		{	var it;
			{	for(var i = 0; i < elements.length; i++)
				{	it = elements[i];
					if(it[0] == key)
					{	value = it[1];
				
						// shift the mappings after to the left	
						for(var j = i; j < (elements.length - 1); j++)
							elements[j] = elements[j + 1];

						// last element is invalid, chop it off
						elements.length -= 1;
								
						break;
					}
				}
			}
		}
	}
	
	return value;
}

/*
 * Sorts this map's keys according to the specified sort function. If the sort
 * function is not defined, the keys are sorted using the default
 * no-argument sort function Array.sort().
 */
Map.prototype.sort = function(sortFunc)
{	if(sortFunc && sortFunc != null)
		this.elements.sort(sortFunc);
	else this.elements.sort();	
}

/*
 * Clears this map. This method reduces the size of the map to 0.
 */
Map.prototype.clear = function()
{	this.elements.length = 0;
}

/*
 * Gets a string representation of this mep.
 */
Map.prototype.toString = function()
{	var str = "[object Map {";

	with(this)
	{	var it;
		for(var i = 0; i < elements.length; i++)
		{	it = elements[i];
		
			if(i > 0)	str += ", ";
		
			str += it[0];
			str += "=";
			str += it[1];
		}
	}
	
	str += "}]";
	
	return str;
}
