///////////////////////////////////////////////////////////////////////////////
// Toolkit Utility Methods
///////////////////////////////////////////////////////////////////////////////

var tkutils;
if (!tkutils) { tkutils = {}; } else if (typeof tkutils !== "object") { throw new Error("tkutils already exists and is not an object"); }

tkutils._globalNamespace = this; // In an HTML context, "this" will be "window"

tkutils.getGlobalNamespace = function()
{
	return tkutils._globalNamespace;
};

tkutils.createNamespace = function(ns)
{
	var nsParts = ns.split(".");
	var root = tkutils.getGlobalNamespace();

	for(var i=0; i<nsParts.length; i++)
	{
		if(typeof (root[nsParts[i]]) === "undefined")
		{
			root[nsParts[i]] = {};
		}

		root = root[nsParts[i]];
	}
};

tkutils.trimString = function (text)
{
	return text.replace(/^\s*/, '').replace(/\s*$/, '');
};

tkutils.isNonEmptyString = function(test)
{
	return ((typeof (test) === 'string') && (test !== null) && (test.length > 0));
};

tkutils.getObjectFromString = function(spec)
{
	var o = tkutils.getGlobalNamespace();
    if (spec.length > 0) {
    	var parts = spec.split('.');
    	for(var i=0; i<parts.length; i++)
    	{
    	    var childO = o[parts[i]];
    	    if (!tkutils.isDefined(childO))
    	    {
    	        return null;
    	    }
    		o = childO;
    	}
    }	
	return o;
};

tkutils.isDefined = function ( test )
{
	return ( typeof(test) !== 'undefined' );
};

tkutils.formatTimeString = function ( time )
{
    if (!(arguments.length === 1 && typeof(arguments[0]) === 'number'))
    {
        throw new Error('Call formatTimeString with a number!');
    }

	var timeString = "";

	if ( time < 60 )
	{
		timeString = "00:";
		
		if ( time === 0 )
		{
			timeString += "00";			
		}
		else {
		
		    if (time < 10)
		    {
		      timeString += "0" + time;
		    }
		    else
		    {
		      timeString += time;
		    }
		}
	}
	else
	{
		var minutes = Math.floor( time/60 );

		timeString = ( (minutes < 10 ) ? "0" + minutes + ":" : minutes + ":" );

		var seconds = ( time - (minutes*60) );
		
		if ( seconds === 0 )
		{
			timeString += "00";			
		}
		else {
		
		    if ( seconds < 10 )
		    {
		      timeString += "0" + seconds;
		    }
		    else
		    {
		     timeString += seconds;
		    }
		}
	}
			
	return timeString;	
};

///////////////////////////////////////////////////////////////////////////////
// OS/Browser Utility Methods
///////////////////////////////////////////////////////////////////////////////

tkutils.isWindowsOS = function()
{
	return (navigator.platform.indexOf('Win') !== -1);
};

tkutils.isWindowsVistaOS = function()
{
	return (navigator.userAgent.toLowerCase().indexOf('windows nt 6.0') !== -1);
};

tkutils.isMacOS = function()
{
	return (navigator.platform.indexOf('Mac') !== -1);
};

tkutils.isMacOSX = function()
{
	return (navigator.userAgent.toLowerCase().indexOf('mac os x') >= 0);
};

tkutils.isIEBrowser = function()
{
	return (navigator.appName.indexOf('Microsoft') !== -1);
};

tkutils.isIE6Browser = function()
{
	return tkutils.isIEBrowser() && (navigator.userAgent.indexOf('MSIE 6') !== -1);
};

tkutils.isFirefoxBrowser = function()
{
	return (navigator.userAgent.indexOf('Firefox') !== -1);
};

tkutils.isSafariBrowser = function()
{
	return (navigator.vendor) && (navigator.vendor.indexOf('Apple') !== -1);
};

tkutils.isOperaBrowser = function()
{
	return (typeof(window.opera) !== 'undefined');
};

tkutils.findDomElement = function (name)
{
	var el = ( (tkutils.isIEBrowser() || tkutils.isOperaBrowser()) ? window[name] : document[name]);
	
	if ( !el )
	{
		// Fallback attempt.
		el = document.getElementById( name );
	}
	return el;
};

tkutils.getDomParent = function (child)
{
	var parent = ((tkutils.isIEBrowser() || tkutils.isOperaBrowser()) ? child.parentElement : child.parentNode);
	return parent;
};

tkutils.getEventDomTarget = function (theEvent)
{
	var target = (tkutils.isIEBrowser() ? theEvent.srcElement : theEvent.currentTarget);
	return target;
};

