/** 
 * @fileoverview Miscellaneous utility classes and functions for the JSPOOP library
 * @author James Palmer james@phoenixlondon.co.uk
 * @version 0.1 
 */

/**
 * Construct the Phoenix.Util object.
 * @class Base class for miscellaneous utility classes and functions in the Phoenix library.
 * @constructor
 * @requires Phoenix
 */
Phoenix.Util = function()
{
};
//registerNamespace("Phoenix.Util");

/**
 * Standards-compliant "open in new window" function to replace the (now invalid in XHTML) target="_blank" markup.
 * @param	src			An HTML anchor element, an event object whose source element is an HTML anchor element, or any other object whose toString() method returns an appropriate URI
 * @param	winname		The name to give the newly-opened window
 * @param	openparams	The window options ("width=X,height=Y,location=yes", etc) string to pass to window.open
 * @return				Reference to the newly-created window object
 */
Phoenix.Util.openInNewWin = function (src, winname, openparams)
{
	src = src || window.event;
	winname = winname || "";
	openparams = openparams || null;
	
	winname = winname.replace(/[^a-zA-Z0-9\-]/, "_");	// IE doesn't like thingsl ike spaces in window-names, so let's err on the side of caution.

	if(src)
	{
		if(typeof(src.innerHTML) != "undefined" && src.href)	// src is an HTML element and has an href destination
		{
			if(openparams)		// Separate calls depending on whether openparams is specified - Firefox (at least) thinks "" or null for this parameter means "turn everything off", not "whatever the default is".  Instead, simply not passing a windowoptions parameter invokes the window with the default browser chrome
				return(window.open(src.href, winname, openparams));
			else
				return(window.open(src.href, winname));
		}
		else if(typeof(src.cancelBubble) != "undefined")	// src is a DOM event
		{
			if(src.preventDefault)
				src.preventDefault();

			requireNamespace("Phoenix.Util.Event");	// Can't put this at the beginning of the file, as we'd be requiring a child of the Namespace before defined its parent.  Compromise by only throwing an error if the functionality's actually used anywhere.

			var el = Phoenix.Util.Event.getCurrentTarget(src);	// Get the element which fired this event

			if(el && el.href)
			{
				if(openparams)
					return(window.open(el.href, winname, openparams));
				else
					return(window.open(el.href, winname));
			}
		}
		else if(src.toString)
		{
			if(openparams)
				return(window.open(src.toString(), winname, openparams));
			else
				return(window.open(src.toString(), winname));
		}
	}
	
	return(false);
};




/**
 * Converts HTML entities to their character equivalents
 * @param	{string}	html		The raw HTML to convert
 * @return	{string}				The passed text with all HTML entities converted to their character equivalents
 */
Phoenix.Util.unescapeHTMLEntities = function (html)
{
	var textarea = document.createElement("textarea");
	textarea.innerHTML = html.replace(/</g,"&lt;").replace(/>/g,"&gt;");
	
	return(textarea.value);
}

/**
 * Converts special characters to their HTML entity equivalents
 * @param	{string}	html		The raw (unescaped) text to convert
 * @return	{string}				The passed HTML with all special characters converted to their HTML entity equivalents
 */
Phoenix.Util.escapeHTMLEntities = function (text)
{
	var div = document.createElement("div");
	var textnode = document.createTextNode(text);
	div.appendChild(textnode);
	
	return(div.innerHTML);
}


/**
 * Convert a length associated with an element from ems to px
 * 
 * @param {int} 		length	Any valid CSS length value (ems, px, percentage, pts, etc)
 * @param {object}	element	The HTML element whose font-size should serve as the basis for the conversion
 *  
 * @return The computed value of the specified em-length in px
*/
Phoenix.Util.lengthToPX = function(length, element)
{
//	debugger
	var tempdiv = document.createElement("div");
	tempdiv.style.visibility = "hidden";
	tempdiv.style.width = length;
	tempdiv.style.margin = "0px";
	tempdiv.style.padding = "0px";
	
	element.appendChild(tempdiv);
	
	length = tempdiv.offsetWidth;
	
	element.removeChild(tempdiv);
	
	return(length);
}


/**
 * Trivial but useful function to return out a (string) list of the members of any object and their values.
 * @param		{object}	obj				A Javascript object
 * @param		{String}	separator		A string to use as a separator between attribute:value pairs (default: " ")
 * @return									A list of the members of the passed object as a <em>separator</em>-delimited string of attribute:value pairs
 */
Phoenix.Util.listObjectMembers = function(obj, separator)
{
	separator = separator || " ";
	var output = "";
	for(mem in obj)
		output += "" + mem + ":" + obj[mem] + separator;
	return(output);
}


/**
 * Save a value into the global scope so it may be retrieved later.  Using this function instead of arbitrary window.variablename variables groups the saved states together and reduces the chances of unexpected collisions (ie, two different controls or systems using the same variable).
 * 
 * We can usually avoid this by passing variables to functions instead of using variables in the global scope, but in certain situations this is impossible - for example IE still doesn't support passing additional parameters in asynchronous callback functions like setTimeout/setInterval.
 * 
 * Currently this function only saves state locally to the client (for asynchronous calls within a page).  Could easily be extended later with an option to support AJAX calls back to the server to save state *between* page-loads.
 * @param		{String}	uniqueid		A unique id to index this data by
 * @param		{object}	state				An object to save in the global scope
 * 
 * @see #getLocalState
 */
Phoenix.Util.saveLocalState = function (uniqueid, state)
{
	if(!namespaceDefined("Phoenix._Config.SavedState"))
		registerNamespace("Phoenix._Config.SavedState");
		
	Phoenix._Config.SavedState[uniqueid] = state;
};

/**
 * Retrieve a value from where we stashed it the global scope using {@link #saveLocalState}.
 *  
 * @param		{String}	uniqueid		A unique id to index this data by
 * @param		{object}	state				An object to save in the global scope
 * 
 * @see #saveLocalState  
 */
Phoenix.Util.getLocalState = function (uniqueid)
{
	if(namespaceDefined("Phoenix._Config.SavedState"))
		return(Phoenix._Config.SavedState[uniqueid]);
	
	return(null);
};