/*
Author:        Andrew Paul Simmons
Last Modified: 9.11.2006
Contact:       andrew-simmons@andrew-simmons.com
Description:   Basic Utilities for JS applications
*/


Utils = new Object();

/*
Used to ensure that callback methods are invoked in the
scope of their objects.

Usage:
myEl.onclick = Utils.createDelegate(myObject, function
												{
													//[my call back function here]
													//In this function "this"
													//will have the value of myObject.
												});
*/

Utils.createDelegate = function(object, method, val) 
{
	return function(args)
	{
	
		if(typeof args == "Array")
		{
			// make val the first argument
			if(val)args.unshift(val);
			return method.apply(object,args);
		}
		else
		{
			return method.apply(object,val?[val,args]:[args]);
		}
	}
}

/** 
** Delegates (see above) depend on the Function.apply method.
** However Function.apply is not supported by all browsers namely IE 5.0.
** Hence, here is my implementation of the standard apply method for 
** browsers which do not natively support Function.apply. 
** 
** The algorithm is simple: Assign the function to be applied
** to the object on which you wish to apply it. Then invoke 
** the function and delete the method.
**
**
**Note:
** (The native implementation of Funciton.apply invokes a function
** and sets the "this" variable in the function to the value of first 
** argument of apply(obj,args) "the scope object".   This allows us to
** invoke a method in  he scope of any object we choose.)  
**/

if (!Function.prototype.apply) 
{
		Function.prototype.apply = function(object, args)
		{
			// if no scope object is supplied use the window object
			if (!object) object = window;
				
				//make argument string string
				//of the form "args[0],args[1],args[2]"
				// these will later be evaluated by eval
				// and will retain their type.
				var args_str = "";
				if(args)
				{
					for (var i = 0; i < args.length; i++) 
					{
						(i > 0) ? args_str += ',' : '';
						args_str += "args["+i+"]";
					}
					
				}
				
				//  We create a _tempMethod property on object and set it
				// equal to this function.  Remember the value of "this" in
				// "object.tempMethod = this" is the function we are applying
				// (the one we want invoked on object).
            object.__tempMethod__ = this;
					 
					 
				// creates a string of the form
				// "object.tempMethod(args[0],args[1],args[2]);"
            var call_str = "object.__tempMethod__(" + args_str + ");";
					 
				// now that we have put the function on the object we simply invoke the method
				// as a member of "object"  We store the return value in returnVal.
            var returnVal = eval(call_str);
				

				
				//return the arguments.
				return returnVal;
        }
}

//Array needs pop and push in all browsers
if(!Array.prototype.push)
{
	Array.prototype.push = function(v)
	{
		this[this.length] = v;
	}
}
if(!Array.prototype.pop)
{
	Array.prototype.pop = function()
	{
		var v = this[this.length-1];
		var tempArray = [];
		//copy all but the last element
		for(var i = 0; i < this.length-1; i++)
		{
			tempArray[i] = this[i];
		}
		this.length--;
		return v;
	}
}
//pop_front
if(!Array.prototype.shift)
{
	Array.prototype.shift = function()
	{
		var v = this[0];
		for(var i = 0; i < this.length - 1; i++)
		{
			this[i] = this[i+1];
		}
		this.length--;
		return v;
	}

}
if(!Array.prototype.unshift)
{
	Array.prototype.unshift = function(v)
	{
		for(var i = this.length ; i > 0; i--)
		{
			this[i] = this[i-1];		
		}
		this[0] = v;
	}
}
// displays error to JavaScript console in FireFox
Utils.trace = function(aMsg) 
{ 
 	setTimeout( function() { throw new Error("[debug] " + aMsg); }, 0); 
} 


// Function: getElementPosition
// From: JavaScript & DHTML Cookbook
// Modified by: Andrew Paul Simmons

Utils.getElementPosition = function(element) 
{
	var offsetTrail;
	if(typeof element == "string")
	{
    	offsetTrail = document.getElementById(element);
	}
	else
	{
		offsetTrail = element;
	}
    var offsetLeft = 0;
    var offsetTop = 0;
    while (offsetTrail) 
	{
        offsetLeft += offsetTrail.offsetLeft;
        offsetTop += offsetTrail.offsetTop;
        offsetTrail = offsetTrail.offsetParent;
    }
    if (navigator.userAgent.indexOf("Mac") != -1 && 
        typeof document.body.leftMargin != "undefined") 
	{
        offsetLeft += document.body.leftMargin;
        offsetTop += document.body.topMargin;
    }
    return {left:offsetLeft, top:offsetTop};
}

// Function: getElementProperty
// From: JavaScript The Definitive Guide
// Modified by: Andrew Paul Simmons
Utils.getElementProperty = function(element, propertyName_str, process_func)
{
	var e;
	var propertyValue_str;
	
	//Element may be a string if it is we need to retrieve this element.
	if(typeof element == "string")
	{
		e = document.getElementById("InnerContainer2"); 
	}
	else
	{
		e = element;
	}
	
	//Here we get the style object and retrieve the requested property
	if (e.currentStyle) // Try simple IE API first
	{
		propertyValue_str = e.currentStyle[propertyName_str];
	}
	else if (window.getComputedStyle) // Otherwise use W3C API
	{
		propertyValue_str = window.getComputedStyle(e, null)[propertyName_str];	
	}
	
	// more often than not process_func will be parseInt.
	if(process_func)
	{
		return process_func(propertyValue_str);
	}
	
	return propertyValue_str;
	
}
Utils.trimString = function(sString)
{
	while (sString.substring(0,1) == ' ')
	{
	sString = sString.substring(1, sString.length);
	}
	while (sString.substring(sString.length-1, sString.length) == ' ')
	{
	sString = sString.substring(0,sString.length-1);
	}
	return sString;
}


