//
// Environment object (holds information about the browser, and OS)
//
function Environment()
{   
	// convert all characters to lowercase to simplify testing
    var agt = navigator.userAgent.toLowerCase();

   	//
	// Browser version.
	//
    this.major = parseInt(navigator.appVersion); //~~
    this.minor = parseFloat(navigator.appVersion); //~~

    this.nav  = ((agt.indexOf('mozilla') != -1) && ((agt.indexOf('spoofer') == -1) //~~
                && (agt.indexOf('compatible') == -1)));
    this.nav2 = (this.nav && (this.major == 2)); //~~
    this.nav3 = (this.nav && (this.major == 3)); //~~
    this.nav4 = (this.nav && (this.major == 4)); //~~
    this.nav4up = (this.nav && (this.major >= 4)); //~~
    this.navonly = (this.nav && (agt.indexOf(";nav") != -1)); //~~

    this.ie   = (agt.indexOf("msie") != -1); //~~
    this.ie3  = (this.ie && (this.major == 2)); //~~
    this.ie4  = (this.ie && (this.major == 4)); //~~
    this.ie4up  = this.ie  && (this.major >= 4); //~~

    this.opera = (agt.indexOf("opera") != -1); //~~

	//
	// Determine Javascript version.
	//
	this.js; //~~

	if (this.nav2 || this.ie3)
		this.js = 1.0;
	else if (this.nav3 || this.opera) 
		this.js = 1.1;
	else if (this.nav4 || this.ie4) 
		this.js = 1.2;
	else if ((this.nav && (this.minor > 4.05)) || (this.ie && (this.major > 4))) 
		this.js = 1.2;
	else 
		this.js = 0.0;

	//
	// The platform the browser is running on.
	//
	this.platform;

	if (this.js >= 1.2)
		this.platform = navigator.platform.toLowerCase();
}


//
// Global environment object that holds some environmental information.
//

//
// Global variables.
//
var g_debug = true;				// Debug mode
var g_dc;						// Debug console
var g_env = new Environment();	// Environment object

var g_usejar = true;			// Java applet will come from a JAR file (to be enabled in production)
var g_loggedin = false;

function errorHandler(message, url, line) // Log errors
{
	AppLog(message + ' in ' + url + ' (line ' + line + ')');
	return true;
}


function clickHandler(e)
{
	var message = "Powered by GlobeinvestorGOLD.";

	if (document.all)
	{
		if (event.button == 2)
		{
			alert(message);
			return false;
		}
	}
	
	if (document.layers)
	{
		if (e.which == 3)
		{
			alert(message);
			return false;
		}
	}
}

//!if (document.layers)
//!	document.captureEvents(Event.MOUSEDOWN);



//
// Message constants.
//
//
// Please note that the following list should be in sync with the
// Java version in fc.client.applets.base.UIMsg class.
//
var UIM_NOTHING				= 0x10000000;	// Test message
var UIM_SHOWNEWS			= 0x10000001;	// Show news message
var UIM_SHOWNEWSITEM		= 0x10000002;	// Show news item message
var UIM_SHOWCHARTS			= 0x10000004;	// Show charts message
var UIM_SHOWURL				= 0x10000008;	// Show URL
var UIM_SHOWWLIST			= 0x10000010;	// Show watchlist
var UIM_SHOWWLISTEX			= 0x10000020;	// Show extended watchlist
var UIM_SHOWQUOTE			= 0x10000040;	// Show quote
var UIM_SHOWALERTS			= 0x10000080;	// Show alerts
var UIM_SHOWICHART			= 0x10000100;	// Show interactive chart
var UIM_SHOWINDICES1		= 0x10000200;	// Show indices in p1
var UIM_SHOWINDICES2		= 0x10000400;	// Show indices in p2
var UIM_SHOWVIDEO			= 0x10000800;	// Show video
var UIM_SHOWLEVEL2			= 0x10001000;	// Show level II
var UIM_SHOWOPTIONS			= 0x10002000;	// Show Options

//
// Global message constants (messages sent to all views).
//
var UIM_APPLEVEL			= 0x20000000;	// A global message
var UIM_APPINIT				= 0x20000001;	// FCCApp is initialized
var UIM_APPLOGINSUCCESS		= 0x20000002;	// Login succeeded
var UIM_APPLOGINFAILURE		= 0x20000004;	// Login failed
var UIM_APPRECONNFAILURE	= 0x20000008;	// Reconnection failed
var UIM_APPDISCONNECTED		= 0x20000010;	// Got disconnected (comm failure)
var UIM_APPSBOUNCE			= 0x20000020;	// The user to be bounced softly?
var UIM_APPHBOUNCE			= 0x20000040;	// The user to be bounced hardly?
var UIM_APPSHUTDOWN			= 0x20000080;	// The app will shutdown
var UIM_APPREFRESH			= 0x20000100;	// The app will refresh its cache
var UIM_APPREFRESHED		= 0x20000200;	// The app refreshed its cache
var UIM_ALERTPOPUP			= 0x20000400;	// Alert popup message
var UIM_ALERTFLASH			= 0x20000800;	// Alert flash message
var UIM_CFGINDICES			= 0x20001000;	// Open indices configuration popup
var UIM_CFGTICKER			= 0x20002000;	// Open ticker configuration popup
var UIM_PERMCHANGED			= 0x20004000;	// Permissions have changed
var UIM_APPSETFOCUS			= 0x20008000;	// Application window to set focus to itself
var UIM_APPKILL				= 0x20010000;	// Application to kill itself
var UIM_CFGLEVEL2			= 0x20020000;	// Open Level II configuration page
var UIM_APPSHOWLEVEL2		= 0x20040000;	// Show the one and only level II applet
var UIM_CFGTOS				= 0x20080000;	// Config TOS
var UIM_CFGCSTUDY			= 0x20100000;	// Config chart study
var UIM_MSGBOX				= 0x20200000;	// Show message box
var UIM_APPSHOWOPTIONS		= 0x20400000;	// Show the one and only options applet
var UIM_SAVEPREFS			= 0x20800000;	// Saves preferences
var UIM_SHOWUPSELL			= 0x21000000;	// Show upsell

var MSG_ERRSUFFIX			= 24;
var MSG_LOGINSTR			= 25;
var MSG_TOOMANYCOMPS		= 26;

//
// View types
//
var	VT_HTML					= 0;	// HTML content makes up the view
var VT_APPLET			    = 1;	// An applet makes up the view


//
// View activation types.
//
// Please note that this list should be in sync with the one defined
// in fc.client.applets.base.AppletBase.java
//
var AT_USER				= "0";	// View was activated by the user
var AT_MSG				= "1";	// View was activated due to UI message
var AT_DETACH			        = "2";	// View was activated due to a detach

//
// Preference names.
//
var PREF_DEFVIEW		= "defview";	// Default
var PREF_CODEBASE		= "codebase";	// Default


//
// Global functions
//

//
// ::GetMsgMan() -- Return the one and only MsgMan instance
//
function GetMsgMan()
{
	alert("GetMsgMan called");
	return null;

	if (top.name == "FCCMain")
	{
		if (typeof(top.app) != 'undefined' && top.app != null)
			return top.app.msgman;
	}
		
	if (top.opener.top.name == "FCCMain")
	{
		if (typeof(top.opener.top.app) != 'undefined')
			return top.opener.top.app.msgman;
	}

	return null; // Can't find it
}


//
// ::GetPref() -- Return JS preferences
//
function GetPref()
{
	var pref = eval("window.pref");
	if (pref == null && eval("top.opener") != null)
		pref = eval("top.opener.pref"); // Try the opener
	
	return pref;
}


//
// ::getUserPrefObj() -- Return user preferences
//
function getUserPrefObj()
{
	var app = GetApp();

	if (app != null)
		return app.getUserPref();

	return null; // Can't find it
}



//
// ::getAppletByID() -- Return an applet instance given its ID
//
function getAppletByID(id)
{
	var app = GetApp();

	if (app != null)
		return app.getAppletByID(id);

	return null; // Can't find it
}



//
// ::getGlobalPref() -- Return a global preference value
//
function getGlobalPref(param)
{
	var pref = getUserPrefObj();

	if (typeof(pref) != 'undefined' && pref)
		return pref.getGlobalPref(param);
	
	return "";
}