tkutils.findDomAncestorByTagName = function (element, tagName)
{
	while ( element !== null )
	{
		if ( element.tagName.toLowerCase() === tagName.toLowerCase() )	
		{
			return element;
		}		
		element = tkutils.getDomParent( element );
	}
	return null;
};

tkutils.insertDomChildBefore = function (parent, child, sibling)
{
	sibling = (sibling) ? sibling : null;
	if ( tkutils.isIEBrowser() && (sibling === null) )
	{	// older versions of IE do not like a null second parameter...
		parent.insertBefore( child );
	}
	else
	{
		parent.insertBefore( child, sibling );
	}		
};

tkutils.addComboOption = function (combo, newOption)
{
	if ( tkutils.isIEBrowser() )
	{
		combo.add( newOption );
	}
	else
	{
		combo.add( newOption, null );
	}		
};

///////////////////////////////////////////////////////////////////////////////
// Query Argument Utility Methods
///////////////////////////////////////////////////////////////////////////////

tkutils.getQueryArg = function(name)
{
	tkutils.getQueryArg.p_fault();
	var val = tkutils.getQueryArg.p_map[name];
	return (val) ? val : null;
};

tkutils.getQueryArgOpt = function(name, defaultValue)
{
	var val = tkutils.getQueryArg(name);
	return (val) ? val : defaultValue;
};

tkutils.getQueryArg.p_map = null;

tkutils.getQueryArg.p_fault = function()
{
	if (tkutils.getQueryArg.p_map !== null)
	{
		return;
	}
	
	tkutils.getQueryArg.p_map = {};
	
	var query = window.location.search.substring( 1 );
	
	var parameters = query.split( "&" );
	
	for ( var i = 0; i < parameters.length; i++ ) 
	{
		var delimiter = parameters[i].indexOf( '=' );
		
		if ( delimiter > 0 ) 
		{			
			var name = parameters[i].substring( 0,delimiter );			
			var value = decodeURIComponent( parameters[i].substring( delimiter+1 ) );			
			tkutils.getQueryArg.p_map[ name ] = value;	
		}		
	}
};

///////////////////////////////////////////////////////////////////////////////
// Cookie Methods
///////////////////////////////////////////////////////////////////////////////

/*
WM_setCookie(), WM_readCookie(), WM_killCookie()
A set of functions that eases the pain of using cookies.

Source: Webmonkey Code Library
(http://www.hotwired.com/webmonkey/javascript/code_library/)

Author: Nadav Savio

CHANGES TO ORIGINAL: Simply provided an 'OO' wrapper, made a couple 
very tiny changes for JSLint to pass.
*/

tkutils.Cookie = function ()
{
};

tkutils.Cookie.getCookieDomain = function()
{
	return window.location.hostname;
};

tkutils.Cookie.getTopLevelCookieDomain = function()
{
	var domain = tkutils.Cookie.getCookieDomain();
	var pos = domain.indexOf('.');
	if (pos > -1)
	{
		domain = domain.substr(pos);
	}
	return domain;
};

tkutils.Cookie.canUse = function()
{
	// ORIGINAL METHOD: WM_browserAcceptsCookies
	// This next little bit of code tests whether the user accepts cookies.
	var WM_acceptsCookies = false;
	if ( document.cookie === '' ) {
		document.cookie = 'WM_acceptsCookies=yes'; // Try to set a cookie.
		if ( document.cookie.indexOf( 'WM_acceptsCookies=yes' ) !== -1 ) {
			WM_acceptsCookies = true;
		} // If it succeeds, set variable
	} else { // there was already a cookie
		WM_acceptsCookies = true;
	}
	
	return ( WM_acceptsCookies );
};

tkutils.Cookie.write = function(name, value, hours, path, domain, secure)
{
	// ORIGINAL METHOD: WM_setCookie
	if ( tkutils.Cookie.canUse() ) { // Don't waste your time if the browser doesn't accept cookies.
		var numHours = 0;
		var not_NN2 = ( navigator && navigator.appName &&
					 (navigator.appName === 'Netscape') && 
					 navigator.appVersion &&
					(parseInt(navigator.appVersion, 0) === 2) ) ? false : true;

		if ( hours && not_NN2 ) { // NN2 cannot handle Dates, so skip this part
			if ( (typeof(hours) === 'string') && Date.parse(hours) ) { // already a Date string
				numHours = hours;
			} else if ( typeof(hours) === 'number' ) { // calculate Date from number of hours
				numHours = ( new Date((new Date()).getTime() + hours*3600000) ).toGMTString();
			}
		}
		
		document.cookie = name + '=' + escape(value) + ((numHours)?(';expires=' + numHours):'') + ((path)?';path=' + path:'') + ((domain)?';domain=' + domain:'') + ((secure && (secure === true))?'; secure':''); // Set the cookie, adding any parameters that were specified.
	}
};

