/****************************************************************
Global vars
****************************************************************/
var g_inputParams=null;
var g_winName=null;

//left/top, right/bottom: 2 diagnonally opposite anchor objects to resize panels
var g_ltAnchor, g_rbAnchor;
var g_body;
var g_commandSet=null;

//constants
var LOGIN	= "Login";
var LOGINFAILED="LoginFailed";
var CHANGEPASSWORD="ChangePassword";
var PASSWORDCHANGED="PasswordChanged";
var DEFAULT="Default";
var MAINVIEW="MainView";
var FULLSCREEN="FullScreen";
var REPORT="Report";
var REPORTSELECTOR="ReportSelector";
var REPORTVIEW="ReportView";
var YES=1, NO=0;

/****************************************************************
Utilities
****************************************************************/

//Ah hah, to defined or not defined...That is the question!!!
function isUndef (o) { return typeof(o) == 'undefined' || o === '' || o == null }
function isDef(o){return!isUndef(o)};
function unDef(o) {return typeof(o)=='undefined';}

//cache of element refs
var m_elemRefCache=new Array();
function elemRef(id) {
	var ret=m_elemRefCache[id];
	if(ret==null) {
		m_elemRefCache[id]=window.document.getElementById(id);
		ret=m_elemRefCache[id];
	}
	return ret;
};
	

function fatalError(msg) {
	alert("Fatal Error:" + msg);
};

function msgBox(msg) {
	alert(msg);
};

window.onerror= function (sMsg,sUrl,sLine) {
	fatalError("Fatal Error:" + sMsg + "\nUrl: " + sUrl + "\nLine: " + sLine);
};

function ASSERT(condition) {
	try {
		if(!condition)
			alert("Assertion failed:  in function " + ASSERT.caller);
	} catch(e) {
	}
};
	
function setStatus(msg) {
	window.status=msg;
};

function onLoad() {
	fatalError("Tuan: Have you forgotten to handle the 'onload' event?");
};

function onLoadApp(winName) {

	if(isDef(winName)) {
		window.name=winName;
		
		g_body = new elemObj("bodyId");
		
	//TODO: Need to nudge dynamically!
	//Comment these 2 lines out to use default app dimension of 1024x768.
	//Uncomment to maximize app according to user's screen
	//	g_body.W(window.screen.availWidth - 24/**/);
	//	g_body.H(window.screen.availHeight -28/**/);
		
	} else {
		fatalError("Tuan: winName not defined for this page!");
	}
};


function ckKey(key) {
	return "ck"+key;
}
	
//save the given value which can be looked up later using given key
function storeKeyValue(key, value) {
	var now = new Date();
	var KEY=ckKey(key);
	if(!isDef(value)) {
		document.cookie = KEY + "=" + "; expires=" + now.toGMTString() ;
	} else {
		value=escape(value);
		//I think I'll be wandering somewhere in hell by the time this cookie get stale!
		document.cookie = KEY + "=" + value + "; expires=Thursday, 31-Dec-2099 12:00:00 GMT";
	}
}

//lookup the value previously saved under given key
function retrieveKeyValue(key) {
	var ret=null;
	var KEY=ckKey(key);
	var ck=document.cookie;
	if(isDef(ck)) {
		ret=findCookieValue(KEY, ck);
	}
	return ret;
};


function deleteKeyValue(key) {
	storeKeyValue(key, null)
};

//Parse given cookie string and return value of given key
function findCookieValue(key, ckStr) {
	var ret=null;
	var arr1=ckStr.split(";");	//splitted into arrays of "key=value" string
	for(var x=0; x<arr1.length; ++x) {	//parse each string for the key then get the value
		var arr2=arr1[x].split("=");
		if(arr2[0].trim()==key) {
			ret=isDef(arr2[1])? unescape(arr2[1]):null;
			break;
		}
	}
	return ret;
};

  
/*Return true if given object is an empty string, blank or null
*/
function isEmpty(str) {
	var v=str;
	v=v.trim();
	return (v.length>0)? false:true;
};