//
// ::GetApp() -- Return the one and only FCCApp instance
//
function GetApp()
{
	if (window.document.applets[0] != "undefined" && window.document.applets[0] != null)
		return window.document.applets[0].getFCCApp();
	
	return null; // Can't find it!
}

//
// ::GetAppHTML() -- Return the one and only app.htm document
//
function GetAppHTML()
{
	if (top && top.app)
		return top.app;

	if (top.opener && top.opener.top)
		return top.opener.top.app;
	
	return null; // Can't find it!
}


function setDomain()
{

	var dmn = window.document.domain;	
	var newdmn = "";
	var dmnarray;
	
	dmnarray = dmn.split(".");
	if (dmnarray.length > 1)
	{
		newdmn += dmnarray[dmnarray.length - 2];
		newdmn += "."
	}
	newdmn += dmnarray[dmnarray.length -1];
	window.document.domain = newdmn;			
}


function getRootDomain()
{

	var dmn = window.document.domain;	
	var newdmn = "";
	var dmnarray;
	
	dmnarray = dmn.split(".");
	if (dmnarray.length > 1)
	{
		newdmn += dmnarray[dmnarray.length - 2];
		newdmn += "."
	}
	newdmn += dmnarray[dmnarray.length -1];
	return newdmn;			
}


//
// PreView() -- Returns the start of a view HTML document
//
function PreView(name)
{
	var color = GetPref().m_bgcolor;

	var start = '<body bgcolor="' + color + '" text="#FFFFFF" link="#FFFFFF" vlink="#FFFFFF" alink="#FFFFFF" topmargin="0" leftmargin="0" marginheight="0" marginwidth="0" ';

	if (typeof(name) != 'undefined' && name.length != 0)
		start += 'onload=\'if(typeof(parent) != "undefined" && typeof(parent.vm) != "undefined")parent.vm.OnViewLoaded("' + name + '");\'>';
	else
		start += '>';

	//~ add other events/attrs...

	return start;
}


//
// PreAds() -- 
//
function PreAds()
{
	setDomain();
	var color = GetPref().m_bgcolor;
	var start;
	start = '<body topmargin="0" leftmargin="0" class="vGlobal" link="#FFFFFF" vlink="#FFFFFF" alink="#3399FF" target="_blank" bgcolor="' + color + '"';
	start += '>';

	//~ add other events/attrs...
	
	return start;
}


//
// PreCPanel() -- 
//
function PreCPanel()
{
	setDomain();
	var color = GetPref().m_bgcolor;

	var start;
	start = '<body bgcolor="' + color + '" onload="preloadImages()" topmargin="0" leftmargin="0" marginwidth="0" marginheight="0" ';
	start += '>';

	//~ add other events/attrs...
	
	return start;
}


//
// PreAlertPopup() -- 
//
function PreAlertPopup()
{
	setDomain();
	var color = GetPref().m_bgcolor;

	var start;
	start = '<body bgcolor="' + color + '" topmargin="0" leftmargin="0" marginwidth="0" marginheight="0" ';
	start += '>';

	//~ add other events/attrs...
	
	return start;
}


//
// WritePreView() -- Output start of a view's HTML document
//
function WritePreView(name)
{
	setDomain();
	if (typeof(parent) != "undefined" && typeof(parent.vm) != "undefined")
		if (parent.vm.OnViewLoading(name))
			document.writeln(PreView(name));
}


//
// StartApplet() -- Output applet tag, and add globaly used parameters
//
function StartApplet(view, name, width, height, code, nojpref)
{
	var applet = "";
	var pane = "";

	var codebase = GetPref().m_codebase;
	var arc =GetPref().m_archive;

	if (g_env.nav)
	{
		//applet = '<applet codebase="' + codebase + '" code="' + code + '" name="' + name +'" archive="' + arc + '" width="' + width + '" height="' + height + '">';
		applet = '<applet code="' + code + '" name="' + name +'" archive="' + arc + '" width="' + width + '" height="' + height + '" MAYSCRIPT>';
		applet += '<param name="msgman" value="GetMsgMan()">';
		applet += '<param name="quimsgs" value="true">';
	}
	else
	{
		//applet = '<applet codebase="' + codebase + '" code="' + code + '" name="' + name +'" archive="' + arc + '" width="' + width + '" height="' + height + '" MAYSCRIPT>';
		applet = '<applet code="' + code + '" name="' + name +'" archive="' + arc + '" width="' + width + '" height="' + height + '" MAYSCRIPT>';
		applet += '<param name="msgman" value="GetMsgMan()">';
		applet += '<param name="quimsgs" value="true">';
	}

	applet += '<param name="pane" value="' + pane + '">';
	applet += '<param name="view" value="' + view + '">';
	
	if (typeof(nojpref) != 'undefined' && nojpref) // Don't get params from preferences?
	{
		applet += '<param name="bgwindow" value="' + GetPref().m_appletbgcolor + ' ">';
		applet += '<param name="fgwindow" value="' + GetPref().m_appletfgcolor + ' ">';
	}
	
	document.write(applet);
}


//
// ::gpParam() -- Construct a parameter from global prefernces
//
function gpParam(pref, name)
{
	return '<param name="' + name + '" value="' + pref.getUIPref(name) + ' ">';
}

//
// AddParam() -- Adds a parameter tag
//
function AddParam(name, value)
{
	document.writeln('<param name="' + name + '" value="' + value + '">');
}


//
// EndApplet() -- Close applet tag
//
function EndApplet()
{
	document.writeln("</applet>");
}


//
// StartDiv() -- Outputs a section either using <div> or <layer>
//
function StartDiv(left, top, width, height, rel)
{
	var div;

	if (g_env.nav && g_env.nav4)
	{
		var layer;
		if (typeof(rel) == 'undefined' || rel == false)
			layer = "<LAYER";
		else
			layer = "<ILAYER";

		div = layer + ' left=' + left + ' top=' + top + ' width=' + width + ' height=' + height + '">';
	}
	else
	{
		var relation;
		if (typeof(rel) == 'undefined' || rel == false)
			relation = "absolute";
		else
			relation = "relative"

		div = '<div align=left style="position:' + relation + '; ';
		div += 'left:' + left + '; ';
		div += 'top:' + top + '; ';
		div += 'width:' + width + '; ';
		div += 'height:' + height + '; ';
		
		div += '">';
	}

	document.writeln(div);
}


//
// EndDiv() -- Closes a <div>/<layer> section
//
function EndDiv(rel)
{
	if (g_env.nav && g_env.nav4)
	{
		var layer;
		if (typeof(rel) == 'undefined' || rel == false)
			div = "</LAYER>";
		else
			div = "</ILAYER>";
	}
	else
	{
		div = '</div>';
	}

	document.writeln(div);
}


//
// AppLog() -- Log a message
//
function AppLog(msg)
{
	var app = GetApp();
	if (app)
		app.log(msg);
	else
		alert("unable to log message: " + msg);
}


//
// GetWindowWidth() -- Return width of the window
//
function GetWindowWidth(wnd)
{
	if (g_env.ie)
		return wnd.document.body.offsetWidth;

	return wnd.outerWidth;
}


//
// GetWindowHeight() -- Return height of the window
//
function GetWindowHeight(wnd)
{
	if (g_env.ie)
		return wnd.document.body.offsetHeight;

	return wnd.outerHeight;
}


//
// Returns window x position on screen.
//
function getWindowX(wnd)
{
	if (g_env.ie)
		return (wnd.screenLeft);
	return wnd.screenX;
}


//
// Returns window y position on screen.
//
function getWindowY(wnd)
{
	if (g_env.ie)
		return (wnd.screenTop); // - doc.body.scrollTop);
	return wnd.screenY;
}


//
// GetClientWidth() -- Return width of the client area of a window
//
function GetClientWidth(wnd)
{
	if (g_env.ie)
		return wnd.document.body.clientWidth;

	var nsscrollwidth = 15;
	return wnd.innerWidth;// - nsscrollwidth;
}


//
// GetClientHeight() -- Return height of the client area of a window
//
function GetClientHeight(wnd)
{
	if (g_env.ie)
		return wnd.document.body.clientHeight;

	var nsscrollwidth = 15;
	return wnd.innerHeight;// - nsscrollwidth;
}

