var Ary = {
	add: function(a,o){a[a.length]=o;},
	addAll: function(a,a2){if(a)for(var i=0;i<a2.length;i++)a[a.length]=a2[i];},
	insert: function(a,p,o) {
		if(p<0)p=0;if(p>a.length)p=a.length;
		for(var i=a.length;i>p;i--)a[i]=a[i-1];
		a[p]=o;
	},
	remove: function(a,p) {
		if(p==-1||!a||a.length<=0)return null;
		var tmp=a[p];
		for(var i=p+1;i<a.length;i++)a[i-1]=a[i];
		a.length=a.length-1;
		return tmp;
	},
	indexOf: function(a,tst) {
		for(var i=0;i<a.length;i++)if(a[i]==tst)return i;
		return -1;
	}
}

var Obj = {
	count: 0,
	ects: new Object(),
	timeout: function(obj,func,time) {
		var id = toAlpha(Obj.count++);
		Obj.ects[id] = obj;
		setTimeout('Obj.cb("' + id + '","' + func + '")', time);
	},
	cb:  function(id, func) {
		var obj=Obj.ects[id];
		if (obj!=null) {
			obj[func]();
			Obj.ects[id]=null;
		}
	}
}


var Try = {
	these: function() {
		for(var i=0,a=arguments;i<a.length;i++) {
			try{ return (a[i])(); }catch(e){}
		}
		return null;
	}
}
var lary = new Array("a","b","c","d","e","f","g","h","i","j");
function toAlpha(i) {
	var s = ""+i,r="";
	for (var k=0;k< s.length;k++) r += lary[parseInt(s.charAt(k))];
	return r;
}

var empty_func = function(){};

var Ajax = {
	handlers: ['','onLoading','onLoaded','onInteractive', 'onComplete'],

	get: function(url, handler, headers) {
		return Transport.doRequest("GET", this.wipeIEsButt(url), "", headers, handler);
	},

	post: function(url, data, handler, headers) {
		return Transport.doRequest("POST", this.wipeIEsButt(url), data, headers, handler);
	},

	handshake: function(url, data, handler, headers) {
		var hs = new HandShaker(url, data, handler, headers);
		hs.request();
	},

	successCode: function(r) {
		return r.status == undefined || r.status == 0 || (r.status >= 200 && r.status < 300);
	},

	wipeIEsButt: function(url) {
		var tmp = document.location +'';
		return tmp.substring(0,tmp.indexOf('/',10)) + url;
	},

		count: time(),
	asy: new Array(),
	prime: function(obj) {
		var id = toAlpha(Ajax.count++);
		Ajax.asy[id] = obj;
		return id;
	},

	callback:  function(id, conn) {
		var obj = Ajax.asy[id];
		if (obj != null) {
			obj.callback(conn);
			Ajax.asy[id] = null;
		}
	},

	newId: function() {
		return toAlpha(Ajax.count++);
	},

	newHandshakeId: function() {
		return toAlpha(Ajax.count++);
	},

	handle: function(i,handler,conn) {
		return Try.these(function(){handler[Ajax.handlers[i]](conn);})
	},

	error: function(handler,e,conn,i) {
		return Try.these(function(){handler['onException'](e,conn,i);})
	}
}


var Transport = {
	getHTTP: function() {
		return Try.these(
			function(){ return new XMLHttpRequest() },
			function(){ return new ActiveXObject("Msxml2.XMLHTTP") },
			function(){ return new ActiveXObject("microsoft.XMLHTTP") },
			function(){ return new ActiveXObject("Msxml2.XMLHTTP.4.0") },
			function(){ return new ASVRequest() }
		);
	},

	doRequest: function(method, url, data, headers, handler) {
		headers = (headers != null) ? headers : [];
		var async = (handler&&handler.callback) ? true : false;
		var id = Ajax.prime(handler);
		var conn = this.getHTTP();

		if(handler) {
			conn.onreadystatechange = function() {
				if(conn.readyState > 0) Ajax.handle(conn.readyState, handler, conn);

				if (conn.readyState == 4) {
					Ajax.callback(id, conn);
					
					conn.onreadystatechange = empty_func;
					conn = null;
				}
			}
		}

		try{ conn.open(method, url, async); }
		catch(e) {
			Ajax.error(handler, e, conn,-1);
			return null;
		}

		for(var i=0;i < headers.length;i++) {
			conn.setRequestHeader(headers[i][0], headers[i][1]);
		}

		conn.setRequestHeader('x-ajax-reqid', Ajax.newId());
		if (method == 'POST') {
			conn.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
						data += "  ";
		}

		try {conn.send(data);}
		catch(e) {Ajax.error(handler, e, conn,-1);}
		return conn;
	}
}