/*trim off leading/trailing blank
*/
String.prototype.trim = function() {
   return this.replace(/(^\s*)|(\s*$)/g, "");
};


/*
Return value of given input paramter. Return empty string if not defined
*/
function getInputParam(key) {

	var ret="";
	if(isUndef(g_inputParams)) {
		//Extract the search params from a URL into an array of key1/value1, key2/value2 etc...
		var arr=new Array();
		var str=window.document.location.search;
		if(str) {
			str=decodeURIComponent(str);
			str = "&" + str.substr(1);
			var expr=/\&([^=]+)=([^&]+)(.*)$/
			expr.compile; 
			while(expr.test(str)) {
				arr.push(str.replace(expr, "$1"));
				arr.push(str.replace(expr, "$2"));
				str=str.replace(expr, "$3");
			}
		}
		g_inputParams=arr;
	}

	//Return the value associated with the key
	var n =g_inputParams.length;
	for(var x=0; x<n; x+=2) {
		if(g_inputParams[x] == key) {
			ret= g_inputParams[x+1];
			//g_inputParams.splice(x, 2);
			break;
		}
	}
	
	return ret;
};


//launch  a page in an optional window name
function launch(strUrl, winName, features, replace) {
	var url=strUrl;
	var name=isDef(winName)?  winName:"_self";
	if(unDef(features)) features="";
	if(unDef(replace)) replace=true;
	var w=window.open(url, name, features, replace);
	return w;
};


function buildCommandSet() {
	try {
		var doc = new ActiveXObject("MSXML2.DOMDocument.3.0");
		doc.async = false;
		if (doc.load("main.aspx?data=commandset")) {
			g_commandSet=doc.documentElement.selectSingleNode("commandset");
		}
	} catch (e) {
		fatalError(e);
	}
	return g_commandSet!=null;
};

function getCommand(cmd) {
	var ret=null;
	if(isDef(g_commandSet)) {
		ret=g_commandSet.getAttribute(cmd);
	}
	return ret;
};


//Return xsl doc
var g_xslCache=null;
function getXslDoc(xslUrl) {
	if(g_xslCache==null) {
		g_xslCache=new Array();
	}
	var ret=g_xslCache[xslUrl];
	if(ret==null) {
		ret = new ActiveXObject("MSXML2.FreeThreadedDOMDocument.3.0");
		ret.async = false;
		if (ret.load(xslUrl)) {
			g_xslCache[xslUrl]=ret;
		} else ret=null;
	}
	return ret;
};

//return an xslt processor for given xsl template
var g_xslProcessor=null;
function getXslProcessor(xslUrl) {
	var ret=null;
	var xsl = getXslDoc(xslUrl);
	if (xsl!=null) {
		if(g_xslProcessor==null) {
			g_xslProcessor = new ActiveXObject("MSXML2.XSLTemplate.3.0");
		}
		g_xslProcessor.stylesheet = xsl;
		ret = g_xslProcessor.createProcessor();
	}
	return ret;
};

//transform given xmldoc into another doc using given xslt processor
function doc2DOM(xmlDoc, processor) {
	var ret= null;
	if(processor!=null) {
		ret=new ActiveXObject("MSXML2.DOMDocument.3.0");
		processor.input = xmlDoc;
		processor.output = ret;
		processor.transform();	//do it!
	}
	return ret;
};

function transform(xmlDoc, xslUrl) {
	var processor=getXslProcessor(xslUrl);
	var ret=doc2DOM(xmlDoc, processor);
	return ret;
};


/****************************************************************
Base classes
****************************************************************/

/*class pointObj*/ {
	function pointObj(x, y) {
		this.x=x;
		this.y=y;
	}
};