function URLEncode(plaintext)
{
	// The Javascript escape and unescape functions do not correspond
	// with what browsers actually do...
	var SAFECHARS = "0123456789" +					// Numeric
					"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic
					"abcdefghijklmnopqrstuvwxyz" +
					"-_.!~*'()";					// RFC2396 Mark characters
	var HEX = "0123456789ABCDEF";

	var encoded = "";
	for (var i = 0; i < plaintext.length; i++ ) {
		var ch = plaintext.charAt(i);
	    if (ch == " ") {
		    encoded += "+";				// x-www-urlencoded, rather than %20
		} else if (SAFECHARS.indexOf(ch) != -1) {
		    encoded += ch;
		} else {
		    var charCode = ch.charCodeAt(0);
			if (charCode > 255) {
			    alert( "Unicode Character '" 
                        + ch 
                        + "' cannot be encoded using standard URL encoding.\n" +
				          "(URL encoding only supports 8-bit characters.)\n" +
						  "A space (+) will be substituted." );
				encoded += "+";
			} else {
				encoded += "%";
				encoded += HEX.charAt((charCode >> 4) & 0xF);
				encoded += HEX.charAt(charCode & 0xF);
			}
		}
	} // for

	return encoded;
}

function URLDecode(encoded)
{
   // Replace + with ' '
   // Replace %xx with equivalent character
   // Put [ERROR] in output if %xx is invalid.
   var HEXCHARS = "0123456789ABCDEFabcdef"; 
   
   var plaintext = "";
   var i = 0;
   while (i < encoded.length) {
       var ch = encoded.charAt(i);
	   if (ch == "+") {
	       plaintext += " ";
		   i++;
	   } else if (ch == "%") {
			if (i < (encoded.length-2) 
					&& HEXCHARS.indexOf(encoded.charAt(i+1)) != -1 
					&& HEXCHARS.indexOf(encoded.charAt(i+2)) != -1 ) {
				plaintext += unescape( encoded.substr(i,3) );
				i += 3;
			} else {
				alert( 'Bad escape combination near ...' + encoded.substr(i) );
				plaintext += "%[ERROR]";
				i++;
			}
		} else {
		   plaintext += ch;
		   i++;
		}
	} // while
   
   return plaintext;
}

function getDomain()
{
	var pathname = window.document.location.pathname;
	var path = pathname.split("/");
	var shortpath = "";
	
	for (var i = 0; i < path.length-1; i++)
	{
		shortpath += path[i] + "/";
	}
		
	return document.location.host + 
			shortpath.substring(0,shortpath.length-1); 
}

//
// CreatePopupWindow() -- Create a popup window
//
function CreatePopupWindow(url, name, width, height, resizable, centered, scrollbars, proxybaseurl)
{
	//
	// Use the 'launchpopup' page to force the window to focus
	//
	if (typeof(proxybaseurl) != 'undefined' && proxybaseurl != "")
	{
		var index;
		index = url.indexOf("?");
			
		if (index > 0)
			url = 'launchpopup.htm?url=' + url + "&proxybaseurl=" + URLEncode(proxybaseurl);
		else
			url = 'launchpopup.htm?url=' + url + "?proxybaseurl=" + URLEncode(proxybaseurl);
	}
	else
		url = 'launchpopup.htm?url=' + url;

	//
	// Calc position (center window).
	//
	var x = (screen.availWidth - width) / 2;
	var y = (screen.availHeight - height) / 2;

	//
	// Reset position if user requested not to center.
	//
	if (typeof(centered) != 'undefined' && centered == false)
	{
		x = 0;
		y = 0;
	}

	var wndopts = "toolbar=0,height=" + height + ",width=" + width + ",menubar=0";
	
	if (typeof(resizable) != 'undefined' && resizable == false)
		wndopts += ",resizable=0";
	else
		wndopts += ",resizable=1";
	
	if (typeof(scrollbars) != 'undefined' && scrollbars == false)
		wndopts += ",scrollbars=0";
	else
		wndopts += ",scrollbars=1";

	if (g_env.nav)
		wndopts += ",screenX=" + x + ",screenY=" + y;
	else
		wndopts += ",left=" + x + ",top=" + y;

	var wnd = window.open(url, name, wndopts);

	//
	// Register window so that it is automatically closed on app shut down
	// ! currently disabled because array may get too large
	// ! app = GetAppHTML();
	// ! app.regPopUps(wnd);
	
	return wnd;
}


//
// Recreates a popup window using saved size and position preferences.
//
function recreatePopupWindow(href, name, detachpref, resizable, scrollbars)
{
	//
	// detachparams is expected to have the format "height,width,xpos,ypos"
	//
	detachparams = detachpref.split(",");
	if (detachparams.length != 4)
		return null;

	var h = detachparams[0];
	var w = detachparams[1];
	var x = detachparams[2];
	var y = detachparams[3];

	var wndopts = "toolbar=0,height=" + h + ",width=" + w + ",menubar=0";
	
	if (typeof(resizable) != 'undefined' && resizable == false)
		wndopts += ",resizable=0";
	else
		wndopts += ",resizable=1";
	
	if (typeof(scrollbars) != 'undefined' && scrollbars == false)
		wndopts += ",scrollbars=0";
	else
		wndopts += ",scrollbars=1";

	if (g_env.nav)
		wndopts += ",screenX=" + x + ",screenY=" + y;
	else
		wndopts += ",left=" + x + ",top=" + y;

	var wnd = window.open(href, name, wndopts);
	return wnd;
}


function DetachCentered(applet, useviewsize)
{
	if (typeof(applet) != "undefined")
	{
		//
		// Calc position (center window).
		//
		var w;
		var h;

		if (useviewsize && useviewsize == true)
		{
			w = GetWindowWidth(window) + 20;
			h = GetWindowHeight(window) + 20;

		}
		else
		{
			w = applet.getSize().width;
			h = applet.getSize().height;
		}


		var x = (screen.availWidth - w) / 2;
		var y = (screen.availHeight - h) /2;

		return applet.detach(x, y, w, h);
		
	}

	return false;
}


//
// CreateOverlappedWindow() -- Create a popup window
//
function CreateOverlappedWindow(url, name, width, height)
{
	//
	// Calc position (center window).
	//
	var x = (screen.availWidth - width) / 2;
	var y = (screen.availHeight - height) /2;

	var wndopts = "toolbar=1,height=" + height + ",width=" + width + ",menubar=1,resizable=1,scrollbars=1";
	
	if (g_env.nav)
		wndopts += ",screenX=" + x + ",screenY=" + y;
	else
		wndopts += ",left=" + x + ",top=" + y;

    return window.open(url, name, wndopts);
}


//
// View class
//


//
// ViewClone() -- Clone a view
//
function ViewClone()
{
	//
	// Clone self without messages.
	//
	return new View(this.m_name, this.m_imgactive.src, this.m_imginactive.src, 
		this.m_imgdisabled.src, this.m_srcfile, 0);
}


//
// VCreateNewApplet() -- Creates a new applet
//
function VCreateNewApplet(panename, x, y, w, h, param1, param2)
{
	if (typeof(this.m_appcreator) == "undefined" || this.m_appcreator == null)
		return;
	this.m_appcreator.launchApplet(this.m_appletclass, x, y, w, h, param1, param2);
}


//
// View::View() -- Constructor
//
function View(vm, name, type, appletclass, img_active_src, img_inactive_src, img_disabled_src, srcfile, messages, sendinplace, showexternal)
{
    this.m_name = name;	// View name
	this.m_type = type; // View type

	if (sendinplace && sendinplace == true)
		this.m_cansendinplace = sendinplace; // Temp, should be configurable
	else
		this.m_cansendinplace = false;
    
	this.m_imgactive = new Image();
	this.m_imgactive.src = img_active_src;

	this.m_imginactive = new Image();
	this.m_imginactive.src = img_inactive_src;

	this.m_imgdisabled = new Image();
	this.m_imgdisabled.src = img_disabled_src;

    this.m_srcfile = srcfile; // Content source
	this.m_msgs = messages; // Messages we're interested in

	if (showexternal && showexternal == true)
		this.m_external = true;
	else
		this.m_external = false;

	//
	// Only one message will be queued for the view.
	//
	this.m_curmsg = null; // Current message queued

	//
	// Each view will be given the chance to serialize its state in
	// any view-defined object before it is destroyed. And then when
	// the view becomes active again, it can restore itself.
	//
	this.m_state = null;
	this.m_appstates = new Array();

	this.m_appletclass = appletclass;
	this.m_appcreator = null;

	// 
	// An applet based view will have its own applet creator
	//
	if (this.m_type == VT_APPLET)
	{
		this.m_appcreator = GetApp().getAppletCreator();
		
		//
		// Initialize the commonly used parameters upfront.
		//
		this.m_appcreator.addParam("msgman", "GetMsgMan()");
		this.m_appcreator.addParam("pane", vm.m_name);
		this.m_appcreator.addParam("view", this.m_name);
		this.m_appcreator.addParam("bgcolor",  GetPref().m_appletbgcolor);

		if (g_env.nav)
			this.m_appcreator.addParam("quimsgs", "true");
		else
			this.m_appcreator.addParam("quimsgs", "true");

		if (typeof(nojpref) != 'undefined' && nojpref) // Don't get params from preferences?
		{
			this.m_appcreator.addParam("bgwindow", GetPref().m_appletbgcolor);
			this.m_appcreator.addParam("fgwindow", GetPref().m_appletfgcolor);
		}
	}

	//
	// Methods.
	//
	this.Clone = ViewClone;
	this.createNewApplet = VCreateNewApplet;
	this.onMessage = null;
}


