
/*
##############################################################################################
#   $Source: /home/cvs/clientside/cvsroot/jstools/mod/mod.jst_core.js,v $
#   $Author: stephenc $
#   $Revision: 1.22 $
#   $Date: 2004/08/16 15:17:52 $
##############################################################################################
*/

/**
 * The main bbcjs object.
 *
 * @author Stephen Calcott
 */
var bbcjs =
{
	version				: 1,
	cvs_version			: "$Revision: 1.22 $",
	build_date			: '$Date: 2004/08/16 15:17:52 $',
	page				: location.href.split("/")[location.href.split("/").length-1],
	onLoadArr			: [],
	o2lvl				: 0,
	o2cnt				: 0,
	dhtml				: (document.getElementById) ? true : false,
	defaultTraceLevel	: 3,
	quietMode			: false,
	activex				: (typeof(window.ActiveXObject)!="undefined"),
	qs					: location.search.substr(1,location.search.length),
	lib					: {}
};
//Need to remind IE5 mac that it DOESN'T support activex:
if (navigator.userAgent.indexOf("Mac")>-1) bbcjs.activex = false;


/**
 * Provides debugging functionality for use in harness.
 *
 * @author Stephen Calcott
 *
 * @param {string} str The string to be sent to the trace window.
 * @param {number} lvl The debug level for which this message is valid.
 */