function HandShaker(url, data, handler, headers) {
	this.id = Ajax.newHandshakeId();
	this.url = url;
	this.handler = handler;
	this.made = time();
	this.data = data.replace(/^\s*|\s*$/g,'') + '<=-';

	var a = new Array();
	if (headers != null) Ary.addAll(a, headers);
	Ary.add(a, ['x-ajaxhs-id', this.id]);
	Ary.add(a, ['x-ajax-cap-length', (this.data.length + '|<=-')]);

	this.headers = a;
	this.reqCount = 0;
	this.resCount = 0;

	this.request = function() {
		if (!this.start) this.start = time();
		var dif = (AjaxQueue.reqLimit - this.reqCount);
		if (!this.okd && dif > 0) {
			this.reqCount++;
			Obj.timeout(this, 'reqTimeout', AjaxQueue.reqTimer);
			Ajax.post(this.url, this.data, this, this.headers);
		}
	}
	this.fetchResponse = function() {
		if (!this.fetched) {
			this.headers[this.headers.length] = ['x-ajaxhs-emptyreq', 'true'];
			this.fetched = time();
		}
		Obj.timeout(this,'mainTimeout', AjaxQueue.resTimer);
		this.okd = time();
		Ajax.post(this.url, '', this, this.headers);
	}

	this.callback = function(resp) {
		var tmpHandle = this.handler;
				var hsRequest = Try.these(function(){return resp.getResponseHeader('x-ajaxhs-request');});
		var hsResponse = Try.these(function(){return resp.getResponseHeader('x-ajaxhs-response');});

		if ('ok' == hsRequest) {
						Ajax.handle(2, tmpHandle);
			this.fetchResponse();

		} else if ('bad' == hsRequest) {
						this.request();

		} else if (hsResponse != null) {
			if ('bound' != hsResponse && !this.done) {
								this.done = time();
				Ajax.handle(4, tmpHandle);
				if (this.injector) this.injector(this,resp);
				tmpHandle.callback(resp, this);
			}
					}
	}

	this.reqTimeout = function() {
		if (!this.destroyed && !this.okd && !this.done) this.request();
	}

	this.mainTimeout = function() {
		if (!this.destroyed && !this.done && this.resCount < AjaxQueue.resLimit) {
			this.resCount++;
			this.fetchResponse();
		}
	}

	this.onLoading = function() {
		if (!this.destroyed && !this.done && this.reqCount ==1 && !this.okd) {
			var tmpHandle = this.handler;
			Ajax.handle(1, tmpHandle, null);
		}
	}


	
	this.onException = function(ex, conn) {
		var s = 0;
		if (!this.okd) {
			if (this.reqCount >= AjaxQueue.reqLimit) s = 1;
		} else if (!this.done) {
			if (!(this.resCount >= AjaxQueue.resLimit)) s = 2;
		} else if (this.done) s = 3;

		if (s>0) {
			if (this.errInjector) this.errInjector(this,ex,conn,s);
			var hand = this.handler;
			Ajax.error(hand, ex, conn, s);
		}
	}

	this.destroy = function() {
		this.destroyed = true;
		this.id = null;
		this.url = null;
		this.data = null;
		this.handler = null;
		this.headers = null;
		this.reqCount = -1;
		this.resCount = -1;
		this.okd = null;
		this.done = null;
		this.fetched = null;
	}
}

function AjaxQWrap(u, d, ha, p, he) {
	this.made = time();
	this.url = u;
	this.data = d;
	this.handler = ha;
	this.priority = p;
	this.headers = he;

	this.request = function() {
		this.start = time();
		if (this.data) Ajax.post(this.url, this.data, this, this.headers);
		else Ajax.get(this.url, this, this.headers);
	}

	this.callback = function(r) {
		this.done = time();
		AjaxQueue.callback(this,r);
		this.handler.callback(r, this);
	}

	this.onException = function(ex, conn, s) {
		AjaxQueue.error(ex,conn,s);
		this.handler.onException(ex,conn,s);
	}

	this.onLoading = function() { this.handler.onLoading(); }
	this.onLoaded = function() { this.handler.onLoaded(); }
	this.onInteractive = function() { this.handler.onInteractive(); }
	this.onComplete = function() { this.handler.onComplete(); }
}

var AjaxQueue = {
	reqLimit:4,
	resLimit:4,
	reqTimer:2000,
	resTimer:2000,

	transit:false,
	queue: new Array(),

	get: function(u, ha, p, he) { this.post(u, null, ha, p, he); },

	post: function(u, d, ha, p, he) {
		var w = new AjaxQWrap(u, d, ha, p, he);
		this.add(w);
	},

	handshake: function(u, d, ha, p, he) {
		var hs = new HandShaker(u, d, ha, he);
		hs.priority = p;
		hs.injector = function(hs,x) {
			AjaxQueue.callback(hs,x);
		}
		hs.errInjector = function(hs,ex,conn,st) {
			AjaxQueue.error(ex,conn,st);
		}
		this.add(hs);
	},

	add: function(hs) {
		var done = false;
		for(var i=0,a=this.queue; i<a.length; i++) {
			if(a[i].priority < hs.priority) {
				Ary.insert(a,i,hs);
				done = true;
				break;
			}
		}
		if(!done) Ary.add(a,hs);
		this.process();
	},

	next: function() {
		return Ary.remove(this.queue, 0);
	},

	process: function() {
		if (!this.transit) {
			var hs = this.next();
			if (hs != null) {
				this.transit = true;
				hs.request();
			}
		}
	},

	callback: function(hs,x) {
		this.transit = false;
		this.process();
	},

	error: function(h,ex,conn,st) {
		try {FC.logToServer("Queue error:"+st+','+h,null,false,ex);} catch(e){}
		this.transit = false;
		this.process();
	}
}