//
// ViewMan::SetFramePath() -- Set the frame path
//
function SetFramePath(fpath)
{
    this.fpath = fpath;
}


//
// ViewMan::AddView() -- Add a view
//
function AddView(view)
{
    this.m_views[this.m_views.length] = view;

	//
	// Subscribe to the message(s), if applicable.
	//
	if (view.m_msgs != 0 && this.m_msgman)
	{
		if (this.fpath)
			container = this.fpath + "." + this.m_container.name;
		else
			container = this.m_container.name;
	}

	//
	// If we were cloned, copy the view's state and any pending message.
	//
	if (this.m_cloned && this.m_origvmc && !this.m_origvmc.closed && typeof(this.m_origvmc.vm) != 'undefined')
	{
		var pview = this.m_origvmc.vm.GetView(this.m_views.length - 1);

		if (pview)
		{
			view.m_state = pview.m_state; // Copy state
			view.m_curmsg = pview.m_curmsg; // Copy pending message
		}
	}
}


function GetActive()
{
    if (this.m_current >= 0)
        return this.GetView(this.m_current);

    return null;
}


function GetView(index)
{
	if (index < 0 || index > this.m_views.length)
        return null;	
    return this.m_views[index];
}


function GetViewIndex(name)
{
	for (var i = 0; i < this.m_views.length; i++)
	{
		if (this.m_views[i].m_name == name)
			return i;
	}
    
	return -1; // No such view
}


function SetActive(index)
{
	if (index < 0 || index > this.m_views.length)
        return false;

	if (this.m_current >= 0)
	{
		var pold = this.GetView(this.m_current);
		var vwnd = this.GetViewFrame();		

		if (this.HasTabsFrame())
			this.SetTabInactive(this.m_current);

		//
		// Let the current view serialize its state (if applicable).
		//
		if (pold && vwnd && pold.m_type == VT_APPLET && !pold.m_external) // Only serialize internal views
		{
			for (var i = 0; i < vwnd.document.applets.length; i++)
			{
				if (vwnd.document.applets[i] && vwnd.document.isLoaded)
					pold.m_appstates[i] = vwnd.document.applets[i].jsSave();
			}

			//
			// Ask the page to save its state.
			//
			if (vwnd.OnSave)
				pold.m_state = vwnd.OnSave(getUserPrefObj());
		}
	}
	if (this.HasTabsFrame() && !this.SetTabActive(index))
        return false;

	
	this.m_current = index;

    //
    //~ Render the tab.
    //
    var frame = this.GetViewFrame();
    var view = this.GetView(index);

	if (frame && view)
		frame.location.replace(view.m_srcfile);	

	return true;
}

function GetFrame(name)
{
    return /*parent.*/frames[name];
}

function GetTabsFrame()
{
    if (this.m_tabsframe && this.m_tabsframe.length > 0)
		return GetFrame(this.m_tabsframe);

	return null;
}

function GetViewFrame()
{
    return GetFrame(this.m_viewframe);
}

function GetTabImage(index)
{
    if (index < 0 || index >= this.m_views.length)
        return null;

    return this.GetTabsFrame().document.images[this.GetView(index).m_name];
}


//
// Activates the specified tab
//
function SetTabActive(index)
{
    if (index < 0 || index >= this.m_views.length)
        return false;

    var view = this.m_views[index];

    if (view)
    {
		var frame = this.GetTabsFrame();
		if (typeof(frame) != 'undefined' && frame && typeof(frame.changeImages) != 'undefined')
			frame.changeImages(view.m_name, view.m_imgactive.src);

        return true;
    }

    return false;
}


function SetTabInactive(index)
{
    if (index < 0 || index >= this.m_views.length)
        return false;

    var view = this.m_views[index];

    if (view)
    {
		var frame = this.GetTabsFrame();
		if (typeof(frame) != 'undefined' && frame && typeof(frame.changeImages) != 'undefined')
			frame.changeImages(view.m_name, view.m_imginactive.src);
        return true;
    }

    return false;
}


function SetTabDisabled(index)
{
    if (index < 0 || index >= this.m_views.length)
        return false;

    var view = this.m_views[index];

    if (view)
    {
		this.GetTabsFrame().changeImages(view.m_name, view.m_imgdisabled.src);
        return true;
    }

    return false;
}


function Clone(override)
{
	if (!this.m_container)
        return null;

	var pview = null;

	if (override && override > -1)
	{
		this.m_override = override;
		pview = this.GetView(override);
	}
	else
	{
		//
		// Let the current view serialize its state (if applicable).
		//
		var pcur = this.GetView(this.m_current);
		var vwnd = this.GetViewFrame();

		if (pcur && !pcur.m_external && vwnd)
		{
			//
			// First, let the view handle the cloning, if it doesn't then
			// we'll do the cloning ourselves.
			//
			if (typeof(vwnd.OnClone) != 'undefined' && vwnd.OnClone() == true)
				return null; // The view took care of cloning
			
			if (pcur.m_type == VT_APPLET)
			{
				//
				// Ask applets to save their state.
				//
				for (var i = 0; i < vwnd.document.applets.length; i++)
					pcur.m_appstates[i] = vwnd.document.applets[i].jsSave();
			}
	
			//
			// Ask the page to save its state.
			//
			if (vwnd.OnSave)
				pcur.m_state = vwnd.OnSave(getUserPrefObj());
		}
		
		pview = pcur;
	}

	var width = GetWindowWidth(this.m_container);
	var height = GetWindowHeight(this.m_container);
	

	var href = this.m_container.location.href;
	var name = "_blank";
	
	/*
	if (pview != null)
	{
		href = pview.m_srcfile;
		name = pview.m_name;
	}
	*/

	//
	// Check to see whether the view to be cloned has a detached window location/size saved.
	//
	if (pview != null)
		var detachpref = "" + getUserPrefObj().getDetachPref(pview.m_name);
	if (detachpref && detachpref.length > 0)
		var wnd = recreatePopupWindow(href, name, detachpref, true, true);	
	else
		var wnd = CreatePopupWindow(href, name, width, height);	

	if (vwnd && vwnd.PostClone && typeof(vwnd.PostClone) != 'undefined')
		vwnd.PostClone(wnd);
	return wnd;
}


//
// GetPathElement() --
//
function GetPathElement(path, index)
{
	if (typeof(path) == 'undefined' || !path)
		return "";

	var arrstr = path.split(".");

	if (arrstr && arrstr.length >= 2)
		return arrstr[index];
	
	return;
}


//
// ParsePane()
//
function ParsePane(path)
{
	return GetPathElement(0);
}


//
// ParseView()
//
function ParseView(path)
{
	return GetPathElement(1);
}