/*class elemObj*/ {
	//elemObj.base = Object.prototype;
	function elemObj(id) {
		var t=this;
		if(isDef(id)) {
			t.e=elemRef(id);	//for quick access
			t.s=t.e.runtimeStyle;
		}
	};
	elemObj.prototype = new Object();
	elemObj.constructor = elemObj;
		
	var cls = elemObj.prototype;
	
	//access the element behind this object
	cls.elem = function() {return this.e;}
	
	//save current states
	cls.saveCoordinates = function() {
		var t=this;
		try {
			t.iL=t.L();
			t.iT=t.T();
			t.iW=t.W();
			t.iH=t.H();
		} catch(e) {
			fatalError("Tuan: Something wrong in saveCoordinates()");
		} finally {
		}
	};
	
	//method to set, retrieve object location (left, top) and size (width, height)
	cls.L = function(v) {
		var t=this;
		if(isDef(v)) {
			t.s.left=v;
		}
		var ret=t.s.left;
		return isDef(ret)? parseInt(ret): t.e.offsetLeft;
	};

	cls.T = function(v) {
		var t=this;
		if(isDef(v)) {
			t.s.top=v;
		}
		var ret=t.s.top;
		return isDef(ret)? parseInt(ret): t.e.offsetTop;
	};
		
	cls.W = function(v) {
		var t=this;
		if(isDef(v) && v>=0) {
			t.s.width=v;
		}
		var ret=t.s.width;
		return isDef(ret)? parseInt(ret): t.e.offsetWidth;
	};
	cls.H = function(v) {
		var t=this;
		if(isDef(v) && v>=0) {
			t.s.height=v;
		}
		var ret=t.s.height;
		return isDef(ret)? parseInt(ret): t.e.offsetHeight;
	};
	
	//NOTE: show, hide will affect both visibility and display dynamic attributes
	cls.visible = function(v) {
		var t=this;
		if(isDef(v)) {
			t.s.visibility = v? "visible":"hidden";
			t.s.display = v? "block":"none";
		}
		return (t.s.visibility != "hidden") && t.display !="none";
	};
	
	
	cls.maximize = function() {
		var t=this;
		//left, top
		t.L(g_ltAnchor.x);
		t.T(g_ltAnchor.y);
		
		//width, height
		t.W(g_rbAnchor.x - g_ltAnchor.x);	//width=right-left
		t.H(g_rbAnchor.y - g_ltAnchor.y);	//height=bottom-top
	}
	
};	/*class elemObj*/


/*class formObj:*/ {
	//Not really a form but just to conveniently process a form members
	function formObj(id) {
		this.base = elemObj;
		this.base(id);
	};
	formObj.prototype = new elemObj();
	formObj.constructor = formObj;
		
	var cls = formObj.prototype;
	
	//set focus to given item
	cls.focus = function(id) {
		this.e.item(id).focus();
	}
	
	//return true if value of given item is empty
	cls.isEmpty=function(id) {
		var v=this.e.item(id).value;
		return isEmpty(v);
	}
	
	//set or get the value of given item
	cls.value=function(id, newValue) {
		if(!unDef(newValue)) {
			this.e.item(id).value=newValue;
		}
		return this.e.item(id).value;
	}
	
	//return true if given item is checked
	cls.isChecked=function(id) {
		return this.e.item(id).checked? true:false;
	}
	
	//check/uncheck
	cls.check=function(id, bCheck) {
		this.e.item(id).checked=bCheck? true:false;
	}
};

/****************************************************************
Overrides: overriding offending stuffs from CodeThat controls
****************************************************************/
try {
	var CT_IMG_BLANK = "res/1x1.gif";
	//override to write cookie to local jar. Otherwise a big tree would choke the server, resulting in a session loss!
	var m_cookieJar=new Array();
	CodeThat.readCookie = function(name) {
		return m_cookieJar[name];
	}
	CodeThat.writeCookie = function (name, val, exp) {
		m_cookieJar[name]=val;
	}
} catch(e) {};