function time() {
	return new Date().getTime();
}

 
 
var Json = {
	toString: function(o) {
		if (typeof(o) == 'array') return Json.array(o);
		else return Json.object(o);
	},

	m: {'\b': '\\b','\t': '\\t','\n': '\\n','\f': '\\f','\r': '\\r','"' : '\\"','\\': '\\\\'},

	array: function (x) {
		var a = ['['], b, f, i, l = x.length, v;
		for (i = 0; i < l; i += 1) {
			v = x[i];
			f = Json[typeof v];
			if (f) {
				v = f(v);
				if (typeof v == 'string') {
					if (b) a[a.length] = ',';
					a[a.length] = v;
					b = true;
				}
			}
		}
		a[a.length] = ']';
		return a.join('');
	},

	'boolean': function (x) {
		return String(x);
	},

	'null': function (x) {
		return "null";
	},

	number: function (x) {
		return isFinite(x) ? String(x) : 'null';
	},

	object: function (x) {
		if (!x) return 'null';
		if (x instanceof Array) return Json.array(x);
		var a = ['{'], b, f, i, v;
		for (i in x) {
			v = x[i];
			f = Json[typeof v];
			if (f) {
				v = f(v);
				if (typeof v == 'string') {
					if (b) a[a.length] = ',';
					a.push(Json.string(i,true), ':', v);
					b = true;
				}
			}
		}
		a[a.length] = '}';
		return a.join('');
	},

	string: function (x,n) {
		if (/["\\\x00-\x1f]/.test(x)) {
			x = x.replace(/([\x00-\x1f\\"])/g,
				function(a, b) {
					var c = Json.m[b];
					if (c) return c;
					c = b.charCodeAt();
					return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
			});
		}
		return (n&&x.match(/^([A-Za-z0-9_]+)$/)) ? x : '"' + x + '"';
	}
}

function tx(o) {
	if (o != null) return o.tx;
	return null;
}

function setTx(o,n,v) {
	if(o == null) return;
	if(o[n] == null) o[n] = ({tx:v});
	else o[n].tx = v;
}

function ary(o) {
	return (o==null)?[]:(o.ary?[].concat(o):[o]);
}

function jsonTrue(o,defaultTrue) {
	return isTrueStr(tx(o)+'',defaultTrue);
}

function n(a,n) {
	if (a==null) return;
	if (a.ary) {
		for (var i=0;i<a.length;a++) a._n = n;
		return;
	}
	a._n = n;
}

function clone(o) {
	if(o == null || typeof(o) != 'object') return o;
	var o2 = (o instanceof Array? new Array() : new Object());
	for(var i in o) o2[i] = clone(o[i]);
	return o2;
}

function equal(o1,o2) {
	if(o1==null || typeof(o1)!='object' || o2==null || typeof(o2)!='object') return o1==o2;
	for(var i in o1) if(!equal(o1[i],o2[i])) return false;
	for(i in o2) if(o1[i]==null && o2[i]!=null) return false;
	return true;
}

function kids(o) {
	if (o==null) return false;
	for (i in o) if ((t = typeof o[i])=='object'||t=='array') return true;
	return false;
}

function first(o) {
	if (o==null) return null;
	var t,a;
	for (i in o)
		if(typeof (a=o[i])=='object')
			if(!a.ary) return a;
			else if(a.length>0 && (typeof(a[0])=='object'&&!a[0].ary)) return a[0];
	return null;
}

selectById = function(j, id) {
	for (n in j) if (o = j[n])
		if (o.ary) {
			for (i in o) if (o[i] && o[i].id && o[i].id==id) return o[i];
		} else if (o.id && o.id==id) return o;
	return null;
}

removeById = function(j, id) {
	for (n in j) if (o = j[n])
		if (o.ary) {
			for (var i=0;i<o.length;i++) if (o[i] && o[i].id && o[i].id==id) {
				Ary.remove(o,i);
				if (o.length==1) j[n]=o[0];
				return;
			}
		} else if (o.id && o.id==id) { j[n] = null; return; }
}

replaceById = function(j, id, nj) {
	for (n in j) if (o = j[n])
		if (o.ary) {
			for (var i=0;i<o.length;i++) if (o[i] && o[i].id && o[i].id==id) { o[i]=nj; return; }
		} else if (o.id && o.id==id) { j[n]=nj; return; }
}

addKid = function(j,d,n) {
	if(j==null)return;
	if((a=j[n])==null) j[n]=d;
	else if(a.ary) a[a.length]=d;
	else j[n]=[a,d];
}

attrs = function(j,nj,aid) {
	var a = [];
	if(j==null)return a;
	var ja = ary(j.get(nj));
	for (n in ja) if (o = j[n])
		if(!o.ary) a.add(o.get(aid));
	return a;
}



sortJsonByText = function(data, sortNodeName, sortOn, reverse) {
	sortJson(data, sortNodeName, sortJsonText, sortOn, reverse);
}
sortJsonByNumericValue = function(data, sortNodeName, sortOn, reverse) {
	sortJson(data, sortNodeName, sortJsonValue, sortOn, reverse);
}
sortJsonByDate = function(data, sortNodeName, sortOn, reverse) {
	sortJson(data, sortNodeName, sortJsonDate, sortOn, reverse);
}

sortJson = function(data, sortNodeName, func, sortProperty, reverse) {
	var tempArray = eval('[data.' + sortNodeName + ']');
	if(sortProperty != null && sortProperty != "") tempArray = sortJsonArray(tempArray, sortProperty, func, reverse);
	else tempArray = tempArray.sort(func);

	eval('data.' + sortNodeName + ' = ({});');
	if(tempArray != null) {
		if(tempArray.length==1) tempArray = tempArray[0];
		eval('data.' + sortNodeName + ' = tempArray;');
	}
}

sortJsonArray = function(jsonArray, sortProperty, func, reverse) {
	sortProp = sortProperty;
	var temp = jsonArray.sort(func);
	if(reverse == true) temp = temp.reverse();
	return temp;
}

sortJsonText = function(j1, j2) {
	var v1 = j1[sortProp];
	var v2 = j2[sortProp];
	if(v1 == null && v2 == null) {
		v1 = tx(j1[sortProp]);
		v2 = tx(j2[sortProp]);
	}

	return (v1<v2? -1:(v1>v2? 1:0) );
}

sortJsonValue = function(j1, j2) {
	var v1 = j1[sortProp];
	var v2 = j2[sortProp];
	if(v1 == null && v2 == null) {
		v1 = tx(j1[sortProp]);
		v2 = tx(j2[sortProp]);
	}

	v1 = parseFloat(v1);
	v2 = parseFloat(v2);
	return (v1<v2? -1:(v1>v2? 1:0) );
}

sortJsonDate = function(xml1, xml2) {
	v1 = new Date(tx(j1[sortProp])).getTime();
	v2 = new Date(tx(j2[sortProp])).getTime();

	return (v1<v2? -1:(v1>v2? 1:0) );
}

 
 
if (!Remote) var Remote = new Object();

Remote.requestCounter = 0;
Remote.handyCounter = 0;

Remote.nextRequestId = function() {
	Remote.requestCounter++;

	var win = '';
	try { win = '-' + B62.to(MB.getUIWindowID()); } 
	catch (e) {} // exception ignored, we may not be in the bet process

	return Guid.create() + win + '-' + B62.to(Remote.requestCounter);
}
Remote.nextHandshakeId = function() {
	return Random.string(5) +'-'+ B62.to(++Remote.handyCounter);
}

Ajax.newId = Remote.nextRequestId;
Ajax.newHandshakeId = Remote.nextHandshakeId;


Remote.createRequestHeaders = function(extra) {
	var headers = new Array();
	var token = FC.getUserToken();
	if (token != null) headers.add(new Array(FC.HDR_USER_TOKEN_NAME, token));
	if (extra != null) headers.add(new Array(FC.HDR_EXTRA_CMD_NAME, extra));
	return headers;
}

Remote.machineCall = function(machine,xml,extra,callback,priority) {
	return Remote.ajaxMachineCall(machine, xml, extra, false);
}
Remote.jsonMachineCall = function(machine, jOb, extra) {
	return Remote.ajaxMachineCall(machine, jOb, extra, true);
}
Remote.ajaxMachineCall = function(machine, obj, extra, json) {
	machine = (machine) ? machine : "matchbook.com/remote/sample/RemoteSampleMachine";
	if (machine.indexOf("/") != 0) machine = "/" + machine;

	var data = (json) ? Json.toString(obj) : XML.toString(obj);
	FC.logRequest(url, data);
	FC.callAudit(machine, 0);

	var url = Remote.remoteURL + machine;
	var response = null;
	var hea = Remote.createRequestHeaders(extra);
	if (json) hea.add(new Array('x-json-rr', 'true'));

	var qstring = url + '?' + escape(data);
		if (extra != 'login' && qstring.length < 2000) response = Ajax.get(qstring, null, hea);
	else response = Ajax.post(url, data, null, hea);

	var result = Remote.handleResponse(json, response, url, extra);
	if(result == null) FC.logError("Remote", "Failed to communicate with:" + url + "::" + data);
	return result;
}

Remote.asynchMachineCall = function(machine,xml,callback,extra,priority) {
	Remote.ajaxAsynchMachineCall(machine, xml, callback, extra, priority, false);
}
Remote.jsonAsynchMachineCall = function(machine, xml, callback, extra, priority) {
	Remote.ajaxAsynchMachineCall(machine, xml, callback, extra, priority, true);
}
Remote.ajaxAsynchMachineCall = function(machine, obj, callback, extra, priority, json) {
	machine = (machine) ? machine : "matchbook.com/remote/sample/RemoteSampleMachine";
	if (machine.indexOf("/") != 0) machine = "/" + machine;
	FC.callAudit(machine, 0);

	var data = (json) ? Json.toString(obj) : XML.toString(obj);
	var url = Remote.remoteURL + machine;
	var handler = new AjaxCallback(callback, url, extra, json);
	var headers = Remote.createRequestHeaders(extra);

	if (json) headers.add(new Array('x-json-rr', 'true'));
	FC.logRequest(url, data, AjaxQueue.queue.length);

	var qstring = url + '?' + escape(data);
	if (extra != 'login' && qstring.length < 1500) {
		AjaxQueue.get(qstring, handler, priority, headers);
	} else {
		url = Remote.hindsightServerURL + machine;
		AjaxQueue.handshake(url, data, handler, priority, headers);
	}
}

function AjaxCallback(c, m, e, j) {
	this.cb = c;
	this.extra = e;
	this.machine = m;
	this.json = j;

	this.callback = function(xr, qObj) {
		var result = Remote.handleResponse(this.json, xr, this.machine, this.extra);
		if (result && this.cb) this.cb(result, this.extra);
		if (qObj) logRRCBstats(qObj.url, qObj.made, qObj.start, qObj.okd, qObj.done);
	}
}

function logRRCBstats(url,made,start,ok,complete) {
	try {
		var u = "" + url;
		var qPos = url.indexOf('?');
		if(qPos > 0) u = url.substr(0, qPos);
		if(u) u = u.substr(u.lastIndexOf("/")+1);
		if(u.length < 28) u += "	";

		FC.log(u + "	ok:" + (ok>0? (ok - start) : "~")
				 + ",	c/:" + (complete - (ok>0? ok:start))
				 + ",	cb:" + (time() - complete));
	} catch(e) {}
}

Remote.handleResponse = function(json, respXHttp, url, extra) {
	var respTxt = respXHttp.responseText;
	var o = null;

	try {
		if(url) {
			url = url.substr(url.indexOf('matchbook.com'));
			FC.callAudit('/'+url,1);
			FC.logResponse(url, respTxt, AjaxQueue.queue.length);
		}
	} catch(e) {}; 	//empty catch, can't log a fail to a logging call

	try {
				if(respTxt && respTxt.charAt(0) == '<') json = false;

		o = (json? Remote.handleJson(eval('(' + respTxt + ')')) : Remote.handleSystemErrors(XML.parse(respTxt)));
		if (o != null) FC.handleResponseFirst(o, extra, json);
	} catch(e) {
		FC.logToServer("Error at framework handleResponse::"+json+"::"+url+"::"+extra+"::"+respTxt, null, false, e);
	}

	return o;
}

Remote.handleJson = function(jOb) {
	if (jOb.exception) Remote.handleSystemErrors(XML.parse(jOb.exception));
	return jOb;
}

Remote.handleSystemErrors = function(xml) {
	if(xml != null) {
		var lName = XML.getName(xml);
		if (lName == "application-invalid-error") FC.applicationInvalid();
		else if (lName == "request-parsing-error") Remote.showMachineURIFailure();
		else if (lName == "response-machine-uri-error") Remote.showMachineURIFailure();
		else if (lName == "response-processing-error") Remote.showError(xml);
		else if (lName == "request-duplication-error") Remote.reactToDuplication(xml);
		else return xml;
	}
	return null;
}

Remote.reactToDuplication = function(xml) {
	FC.logError("Remote", "Server said UI just made a dupe for request: " + XML.getText(xml, "message"));
}

Remote.showMachineURIFailure = function() {
	FC.logError("Remote", "Machine URI requested is blocked or incorrect");
}

Remote.displayError = function(id, msg) {
	FC.displayError(id, msg);
}

Remote.showError = function(xml) {
	FC.displayError("remote-client-communication", "Processing Error: " +
					XML.getText(xml,"message") + "\n" + XML.getText(xml,"exception"));
}
var _waitStateBailOut = null;
function setWaitState(timeout, message) {
	document.body.style.cursor = "wait";
	window.status = (message && message.length > 0)? message : FC.WAITING_MESSAGE;

	var time = (timeout > 0? timeout: FC.WAIT_STATE_TIMEOUT);
	if(_waitStateBailOut != null) window.clearInterval(_waitStateBailOut);
	_waitStateBailOut = window.setTimeout(releaseWaitState, time);
}

function releaseWaitState() {
	document.body.style.cursor = "default";
	document.body.link.cursor = "default";
	window.status = '';
}

function getKeyCode() {
	return (window.event? window.event.keyCode : -1);
}

var eventCall = new Array();
eventCall["mouse:click"]	= "handleClick";
eventCall["mouse:over"]	 	= "handleMouseOver";
eventCall["mouse:out"]		= "handleMouseOut";
eventCall["general:blur"]	= "handleBlur";
eventCall["input:change"]	= "handleInputChange";
eventCall["form:submit"]	= "handleFormSubmit";
eventCall["input:keyUp"]	= "handleKeyUp";

function doClick(e,extra) { doEvent("mouse:click",e,e,extra); }
function doMouseOver(e,extra) { doEvent("mouse:over",e,e,extra); }
function doMouseOut(e,extra) { doEvent("mouse:out",e,e,extra); }
function doBlur(e,extra) { doEvent("general:blur",e,e,extra); }
function doChange(e,extra) { doEvent("input:change",e,e,extra); }
function doKeyUp(e,extra) { doEvent("input:keyUp",e,e,extra); }
function doFormSubmit(e,extra) { doEvent("form:submit",e,e,extra); }

function doEvent(type,origin,e,extra) {
	var cid = null;
	e = e.parentNode;
	while (e) {
		if (e.className.indexOf("component") > -1) {
			cid = e.id;
			break;
		}
		e = e.parentNode;
	}

	if (cid != null) {
		var comp = componentRegistry.getComponent(cid);
		if (comp != null) {
			var recurse = false;
			if (eventCall[type]) {
				eval("recurse = (comp." + eventCall[type] + " && !comp." + eventCall[type] + "(origin,extra));");
			}
			if (recurse) doEvent(type,origin,e,extra);
			else if (comp.handleEvent && !comp.handleEvent(type,origin,extra)) doEvent(type,origin,e,extra);

		} else {
			doEvent(type,origin,e,extra);
		}
	} else {
		doEvent(type,origin,e,extra);
	}
}

if (window.attachEvent) {
	window.attachEvent("onunload", function() {
		var events = ['onmouseover','onmouseout','onkeyup','onclick','onblur','onchange','ondblclick'];
		for(var d = document.all.length;d--;){
			el = document.all[d];
			for(var c = events.length;c--;){
				el[events[c]] = null;
			}
		}
	});
}

var _sessionStorage = new Array();
Remote.storeInSession = function(pId, pObject) { _sessionStorage[pId] = pObject; }
Remote.removeFromSession = function(pId) { _sessionStorage[pId] = null; }
Remote.fetchFromSession = function(pId) { return _sessionStorage[pId]; }


var B62 = {
	chrs: ['0','1','2','3','4','5','6','7','8','9',
			'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
			'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'],
	to: function (n) {
		var s = '';
		while (n >= 62) {
			s = this.chrs[n%62]+s;
			n = Math.floor(n/62);
		}
		return this.chrs[n]+s;
	},
	from: function(s) {
		if (!B62.revc) {
			this.revc = new Object();
			for(var i=0;i<B62.chrs.length;i++)B62.revc[''+B62.chrs[i]]=i;
		}
		var r=0;
		for (var p=0;i=s.length-p-1,p<s.length;p++) r += this.revc[s.charAt(p)]*(i>0?Math.pow(62,i):1);
		return r;
	}
}
var Random = {
	number: function(x,y) {return (Math.floor(Math.random()*(y-x))) + x;},
	string: function(len) {
		var s = '';
		while(s.length<len)s+=B62.chrs[this.number(0,62)];
		return s;
	}
}
var Guid = {
	create: function() { return B62.to(new Date().getTime()) + Random.string(6); }
}

 
 
var componentRegistry = new ComponentRegistry();

function ComponentRegistry() {
	this.registryReady = false;
	this.pending = [];
	this.components = new Map();

	this.isReady = function() {return this.registryReady;}
	this.getComponent = function(id) {return this.components.get(id);}
	this.register = function(id,comp) {this.components.put(id,comp);}
	this.unregister = function(id) {this.components.remove(id);}
	
	this.registerPending = function(id,comp) {
		this.pending.add(id);
		this.register(id,comp);
	}

	this.transferPending = function() {
		for (var i=0,p=this.pending; i < p.length;i++) {
			var comp = this.components.get(p[i]);
			if (!comp) continue;

			comp.htmlElement = getDocElementById(p[i]);
			if (comp.init) comp.init();
			p[i] = null;
		}
		this.pending = [];
	}
}

function RegisterComponent(comp) {componentRegistry.register(comp.id,comp);}
function UnregisterComponent(compId) {componentRegistry.unregister(compId);}

function ComponentInLine(type,id,data,parent) {
	var comp = componentRegistry.getComponent(id);
	if (comp == null) {
		eval("comp = new " + type + "(id,null,data);");
		componentRegistry.registerPending(id,comp);
	} else {
		comp.data = data;
		comp.xml = data;
	}

	if (parent != null) comp.parent = parent;
	return comp;
}

function BufferComponentHtml(buff,type,id,data,parent) {
	var comp = ComponentInLine(type,id,data,parent);
	if (comp.bufferHtml) comp.bufferHtml(buff);
	else buff.app(comp.componentHtml());
}

function ComponentHtml(type,id,data,parent) {
	var comp = ComponentInLine(type,id,data,parent);
	if (comp.bufferHtml) {
		var buff = new StrBuff();
		comp.bufferHtml(buff);
		return buff.toString();
	}
	return comp.componentHtml();
}

function buildAndRegisterComponent(type,id,json) {
	var data = null;
	var doc = getDocElementById("data:" + id);
	if (json) {
		if (doc && doc.value != null && doc.value.length > 0) data = eval('(' + doc.value +')');
		else if (doc && doc.innerHTML.length > 0) data = eval('(' + doc.innerHTML +')');
	} else {
		if (doc && doc.value != null && doc.value.length > 0) data = XML.parse(doc.value);
		else if (doc && doc.innerHTML.length > 0) data = XML.parse(doc.innerHTML);
	}

	doc = getDocElementById(id);
	var comp = null;
	eval("comp = new " + type + "(id,doc,data);");

	componentRegistry.register(id,comp);
	if (comp.init) comp.init();
	if (comp.repaint) comp.repaint();

	componentRegistry.transferPending();
	if (comp.handleRegistryLoadComplete) {
		comp.handleRegistryLoadComplete();
		componentRegistry.registryReady = true;
	}
}

function htmlEncode(s) {
	if(s) s=s.replace(/&/g,'&amp;');
	if(s) s=s.replace(/</g,'&lt;');
	if(s) s=s.replace(/>/g,'&gt;');
	return s;
}

function debugComponent(id, force) {
	if((force || COMPONENT_DEBUGGING_ON) && id) {
		var comp = componentRegistry.getComponent(id);
		var el = getDocElementById(id);
		
		var dat = comp.data? Json.toString(comp.data) : (comp.xml? XML.toString(comp.xml) : null);
		var dat2 = (comp.getXml || comp.getData? ('\n\n---getData---\n\n'+(comp.getXml? XML.toString(comp.getXml()) : Json.toString(comp.getData()))) : '')
		if(comp) debugCompWin(id, dat + dat2, (el? el.innerHTML:'HTML element is null'),(comp.debugStr? comp.debugStr():null));
		else debugCompWin(id, "Component is null");
	}
}

function debugCompWin(id,xml,html,toStr){
	html = htmlEncode(html);
	toStr = (toStr? toStr + '<br>': '');
	while(toStr.indexOf(',') > 0) toStr = toStr.replace(",", "; ");

	var w = window.open(Remote.remoteServerURL + '/blank.htm','','scrollbars=yes,status=yes,resizable=yes,location=no,menubar=yes,width=790,height=590');
	w.document.write('<html><body><form name=frm><h3>Component ID: '+id+'&nbsp;&nbsp;<A href=javascript:window.close()>[CLOSE]</A></h3><table width=100% '
		+ '><tr>'+(toStr? '<td width=16% valign=top style="padding-right:5px;font-family:Arial;font-size:12px;background:#CCCCEE"><br>'+toStr+'</td>' : '')
		+ '<td width=84% valign=top><b>Data:</b> <input type=button onClick="window.opener.setDebugCompXml(\''+id+'\',document.frm.compXml.value);" '
		+ 'value="Set component XML"><textarea name=compXml style="width:100%;height:173px;font-size:11px;margin-bottom:5px" wrap=soft>'+xml+'</textarea>'
		+ '<b>Html:</b> <input type=button onClick="window.opener.setDebugCompHtml(\''+id+'\',document.frm.compHtml.value);" value="Set component HTML">'
		+ '<textarea name=compHtml style="width:100%;height:173px;font-size:11px;margin-bottom:5px" wrap=soft>'+html+'</textarea><b>Command Input:</b> '
		+ '<input type=text name=compCmd style="width:350;font-size:11px"> <input type=button value="Do Command" onClick="'
		+ 'document.frm.compRet.value=window.opener.doDebugCommand(\''+id+'\',document.frm.compCmd.value);"><textarea name=compRet '
		+ 'style="width:100%;height:105px;font-size:11px" wrap=off></textarea></td></tr></table></form></body></html>');
	w.focus();
}

function doDebugCommand(id,cmd) {
	var r = null;
	if(id && cmd) {
		var comp = componentRegistry.getComponent(id);
		if(comp) eval('r = ' + cmd.replace('this.', 'comp.'));
	}
	return r;
}

function setDebugCompXml(id,pXml) {
	if(id) {
		var comp = componentRegistry.getComponent(id);
		var x = XML.parse(pXml);
		if(comp && x) {
			comp.xml = x;
			if(comp.updateFromXml) comp.updateFromXml();
			else if(comp.repaint) comp.repaint();
		}
	}
}

function setDebugCompHtml(id,html) {
	if(id) {
		var el = getDocElementById(id);
		if(el) el.innerHTML = html;
	}
}

 
 
var processorRegistry = new ProcessorRegistry();

function ProcessorRegistry() {
	this.processors = new Map();

	this.register = function(p) { this.processors.put(p.id,p); }
	this.getProcessor = function(mapping) { return this.processors.get(mapping); }
	this.deleteProcessor = function(mapping) { return this.processors.get(mapping); }
	this.registerNewProcessor = function(id,request,machine) { this.register(new Processor(id,request,machine)); }
}

function Processor(id,xml,machine) {
	this.id = id;
	this.requestXml = xml;
	this.machine = machine;

	this.processResponse = function(rXML) { 
		componentRegistry.getComponent(this.id).serverUpdate(rXML); 
	}
}

function registerAndStartPollingProcessors(xml) {
	if(xml == null) return;
	remotingHub.url = XML.getAttribute(xml,"url");

	var procs = XML.select(xml,"processor");
	for(var i=0,px=null,rate=-1;i< procs.length; i++) {
		px = procs[i];
		processorRegistry.registerNewProcessor(XML.getAttribute(px,"id"),
					XML.selectOne(px,"request"),XML.getAttribute(px,"machine"));

		rate = parseInt(XML.getAttribute(px,"polling-rate"));
		if(rate < remotingHub.interval || remotingHub.interval == -1) remotingHub.interval = rate;
	}

	remotingHub.startPolling(true);
}

var remotingHub = new RemoteHub();
function RemoteHub() {
	this.url = null;
	this.polling = false;
	this.interval = -1;

	this.firePolling = function() {
		if(!this.polling || this.interval == -1) return;
		var pk = processorRegistry.processors.keys;
		var poll = XML.createElement("polling");

		for(var i=0;i< pk.length; i++) {
			var ps = processorRegistry.processors.get(pk[i]);
			var pwrap = XML.createElement("processor");

			XML.addContent(poll,pwrap);
			XML.setAttribute(pwrap,"id",ps.id);
			if(ps.machine) XML.setAttribute(pwrap,"machine",ps.machine);

			var clone = ps.requestXml.cloneNode(true);
			XML.addContent(pwrap,clone);
		}

		var loc = "" + document.location;
		loc = loc.substring(0,loc.indexOf("/",7));
		var pollUrl = loc + "/admin/poller/server/pollingServer.jsp";
		var response = connection.postURL(pollUrl,XML.toString(poll),null);

		if(!this.polling) return;
		var respX = XML.parse(response.responseText);
		var procs = XML.select(respX,"processor");

		for(var i=0;i< procs.length; i++) {
			var p = processorRegistry.getProcessor(procs[i].getAttribute("id"));
			if(p != null) p.processResponse(procs[i]);
		}

		if(this.interval >= 0) setTimeout("remotingHub.firePolling()",this.interval);
	}

	this.stopPolling = function() { this.polling = false; }
	this.startPolling = function(w) {
		this.polling = true;
		if(!w) remotingHub.firePolling();
		else setTimeout("remotingHub.firePolling()",this.interval);
	}
}

function FrameworkTimer(id,func,interval,extra) {
	var comp = componentRegistry.getComponent(id);
	if (!comp) { return; }

	var cont = false;
	eval("cont = comp." + func + "(extra)");
	if (cont) setTimeout("FrameworkTimer('"+id+"','"+func+"',"+interval+(extra?",'"+extra+"'":"")+")",interval);
}

function FrameworkTimeout(id,func,interval,extra,doIt) {
	if(doIt) {
		var comp = componentRegistry.getComponent(id);
		if(comp) eval("comp." + func + "(extra)");
	} else {
		setTimeout("FrameworkTimer('"+id+"','"+func+"',0"+(extra?",'"+extra+"'":",''")+",true)",interval);
	}
}

function timedComponentCall(comp,func,timer) {
	if(func && func.lastIndexOf(")") != func.length-1) func += "()";
	return setTimeout((comp? "componentRegistry.getComponent('"+comp+"').":"")+func,timer);
}

var TIMED_COMPONENT_CALL_ID = null;
function startTimedPoller(comp,func,timer) {
	if(TIMED_COMPONENT_CALL_ID != comp + "." + func) {
		timedComponentCall(comp,func,timer);
		TIMED_COMPONENT_CALL_ID = comp + "." + func;
	}
}

 
 