//
// VMOnMessage() -- ViewMan message handler
//
function VMOnMessage(sender, msg, param1, param2, forceview, newwnd)
{
    for (var i = 0; i < this.m_views.length; i++)
	{
		if ((this.m_views[i].m_msgs & msg) != msg)
			continue; // The view is not interested in the msg

		//
		// Queue the message for the view.
		//
		var pview = this.GetView(i);

		if (pview.onMessage && pview.onMessage(sender, msg, param1, param2, forceview, newwnd))
			return; // If the view object handles the message and returns true we stop here.

		//
		//~ For messages that come from the same pane, we will clone the view
		// and send the message to the cloned one.
		//
		if (ParsePane(sender) == this.m_name)
		{
			//
			// Only clone the view if the sender doesn't allow sending
			// messages inplace (to the same pane).
			//
			var psender = null;
			var index = this.GetViewIndex(ParseView(sender));
			
			if (index >= 0)
				psender = this.GetView(index);

			if (psender != null && !psender.m_cansendinplace)
				newwnd = true; // Force cloning the view
		}

		pview.m_curmsg = new UIMsg(msg, param1, param2);

		if (newwnd && newwnd == true) // Activate the view in a new window?
		{
			var w = GetWindowWidth(window) + 20;
			var h = GetWindowHeight(window) + 20;
			var x = (screen.availWidth - w) / 2;
			var y = (screen.availHeight - h) / 2;

			//
			// For views of type VT_APPLET, activate them by cloning.
			//
			if (pview.m_type == VT_APPLET && pview.m_appcreator && pview.m_appletclass.length > 0)
			{
				pview.createNewApplet(this.m_name, x, y, w, h, param1, param2);
				return;
			}
			else // All other view types will be activated by cloning
			{
				if (msg == UIM_SHOWURL)
					top.frames.app.popupURL(pview.m_name, param1, x, y, w, h);
				else
					this.Clone(i); // Clone and activate the specified view

				return true;
			}
		}

		//
		// Notify the view to check its message if it is active,
		// otherwise activate it if the caller requested activation.
		//
		if (i == this.m_current)
		{
			if (pview.m_external)
			{
				//
				// For external views, if the message is UIM_SHOWURL, then
				// handle it here, otherwise don't do anything.
				//
				if (msg == UIM_SHOWURL)
				{
					var vwnd = this.GetViewFrame();
					if (vwnd)
						vwnd.location.replace(param1);
				}
			}
			else
			{
				var vwnd = this.GetViewFrame();
				if (vwnd && vwnd.OnMessage)
					vwnd.OnMessage(msg, param1, param2);
			}
		}
		else if (forceview)
			this.SetActive(i); // Activate the view if requested
	}
}

//
// ViewMan::saveState() - Save the state for this view
//
function saveState(viewname, state)
{
	var view = this.GetView(this.GetViewIndex(viewname));	
	view.m_state = state;	
}

//
// ViewMan::getState() - Retrieve the state for this view
//
function getState(viewname)
{
	var view = this.GetView(this.GetViewIndex(viewname));
	return view.m_state;
}


//
// ViewMan::VMOnViewLoading() -- View is loading
//
function VMOnViewLoading(from)
{
	//
	// If it's the empty page, then load the default one.
	//
	if (!this.m_cloned && (typeof(from) == 'undefined' || !from || from.length == 0))
		from = this.getPref(PREF_DEFVIEW);
	
	var index = this.GetViewIndex(from);

	//
	// If the loaded page is not the same as the current active page
	// (probably because we were just displayed), then activate the 
	// current view.
	//
	if (index != this.m_current /*|| this.m_cloned == true*/)
	{
		var toset;
		//
		// Queue the call to be called soon, to avoid the problem
		// of replacing a page due to a call from inside it.
		//
		if (this.m_current >= 0)
			toset = this.m_current;
		else if (index >= 0)
			toset = index;

		if (this.SetActive(toset))
			return false;
	}

	return true;
}


//
// ViewMan::VMOnViewLoaded() -- View was successfuly loaded
//
function VMOnViewLoaded(from)
{
	//
	// If it's the empty page, then load the default one.
	//
	//!if (!this.m_cloned && (typeof(from) == 'undefined' || !from || from.length == 0))
		//!from = this.getPref(PREF_DEFVIEW);

	var index = this.GetViewIndex(from);

	if (index >= 0)
	{
		//
		// If the loaded page is not the same as the current active page
		// (probably because we were just displayed), then activate the 
		// current view.
		//
		if (index != this.m_current)
		{
			//
			// Queue the call to be called soon, to avoid the problem
			// of replacing a page due to a call from inside it.
			//
			//!setTimeout("vm.SetActive(" + (this.m_current >= 0 ? this.m_current : index) + ")", 10);
			return;
		}

		var pview = this.GetView(index);
		if (pview)
		{
			var vwnd = this.GetViewFrame();
			vwnd.document.isLoaded = true;
			
			//
			// Restore view's state, if it previously saved it.
			//
			if (pview.m_state)
			{
				if (vwnd && vwnd.OnRestore)
					vwnd.OnRestore(pview.m_state, getUserPrefObj());
			}

			
			//
			// For applet type views, call their set() method.
			//
			if (pview.m_type == VT_APPLET)
			{
				var papp = vwnd.document.applets[0];
				if (papp && !pview.m_curmsg)
				{
			
					if (pview.m_appstates.length > 0)
						papp.set5("", "", "", AT_USER, pview.m_appstates[0]);
					else
						papp.set5("", "", "", AT_USER, null);
				}			
			}


			if (pview.m_appstates.length > 0) // Did we previously store some applet's state?
			{
				/*for (var i = 0; i < vwnd.document.applets.length; i++)
				{
					//
					// Ask applets that implement the JSSerializable interface
					// to restore their state.
					//
					if (typeof(vwnd.document.applets[i].JSOnRestore) != "undefined")
						vwnd.document.applets[i].JSOnRestore(pview.m_appstates[i]); //!
				}*/
			}
			/*else // Otherwise it's the first time this page is displayed
			{
				//
				// For VT_APPLET type views, ask the applets to load themselves.
				//
				if (pview.m_type == VT_APPLET)
				{
					for (var i = 0; i < vwnd.document.applets.length; i++)
					{
						if (typeof(vwnd.document.applets[i].JSOnLoad) != "undefined")
							vwnd.document.applets[i].JSOnLoad();
					}
				}
			}*/
			
			if (eval(vwnd.onPageLoaded))
				vwnd.onPageLoaded();

			//
			// Update the preferences.
			//
			if (!this.m_cloned)
				this.setPref(PREF_DEFVIEW, pview.m_name);

			//
			// Route any pending messages to the view.
			//
			if (pview.m_curmsg)
			{
				/*if (pview.m_type == VT_APPLET)
				{
					app.set2(pview.m_curmsg.param1, pview.m_curmsg.param2);
				}
				else*/ if (vwnd && vwnd.OnMessage)
				{
					vwnd.OnMessage(pview.m_curmsg.m_msg, pview.m_curmsg.m_param1, pview.m_curmsg.m_param2);
					delete pview.m_curmsg;
				}
			}
		}

		return true;
	}
}


//
// ViewMan::VMsetViewPref() -- Sets a preference inside the pane.view preferences
//
function VMsetViewPref(view, name, value)
{
	if (typeof(name) == 'undefined' || !name || name.length == 0)
		return;

	var param;
	param = this.m_name;

	//
	// Add the view to the path (if provided).
	//
	if (view != null && view.length != 0)
		param += "." + view;

	var pref = getUserPrefObj();

	if (pref != null)
		pref.set(param, name, value);
}


//
// ViewMan::VMsetPref() -- Sets a preference inside the pane's preferences
//
function VMsetPref(name, value)
{
	this.setViewPref("", name, value);
}


//
// ViewMan::VMgetViewPref() -- Gets a value from the pane.view preferences
//
function VMgetViewPref(view, name)
{
	var value = "";

	if (typeof(name) == 'undefined' || !name || name.length == 0)
		return;

	var param;
	param = this.m_name + ".";

	//
	// Add the view to the path (if provided).
	//
	if (view != null && view.length != 0)
		param += view + ".";

	param += name;

	var pref = getUserPrefObj();

	if (pref != null)
		value = pref.get(param);

	return value;
}


//
// ViewMan::VMgetPref() -- Gets a value from the pane's preferences
//
function VMgetPref(name)
{
	return this.getViewPref("", name);
}


//
// ViewMan::HasTabsFrame() -- Return whether the view man has a tab frame
//
function HasTabsFrame()
{
	return this.m_tabsframe && this.m_tabsframe.length ? true : false;
}


//
// ViewMan::Register() -- Register with MsgMan
//
function VMRegister()
{
	//
	// Don't register if we are cloned.
	//~ This should be changed to register only for app level messages
	//
	if (this.m_cloned)
		return false; // For now, we won't register cloned windows, review

	var msgman = GetMsgMan();

	if (typeof(msgman) != 'undefined' && msgman)
		return msgman.RegisterViewMan(this);
}