tkutils.Cookie.read = function(name)
{
	// ORIGINAL METHOD: WM_readCookie
	if ( document.cookie === '' ) { // there's no cookie, so go no further
	    return false;
	} else { // there is a cookie
	    var firstChar, lastChar;
		var theBigCookie = document.cookie;
		firstChar = theBigCookie.indexOf(name);	// find the start of 'name'
		var NN2Hack = firstChar + name.length;
		if ( (firstChar !== -1) && (theBigCookie.charAt(NN2Hack) === '=') ) { // if you found the cookie
			firstChar += name.length + 1; // skip 'name' and '='
			lastChar = theBigCookie.indexOf(';', firstChar); // Find the end of the value string (i.e. the next ';').
			if (lastChar === -1) { lastChar = theBigCookie.length; }
			return unescape( theBigCookie.substring(firstChar, lastChar) );
		} else { // If there was no cookie of that name, return false.
			return false;
		}
	}	
};

tkutils.Cookie.kill = function(name, path, domain)
{
	// ORIGINAL METHOD: WM_killCookie
	var theValue = tkutils.Cookie.read( name ); // We need the value to kill the cookie
	if ( theValue ) {
		document.cookie = name + '=' + theValue + '; expires=Fri, 13-Apr-1970 00:00:00 GMT' + ((path)?';path=' + path:'') + ((domain)?';domain=' + domain:''); // set an already-expired cookie
	}
};

///////////////////////////////////////////////////////////////////////////////
// Timer class
///////////////////////////////////////////////////////////////////////////////

tkutils.Timer = function (interval, maxRepeatCount, callbackFn, callee)
{
    var validArgs = (
        // interval must be a number greater than or equal to 0
        (typeof(interval) === 'number') &&
        (interval >= 0) && 
        // maxRepeatCount must be -1 (repeat until stop is called) or a positive number
        (typeof(maxRepeatCount) === 'number') &&
        (maxRepeatCount === -1 || maxRepeatCount > 0) && 
        // callbackFn must be a function, which will be called with one arg, the timer object
        (typeof(callbackFn) === 'function') &&
        // callee must be an object if callbackFn is a prototype method, else callee must be null 
        (callee === null || (typeof(callee) === 'object')));
        
    if (!validArgs)
    {
        throw new Error('Check arguments passed to timer constructor');
    }
        
	this.p_id = 'not set'; // set by calling setId
	this.p_interval = interval;	
	this.p_maxRepeatCount = maxRepeatCount;
	this.p_callbackFn = callbackFn;
	this.p_callee = callee;
	this.p_repeatCount = 0;
	this.p_cookie = -1;	
};

tkutils.Timer.prototype.setId = function(val)
{
	this.p_id = val;
};

tkutils.Timer.prototype.getId = function()
{
	return this.p_id;
};

tkutils.Timer.prototype.isRunning = function()
{
	return (this.p_cookie !== -1);
};

tkutils.Timer.prototype.start = function()
{
	this.stop();
	this.p_repeatCount = 0;
	var closureThis = this;
	this.p_cookie = window.setInterval( function(){closureThis.p_timerCallback();}, this.p_interval );
};

tkutils.Timer.prototype.stop = function()
{
	if (this.p_cookie !== -1)
	{
		window.clearInterval( this.p_cookie );
		this.p_cookie = -1;		
	}
};

tkutils.Timer.prototype.p_timerCallback = function()
{
	if (!this.isRunning())
	{
		return; // timer was already stopped
	}
	
	try
	{
		this.p_callbackFn.apply(this.p_callee, [this]);
	}
	catch (ex)
	{
	    // TODO - may want to somehow log this error, for now just stop
	    this.stop();
	}
	
	if (!this.isRunning())
	{
		return; // timer was stopped in callback method
	}
	
	this.p_repeatCount++;
	if (this.p_maxRepeatCount !== -1 && this.p_repeatCount >= this.p_maxRepeatCount)
	{
		this.stop();
	}
};

///////////////////////////////////////////////////////////////////////////////
// End of File
///////////////////////////////////////////////////////////////////////////////