bbcjs.trace = function (str,lvl)
{
	if (window.self != window.parent) {
		if ((typeof(window.parent.frames.tools)!="undefined") && typeof(window.parent.frames.tools.jsh_debug)!="undefined" )
		{
			if (typeof(lvl)=="undefined") lvl = bbcjs.defaultTraceLevel;
			window.parent.frames.tools.jsh_debug(str,lvl);
		}
	}
	//If we have a level 1 alert, are working on preview servers and no harness is loaded, alert the message.
	else if ( (!bbcjs.quietMode) && (lvl == 1) && (location.href.match(/wc\.bbc/)))
	{
		str = str.replace(/\<br ?\/?\>/g,"\n");
		str = str.replace(/\<[a-zA-Z0-9\=\"_\-\' \/]+\>/g,"");
		alert("JSTools error (this will not appear on live):\n\n"+str);
	}
}
bbcjs.trace('<b><font color="green">jst_core.js</font> was included.</b>',2);

/**
 * Add something to be done onLoad.
 *
 * @author Stephen Calcott
 *
 * @param {string} str A line of javascript eval-able code, with neccessary escaping.
 */
bbcjs.addOnLoadItem = function (str)
{
	bbcjs.onLoadArr[bbcjs.onLoadArr.length] = str;
	window.onload = bbcjs.loadedHandler;
}

/**
 * Loop through all onload code defined in the bbcjs.onLoadArr array and eval each item.
 *
 * @author Stephen Calcott
 */
bbcjs.loadedHandler = function ()
{
	for (var i in bbcjs.onLoadArr)
	{
		eval(bbcjs.onLoadArr[i]);
	}
}

/**
 * Copy an object, and return. makes a non-reference.
 *
 * @author Stephen Calcott
 *
 * @param {object} o The object to be copied from.
 * @returns An object with the same structure as the original passed through.
 */
bbcjs.copyObj = function (o)
{
	var t = {};
	if (typeof(o.length)!="undefined") t = [];

	for (var i in o)
	{
		if (typeof(o[i])=="object") t[i] = bbcjs.copyObj(o[i]);
		else t[i] = o[i];
	}
	return t;
}

/**
 * Returns a html <ul> element to graphically represent a js object.
 *
 * @author Stephen Calcott
 *
 * @param {object} o The object that needs to be represented visually.
 * @param {string} name The name that will appear at the top of the html list that is created
 * @param {boolean} hide A flag to say whether or not to have the list collapsed when written to the page (default is true)
 */
bbcjs.obj2list = function(o,name,hide)
{
	var str = "";
	var c=0;
	var display = "none";

	if (typeof(hide)!="undefined"){ if (!(hide)) display = "block";}
	else hide = true;

	//If we haven't been supplied a name, use a common name
	if (typeof(name)=="undefined") name = "_root";

	//Only create the outer UL tag for the first instance (root)
	if (bbcjs.o2lvl==0) str+="<ul>\n";
	bbcjs.o2lvl++;
	bbcjs.o2cnt++;

	//Begin the object element.
	str+='<li><a href="javascript:void(0);" onclick="return bbcjs.o2swap('+bbcjs.o2cnt+')">'+name+'</a></li>\n';
	if (o.constructor == bbcjs.Module) str+= ' <small>(<a href="javascript:void(0);" onclick="return bbcjs.'+o.name+'.getDocs();">mod</a>)</small>';
	str+='<ul style="display:'+display+';" id="bbcjsnode_'+bbcjs.o2cnt+'">\n';

	//Loop through each element of this object, recurse if we find an object...
	for (var i in o)
	{
		if (typeof(o[i])=='function') str+=('<li>'+i.bold()+'()</li>\n');
		else if ((typeof(o[i])=='object') && (o[i].constructor != Date))
		{
			if ((typeof(o[i].src)!="undefined") && (typeof(o[i].alt)!="undefined"))
			{
				str+=('<li><b>'+i+"</b>: "+o[i].src+' (image)</li>\n');
			}
			else if (bbcjs.o2lvl<100) str+=bbcjs.obj2list(o[i],i,hide); //recurse here
			else str+="<li>Too much recursion...</li>\n";
		}
		else if (o[i]!=null) str+=('<li>'+i+' ['+bbcjs.HTMLOut(o[i])+'] ('+typeof(o[i])+')</li>\n');
		else str += '<li><b>null item</b></li>';
		c++;
	}
	if (c==0) str+=('<li>'+o+'</li>\n'); //Output empty objects as [Empty Object]
	str+="</ul>\n";

	//Get out of this level of nesting...
	bbcjs.o2lvl--;

	//close the original ul if on main recursion level.
	if (bbcjs.o2lvl==0)	str+="</ul>\n";

	return str;
}

/**
 * Works with obj2list to make collapsable lists.
 *
 * @author Stephen Calcott
 *
 * @param {string} nn The number of the node that is to be toggled
 */
bbcjs.o2swap = function (nn)
{
	var node = document.getElementById("bbcjsnode_"+nn);
	if (node.style.display == "block") node.style.display = "none";
	else node.style.display = "block";
}

/**
 * Takes in a chunk of HTML, and converts the special characters (namely < and >) for output to screen. This could
 * possibly be replaced by String.prototype.xmp()
 *
 * @author Stephen Calcott
 *
 * @param {string} html A string of html that needs to be used in an output scenario
 * @returns The same string as passed through, but in xmp tags.
 */
bbcjs.HTMLOut = function (html)
{
	return "<xmp style='display:inline;'>"+html+"</xmp>";
}

/**
 * bbcjs.Module is the prototype for all subsequent JSTools modules.
 *
 * @author Stephen Calcott
 *
 * @constructor 
 * @param {String} name The module name to be referenced in documentation
 * @param {Number} v The release version number
 * @param {String} cvs The CVS version rubric (e.g. "$Revision: 1.22 $")
 * @param {String} bd The CVS date rubric (e.g. "$Date: 2004/08/16 15:17:52 $")
 */
bbcjs.Module = function (name, v, cvs, bd)
{
	/** The name of the module */
	this.name = name;
	/** The release version */
	this.version = v;
	/** The CVS version rubric */
	this.cvs_version = cvs;
	/** The CVS date rubric */
	this.build_date = bd;
	/** Provides easy access to the documentation for the module */
	this.getDocs = function()
	{
		window.open("http://technet.wc.bbc.co.uk/software/js/findmod.xhtml?"+this.name);
	}
}

/**
 * Emulates printf basically. Allows for easier construction of strings from within functions.
 *
 * @author Stephen Calcott
 * @param str A string containing the text and replacement holders for a printf output
 * @param vars n number of arguments passed through in order of replacement for the string.
 */
function printf ()
{
	var parsed = arguments[0];
	for (var i=1; i<arguments.length; i++)
	{
		parsed = parsed.replace(/%[a-z]/, arguments[i]);
	}
	// Cleanup and superfluous args
	parsed = parsed.replace(/%[a-z]/g, "");
	return parsed;
}
var sprintf = printf;

/**
 * A global named CONST, within which to store 'constants'.
 *
 * @author Stephen Calcott
 */
var CONST = {};