//
// ViewMan::Unregister() -- Unregister with MsgMan
//
function VMUnregister()
{
	if (this.m_cloned)
		return false; //! Cloned windows are not registered (review)

	var msgman = GetMsgMan();

	if (typeof(msgman) != 'undefined' && msgman)
		return msgman.UnregisterViewMan(this);
}


//
// ViewMan::ShowContent() -- Show the provided content
//
function ShowContent(cnt)
{
    var frame = this.GetViewFrame();

    if (frame)
        frame.document.write(cnt);
}


//
// ViewMan class
//
function ViewMan(name, tabs_frame, view_frame)
{
	this.m_id = -1;	// ID controlled by MsgMan

    this.m_name = name;
	this.m_tabsframe = tabs_frame;
    this.m_viewframe = view_frame;
    this.m_views = new Array();
    this.m_container = window;

    this.m_fullscreen = false;
	this.m_override = -1;

    //
    // This class represents a cloned (Detached) pane if we were
    // opened from a window with ViewMan instance running.
    // 
    //
    if (opener && typeof(opener.vm) != 'undefined' && opener.vm)
    {
		this.m_cloned = true;
		this.m_origvmc = opener; // keep a reference to the original
		this.m_msgman = null;

		if (opener.vm.m_override && opener.vm.m_override > -1)
		{
			this.m_current = opener.vm.m_override;
			opener.vm.m_override = -1; // Reset the override
		}
		else
			this.m_current = opener.vm.m_current;
    }
    else
    {
		this.m_cloned = false;
		this.m_origvmc = null;
		this.m_msgman = top.app.msgman;
	
		this.m_current = -1;
	}

    this.SetFramePath = SetFramePath;
    this.AddView = AddView;
    this.SetActive = SetActive;    
    this.GetActive = GetActive;
    this.GetView = GetView;
    this.GetViewIndex = GetViewIndex;
    this.Clone = Clone;
    
    this.GetFrame = GetFrame;
    this.GetTabsFrame = GetTabsFrame;
    this.GetViewFrame = GetViewFrame;
    
    this.GetTabImage = GetTabImage;
    this.SetTabActive = SetTabActive;
    this.SetTabInactive = SetTabInactive;
    this.SetTabDisabled = SetTabDisabled;

	this.HasTabsFrame = HasTabsFrame;

	this.Register = VMRegister;
	this.Unregister = VMUnregister;
	
	this.ShowContent = ShowContent;

    //
	// UI message handler.
	//
	this.OnMessage = VMOnMessage;

	//
	// Notifications from the views.
	//
	this.OnViewLoaded = VMOnViewLoaded;
	this.OnViewLoading = VMOnViewLoading;

	this.saveState = saveState;
	this.getState = getState;

	//
	// Preference related methods.
	//
	this.setViewPref = VMsetViewPref;
	this.getViewPref = VMgetViewPref;
	this.setPref = VMsetPref;
	this.getPref = VMgetPref;

	//
	// Get the initial view to display
	//
	this.m_default = this.getPref(PREF_DEFVIEW);
}


//
// ::trace() -- output the properties of the provided object
//
function trace(obj)
{
	if (!g_debug)
		return false;

	var msg;
    msg += typeof obj;

    for (i in obj)
        msg += i + " --> " + typeof(i) + " --> " + obj[i] + "<BR>\n";
    
	alert(msg);
	return true;
}



//
// MsgMan class
//


//
// MsgMan::SendMessage() -- Send a message
//
function SendMessage(sender, msg, param1, param2, forceview, newwnd)
{
    //
	// Send the message to all non-detached view managers, and let them
	// decide whether to handle them or not (including app
	// level messages).
	//
	for (var i = 0; i < this.m_vms.length; i++)
	{
		var vmc = this.m_vms[i];
		if (vmc != null && !vmc.closed && typeof(vmc.vm) != 'undefined' && !vmc.vm.m_cloned)
			vmc.vm.OnMessage(sender, msg, param1, param2, forceview, newwnd);
    	}

	//
	// Handle application level messages after being handled by 
	// all the view managers.
	//
	if ((UIM_APPLEVEL & msg) == UIM_APPLEVEL)
	{
		if (msg == UIM_CFGTICKER)
		{
			window.configTicker();			
		}
		else if (msg == UIM_CFGCSTUDY)
		{
			configChart(param1, getParamValue(param2, "sid"), getParamValue(param2, "sname"), getParamValue(param2, "help"));
		}
		else if (msg == UIM_MSGBOX)
		{
			top.app.msgBox(param1);
		}
		else if (msg == UIM_ALERTFLASH)
		{
			if (typeof(top.views) != 'undefined' && typeof(top.views.bottom) != 'undefined' &&
				typeof(top.views.bottom.cpanel) != 'undefined' &&
					typeof(top.views.bottom.cpanel.playAlert) != 'undefined')
				top.views.bottom.cpanel.playAlert(param1);
		}
		else if (msg == UIM_ALERTPOPUP)
		{
			var width = 420;
			var height = 250; // Assume tallest window
			if (typeof(param2) != "undefined")
			{
				if (param2 == "1")
					height = 100; // Small
				else if (param2 == "2")
					height = 150; // Medium
			}

			var cmd = "CreatePopupWindow('alertpopup.htm?msg=" + escape(param1) + "', 'alertpopup', " + width + ", " + height + ", false, true, false)";
			setTimeout(cmd, 1);
		}
		else if (msg == UIM_APPHBOUNCE || msg == UIM_APPSBOUNCE || msg == UIM_APPSHUTDOWN)
		{
			//
			// Display the message to the user and exit.
			//
			alert(param1);
			//!setTimeout("top.close()", 1); // Close the app
		}
		else if (msg == UIM_APPREFRESH)
		{
			var page = '<html>';
			page +=	PreView();
			page += '<center>Please wait while we refresh...</center>';
			page += '<scr' + 'ipt>top.app.document.fccapp.refresh();</scr' + 'ipt>';
			page += '</body></html>';
			parent.views.document.write(page);
		}
		else if (msg == UIM_APPREFRESHED || msg == UIM_APPINIT)
		{
			if (typeof(top.views) != 'undefined' && top.views != null)
				top.views.initViews();
		}
		else if (msg == UIM_APPLOGINSUCCESS) // Login succeeded
		{
			g_loggedin = true;
		}
		//	
		// Login failed, unable to reconnect, or got disconnected
		//
		else if (msg == UIM_APPLOGINFAILURE || msg == UIM_APPRECONNFAILURE || msg == UIM_APPDISCONNECTED)
		{
			/*var sendlog = confirm(param1 + getErrMsgStr(MSG_ERRSUFFIX));
			if (sendlog)
				createHTMLLog(false);
			else
				setTimeout("top.close()", 1); // Close the app*/

			//
			// Display an error message to the user and exit.
			//
			alert(param1 + getErrMsgStr(MSG_ERRSUFFIX));
			//!setTimeout("top.close()", 1); // Close the app

		}
		else if (msg == UIM_APPSETFOCUS)
		{
			setTimeout("top.focus()", 1); // Set the focus
		}
		else if (msg == UIM_APPKILL)
		{
			setTimeout("top.close()", 1); // Close the app
		}
	}
}



//
// MsgMan::RegisterViewMan() -- Register a ViewMan
//
function RegisterViewMan(vm)
{
	var id = this.m_vms.length;
	this.m_vms[this.m_vms.length] = vm.m_container;
	vm.m_id = id;

	return true;
}


//
// MsgMan::UnregisterViewMan() -- Unregister a ViewMan
//
function UnregisterViewMan(vm)
{
	var id = vm.m_id;

	if (id > -1)
	{
		this.m_vms[id] = null;
		vm.m_id = -1;
	}

	return true;
}


//
//
//
function MMCleanup()
{
	//
	// Close all opened vm windows.
	//
	for (i = 0; i < this.m_vms.length; i++)
	{
		var vmc = this.m_vms[i];
		if (vmc != null && !vmc.closed)
			vmc.close();

		/*var vm = this.m_vms[i];
		if (vm != null && typeof(vm.m_container) != 'undefined' && vm.m_container)
			vm.m_container.close();*/
	}
}


//
// MsgMan -- Constructor
//
function MsgMan(viewsframepath)
{
    this.m_vsfpath = viewsframepath;	// Views frame path
	this.m_vms = new Array();			// Array of registered views

	this.RegisterViewMan = RegisterViewMan;
	this.UnregisterViewMan = UnregisterViewMan;
    this.SendMessage = SendMessage;
	this.cleanup = MMCleanup;
}


//
// UIMsg
//
function UIMsg(msg, param1, param2)
{
	this.m_msg = msg;
	this.m_param1 = param1;
	this.m_param2 = param2;
}

//
// Creates image object
//
function newImage(arg) {
	if (document.images) {
		rslt = new Image();
		rslt.src = arg;
		return rslt;
	}
}

//
// Returns an error message related string.
//
function getErrMsgStr(id)
{
	var str = "";
	var app = GetApp();
	if (app)
		str = app.getString(id);

	return "\n" + str;
}

/*
//
// Swaps image in place
//
function changeImages(img, img2) {
	if (document[img])
	{		
		document[img].src = img2;
	}	
}
*/

/*
//
// Updates the list select with the latest Stocklists and Portfolios
//
function updateListSelect(appletname)
{
	var app = GetApp();
	var stocklistNames = new Array();
	var stocklistIDs = new Array();
	var portfolioNames = new Array();
	var portfolioIDs = new Array();
	sCount = app.getStockListCount();
	pCount = app.getPortfolioCount();
	for (i = 0; i < sCount; i++)
	{
		stocklistNames[i] = app.getStockListName(i);
		stocklistIDs[i] = app.getStockListID(i);
	}
	for (i = 0; i < pCount; i++)
	{
		portfolioNames[i] = app.getPortfolioName(i);
		portfolioIDs[i] = app.getPortfolioID(i);
	}
	document.listform.listselect.length = sCount + pCount;
	for (i = 0; i < sCount; i++)
	{
		document.listform.listselect.options[i].text = stocklistNames[i];
		document.listform.listselect.options[i].value = stocklistIDs[i];
	}
	for (i = 0; i < pCount; i++)
	{
		document.listform.listselect.options[i + sCount].text = portfolioNames[i];
		document.listform.listselect.options[i + sCount].value = portfolioIDs[i];	
	}		
}

//
// Resets the list select's index to the state prior to addition/deletion of options
//
function resetselect(initial)
{
	for (i = 0; i < document.listform.listselect.length; i++)
	{
		if (document.listform.listselect.options[i].value == initial)
		{
			document.listform.listselect.selectedIndex = i;
			break;
		}
	}			
}


//
// Prompts the applet (specified by appletname) to update its list
//
function getNewList(appletname)
{
	index = document.listform.listselect.selectedIndex;
	
	if (typeof(index) != "undefined" && index && index >= 0)
		document[appletname].setWatchList(document.listform.listselect.options[index].value);
}   

//
// Function specific to pages displaying the watchlist applet.  Updates the list-select and
// the list displayed by the applet.
//
function processListChange(msg, param1, param2, appletname)
{
	var index = document.listform.listselect.selectedIndex;		
	var initial = document.listform.listselect.options[index].value;
	if (param1 == "add")
	{
		updateListSelect();
		// set back to old list
		resetselect(initial);
	}
	else if (param1 == "del")
	{
		updateListSelect();
		if (param2 == initial)
		{
		document.listform.listselect.selectedIndex = 0;
			getNewList(appletname);
		}
		else
			resetselect(initial);
	}
	else if (param1 == "chg")
	{
		updateListSelect()
		if (initial == param2)
		getNewList(appletname);
	}		
}
*/

//
// Returns the value of a prameter embedded in a URL
//
function getParamValue(myURL, param)
{
	var query = myURL.split('?');
	if (query.length < 2)
		return '';
	
	var pairs = query[1].split('&');
	for (i = 0; i < pairs.length; i++)
	{
		var assignment = pairs[i].split("=");
		if (assignment.length == 2 && assignment[0] == param)
			return unescape(assignment[1]);
	}

	return '';
}

//
// Creates the specified cookie
//
function createCookie(name, value, days)
{
	var expires = "";

	if (days)
	{
		var date = new Date();
		date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
		expires = "; expires=" + date.toGMTString();
	}

	//!document.cookie = name + "=" + value + expires + "; path=/";
	//!document.cookie = name + "=" + value + expires + ";path=/; domain=." + getRootDomain();
	document.cookie = name + "=" + value + expires + "; domain=." + getRootDomain();
}

//
// Returns the value of a parameter embedded in a cookie
//
function getCookieValue(cookie, paramname)
{
	var fields = cookie.split(";");

	if (fields.length > 0)
	{
		for (var i = 0; i < fields.length; i++)
		{
			var pair = fields[i].split("=");

			if (pair.length == 2)
			{
				if (pair[0].indexOf(paramname) >= 0)
					return pair[1];
			}
		}
	}

	return ""
}


//
// showMsgBox()
//
function showMsgBox(name, title, msg, timeout)
{
	//~ To be implemented	
}


//
// testBit() -- Tests if <bit> exists in <v> (binary check)
//
function testBit(v, bit)
{
	return (v & bit) == bit;
}


function showUpsellMsg()
{
	CreatePopupWindow('feature.htm', '', '260', '120', false, true, false);
}

//
// createHTMLLog() -- creates a HTML popup with the current contents of the log.
//
function createHTMLLog(debug)
{
	CreatePopupWindow('log.htm?debug=' + (debug? 'true' : 'false'), 'Log', '560', (debug? '260' : '390'), false, true, true);
}

// config view activation flags
var SHOW_L2		= 0x10000001;	// Enable LEVEL2 config view
var SHOW_TOS	= 0x10000002;	// Enable TOS config view
var SHOW_MM	= 0x10000004;	// Enable Market Meter config view

// The delimiter for the params
var DELIM = "\x01";

//
// Chart studies configuration pages (views).
//
var CFGVID_CSMA				= 0x00000004;	// Moving average
var CFGVID_CSEMA			= 0x00000008;	// Exp. moving average
var CFGVID_CSBOLLINGER		= 0x00000010;	// Bollinger bands
var CFGVID_CSMOMENTUM		= 0x00000020;	// Momentum
var CFGVID_CSVOLATILITY		= 0x00000040;	// Volatility
var CFGVID_CSRSI			= 0x00000080;	// RSI
var CFGVID_CSMACD			= 0x00000100;	// MACD
var CFGVID_CSSTOCHASTIC		= 0x00000200;	// Stochastic
var CFGVID_CSWILLIAMS		= 0x00000400;	// Williams
var CFGVID_CSOBV			= 0x00000800;	// OBV
var CFGVID_CSMAE			= 0x00001000;	// Moving average envelope
var CFGVID_CSVOLUME			= 0x00002000;	// Volume
var CFGVID_CSROC			= 0x00004000;	// Rate of change
var CFGVID_CSVOLACC			= 0x00008000;	// Volume accumulation
var CFGVID_CSPRICECHANNEL	= 0x00010000;	// Price channel
var CFGVID_CSVOLUMEPLUS		= 0x00020000;	// Volume plus
var CFGVID_CSMONEYFLOW		= 0x00040000;	// Money flow
var CFGVID_CSULTIMOSC		= 0x00080000;	// Ultimate oscillator
var CFGVID_CSDMI			= 0x00100000;	// DMI
var CFGVID_CCOMPARE			= 0x00200000;	// Compare with...
var CFGVID_CSSAR			= 0x00400000;	// Parabolic SAR




//
// Chart studies config tab names.
//
var CFGVNAME_CSMA			= "Moving average";
var CFGVNAME_CSEMA			= "Exp moving average";
var CFGVNAME_CSBOLLINGER	= "Bollinger bands";
var CFGVNAME_CSMOMENTUM		= "Momentum";
var CFGVNAME_CSVOLATILITY	= "Volatility";
var CFGVNAME_CSRSI			= "RSI";
var CFGVNAME_CSMACD			= "MACD";
var CFGVNAME_CSSTOCHASTIC	= "Stochastic";
var CFGVNAME_CSWILLIAMS		= "Williams";
var CFGVNAME_CSOBV			= "OBV";
var CFGVNAME_CSMAE			= "Moving average envelope";
var CFGVNAME_CSVOLUME		= "Volume";
var CFGVNAME_CSROC			= "Rate of change";
var CFGVNAME_CSVOLACC		= "Volume accumulation";
var CFGVNAME_CCOMPARE		= "Compare";
var CFGVNAME_CSPRICECHANNEL	= "Price channel";
var CFGVNAME_CSVOLUMEPLUS	= "Volume+";
var CFGVNAME_CSMONEYFLOW	= "Money flow";
var CFGVNAME_CSULTIMOSC		= "Ultimate oscillator";
var CFGVNAME_CSDMI			= "Average Directional Movement Index";
var CFGVNAME_CSSAR			= "Parabolic SAR";

//
// Chart studies parameters.
//
var CFGP_WINSIZE	= "winsize";	// Window size (periods?)
var CFGP_SHADEABOVE	= "shadeabove";	//
var CFGP_SHADEBELOW = "shadebelow"; //
var CFGP_FASTWIN	= "fastwin";	//
var CFGP_SLOWWIN	= "slowwin";	//
var CFGP_EMAWIN		= "emawin";		//
var CFGP_KWIN		= "kwin";		//
var CFGP_SMOOTHWIN	= "smoothwin";	//
var CFGP_DWIN		= "dwin";		//
var CFGP_ENVELOPE	= "envelope";	//
var CFGP_WINSIZE1	= "winsize1";	// Window size (periods)
var CFGP_WINSIZE2	= "winsize2";	// Window size (periods)
var CFGP_WINSIZE3	= "winsize3";	// Window size (periods)
var CFGP_AF			= "af";			 
var CFGP_MAXAF		= "maxaf";		 

var CFGP_COMPARETO	= "compareto";	//
var CFGP_COMPARISONINDICES = "compareindices";

// configuration set types
var CFGSET_L2THEMES = "l2themes";
var CFGSET_TOSTHEMES = "tosthemes";
var CFGSET_MMTHEMES = "mmthemes";

//
// names for each config view
//
var LEVEL2ID = "l2";
var TOSID = "tos";
var METERID = "meter";

// names for the LEVEL2 PARAMS
var SHOWQUOTE = "showquote";
var AGGVOL = "aggvol";
var SUPCLOSEDMPIDS = "supclosedmpids";
var MONMPIDS = "monmpids";
var L2THEME = "tctheme";
var EXCHGID = "exchgid";
var SIZEINLOTS = "sizeinlots";

// names for the TOS PARAMS
var INSERTTOP = "tos.inserttop";
var GROUPBYTIME = "tos.groupbytime";
var SHOWSECONDS = "tos.showseconds";
var SHOWANNOT = "tos.showannotations";
var SHOWTOS = "showtos";
var TOSTHEME = "tos.theme";

// names for the MARKET METER PARAMS
var MMHISTORY = "marketmeter.mmhistory";
var SHOWMETER = "showmeter";
var MMTHEME = "marketmeter.theme";

// Exchange IDs
var EXCHGID_NASDAQ = 0;

var TRUE = 1;
var FALSE = 0;

function configChart(appid, sid, sname, help)
{
	var enabled = 0;
	var w = 310;
	var h = 145;
	var title = "Configure Study";

	if (sid == -1)
	{
		enabled = CFGVID_CCOMPARE; // Comparison page
		title = "Edit Chart Comparison";
		h = 300;
		page = "help_tracker_charts_comparing.html";
	}
	else if (sid == -2)
	{
		page = "help_tracker_charts.html";
	}
	else if (sname == "MOVINGAVERAGE")
	{
		enabled = CFGVID_CSMA;
		page = "help_tracker_edit_averages.html";
	}
	else if (sname == "EXPMOVINGAVERAGE")
	{
		enabled = CFGVID_CSEMA;
		page = "help_tracker_edit_averages.html";
	}		
	else if (sname == "BOLLINGERBANDS")
	{
		enabled = CFGVID_CSBOLLINGER;
		page = "help_tracker_edit_bollinger.html";
	}
	else if (sname == "MOMENTUM")
	{
		enabled = CFGVID_CSMOMENTUM;
		page = "help_tracker_edit_momentum.html";
	}
	else if (sname == "VOLATILITY")
	{
		enabled = CFGVID_CSVOLATILITY;
		page = "help_tracker_edit_volatility.html";
	}
	else if (sname == "RSI")
	{
		enabled = CFGVID_CSRSI;
		h = 280;
		page = "help_tracker_edit_rsi.html";
	}		
	else if (sname == "MACD")
	{
		enabled = CFGVID_CSMACD;
		h = 300;
		page = "help_tracker_edit_macd.html";
	}
	else if (sname == "STOCHASTIC")
	{
		enabled = CFGVID_CSSTOCHASTIC;
		h = 300;
		page = "help_tracker_edit_oscillator.html";
	}		
	else if (sname == "MOVINGAVERAGEENVELOPE")
	{
		enabled = CFGVID_CSMAE;
		h = 225;
		page = "help_tracker_edit_mae.html";
	}
	else if (sname == "ULTIMOSC")
	{
		enabled = CFGVID_CSULTIMOSC;
		h = 300;
		page = "help_tracker_edit_ultimosc.html";
	}
	else if (sname == "WILLIAMS")
	{
		enabled = CFGVID_CSWILLIAMS;
		page = "help_tracker_edit_williams.html";
	}
	else if (sname == "OBV")
	{
		enabled = CFGVID_CSOBV;
		page = "help_tracker_edit_obv.html";
	}
	else if (sname == "VOLUME")
	{
		enabled = CFGVID_CSVOLUME;
		page = "help_tracker_edit_volume.html";
	}
	else if (sname == "ROC")
	{
		enabled = CFGVID_CSROC;
		page = "help_tracker_edit_roc.html";
	}
	else if (sname == "VOLACC")
	{
		enabled = CFGVID_CSVOLACC;
		page = "help_tracker_edit_volacc.html";
	}
	else if (sname == "PRICECHANNEL")
	{
		enabled = CFGVID_CSPRICECHANNEL;	
		page = "help_tracker_edit_pricechannel.html";
	}
	else if (sname == "PRICEBYVOLUME")
	{
		page = "help_tracker_edit_pbvol.html";
	}
	else if (sname == "VOLUMEPLUS")
	{
		enabled = CFGVID_CSVOLUMEPLUS;
		page = "help_tracker_edit_volume.html";
	}
	else if (sname == "MONEYFLOW")
	{
		enabled = CFGVID_CSMONEYFLOW;
		page = "help_tracker_edit_moneyflow.html";
	}
	else if (sname == "DMI")
	{
		enabled = CFGVID_CSDMI;
		page = "help_tracker_edit_dmi.html";
	}
	else if (sname == "SAR")
	{
		enabled = CFGVID_CSSAR;
		h = 180;
		page = "help_tracker_edit_sar.html";
	}
	
	if (help == "true")
	{
		var base = "http://gold.globeinvestor.com/public/help/popup/"; //!GetApp().getChartHelpURL();			
		CreatePopupWindow(base + page, "Help", 340, 350, true, true, true);
	}
			
	else if (enabled != 0)
		CreatePopupWindow("cfg.htm?aid=" + appid + "&en=" + enabled + "&ctx1=" + sid + "&ctx2=" + sname + "&title=" + escape(title),
			"ChartConfig", w, h, false, true, false);
}

function setConfigEx(id, params, values, delimiter, ctxid1, ctxid2)
{
	var applet = getAppletByID(id);
	if (applet != null)
	{
		var ps = params.split(delimiter);
		var vs = values.split(delimiter);

		//
		// Construct a string with the format p1=v1;p2=v2..
		//
		var paramstr = "";
		for (var i = 0; i < ps.length; i++)
		{
			if (i > 0)
				paramstr += delimiter;

			paramstr += ps[i] + "=" + vs[i];

		}
			
		applet.setConfigValuesEx(paramstr, delimiter, ctxid1, ctxid2);
		return true;
	}

	return false;
}

function getConfigEx(id, params, delimiter, ctxid1, ctxid2, def)
{
	var applet = getAppletByID(id);
	if (applet != null)
		return applet.getConfigValuesEx(params, delimiter, ctxid1, ctxid2, def);
	return "";
}

	function doAppletCommand(id, cmd, params, sep)
	{
		var applet = getAppletByID(id);
		if (applet != null)
			return applet.doCommand(cmd, params, sep);

		return false;
	}
