//#require /script/csiCom/global/JSON.js
//#require /script/csiCom/external/jquery.min.js
//#require /script/csiCom/global/common.js
//#require /script/csiCom/global/dom.js

/*
Dispatch.js
_______
CHANGES
=======
12/22/2006 -- csh

___________
ARGUMENTS
===========
url: The url for the server-side dispatch handler
module: the module name to load on the server side
method: the method on the module to call 
params: scalar value or an object
context: a context object
domNode: a 

___________
USAGE NOTES
===========
Setup
	Dispatch.url=<<url>>; // the default URL is "Dispatch.aspx"
	
Messages
	set Dispatch.messenger = [a DOM node] and Dispatch will handle keeping the DOM node updated. 
*/

var Dispatch = {};

Dispatch.url = "/" + dom.parseRootName(window.location) + "/Dispatch.aspx";
//console.log(Dispatch.url);

Dispatch.alertErrors = true;

Dispatch.notify = null; // set to a function, called when dispatch state changes

Dispatch.requests = []; // array of ongoing requests
//Dispatch.sessionExpired = false; // set to true to divert incoming requests to the deferred collection
Dispatch.quiet = false; // set to true to supress all error alerts

Dispatch.transportErrors = [];

Dispatch.getLoadingHtml = function(arg){
	var p = arg ? arg : {};//{message:"Loading"};
	if(typeof(p.message) == "undefined") p.message = "Loading";
	if(p.centered){
		return "<table width=\"100%\"><tr><td align=\"center\">"
		+ "<img class=\"DispatchLoading\" src=\"/images/dispatch/loading_bar_small.gif\">&nbsp;<b class=\"DispatchLoading\">" + p.message + "</b>"
		+ "</td></tr></table>";
	}
	else{
		return "<img class=\"DispatchLoading\" src=\"/images/dispatch/loading_bar_small.gif\">&nbsp;<b class=\"DispatchLoading\">" + p.message + "</b>";
	}
}

//==========================================================================
//												 (shared) (public) send
//	sends a dispatch request to the server
//  gives the results back to a context (if provided)
//	or updates a domNode (if provided)
//__________________________________________________________________________
Dispatch.send = function(r){
	/*
	var t = typeof(arguments[0]);
	var d;
	switch(t){
		case "string":
			// legacy mode
			var arg = {
				module:arguments[0],
				method:arguments[1],
				params:arguments[2],
				context:arguments[3].isContext?arguments[3]:null,
				node:arguments[3].isContext?null:arguments[3]
			}
			d = new DispatchRequest(arg);
		break;
		case "object":
			// new cool mode
			d = new DispatchRequest(arguments[0]);
		break;
		default:
			// uhoh
			alert("Dispatch.send did not understand its arguments");
		break;
	}
	*/
	var d = new DispatchRequest(r);
	if(d){
		Dispatch.requests.push(d);
		d.send();
		Dispatch.update();
	}
}
//Dispatch.dispatch = Dispatch.send; // DEPRECATED
//Dispatch.getHTML = Dispatch.send; // DEPRECATED
//Dispatch.dispatchQ = Dispatch.send; // DEPRECATED

/*

Dispatch.deferred = {};
Dispatch.deferredID = 0;
Dispatch.getDeferredKey = function(){
}
Dispatch.callBackDeferred = function(key,data){
	var ctx = Dispatch.deferred[key];
	if(ctx){
		ctx.giveBack(data);
		delete Dispatch.deferred[key];
	}
	
}
*/

Dispatch.loadSource = function(ctx,url){
	// loads the script URL specified in url
	// notifies ctx when complete
	//console.log("Dispatch.loadSource",ctx,url);
	
	//var deferredKey = Dispatch.deferredID ++;
	//alert(ix);
	//Dispatch.deferred[deferredKey] = ctx;
	//var node = $("head")
	//var func = "Dispatch.loadSourceDo(" + ix + ");";
	//console.log("Dispatch.loadSource",url);
	
	var contextKey = ctx ? ctx.suspend() : null;
	
	//console.log("dls",contextKey,Context.suspended);
	
	
	var ctx = new Context(function(c){
		Dispatch.loadSourceDo(c.data.urls,contextKey);
		c.destroy();
	});
	
	Dispatch.send({
		module:"SourceDispatch",
		method:"load",
		context:ctx,
		params:{pageKey:PAGE_KEY,url:url}//,callback:null},
		//loadSource:true
	});
}

Dispatch.loadSourceDo = function(arr,contextKey){
	//console.log(data);
	// data == {urls:[]}
	// urls is a manifest of the files we need to load, in order.
	// we need to wait for each one to load before loading the next
	// when the last one is loaded, call the callback (stored in Dispatch.deferred[deferredKey])

	if(!arr || !arr.length){
		 var ctx = Context.resume(contextKey);//.deferred[deferredKey];
		 if(ctx)ctx.doCallback();
		 return true;
	}
	var s = arr.shift();
	//alert(s);
	
	var hn = document.getElementsByTagName("head")[0];
	if(s.endsWith(".js")){
		var node = document.createElement("script");
			//alert(node);
		node.setAttribute("src",s);
			//alert("set src");
		node.setAttribute("type","text/javascript");
			//alert("set nodeType");
		if(dom.isIE){
			dom.addEvent(node,"readystatechange",function(e){
				if(e.srcElement.readyState == "loaded"){
					Dispatch.loadSourceDo(arr,contextKey);
				}
			});
		}
		else{
			dom.addEvent(node,"load",function(e){
				Dispatch.loadSourceDo(arr,contextKey);
			});	
		}

		hn.appendChild(node);
	}
	else if(s.endsWith(".css")){
		var node = document.createElement('link');
		node.setAttribute('rel', 'stylesheet');
		node.setAttribute('type', 'text/css');
		node.setAttribute('href', s);
		
		hn.appendChild(node);
		
		Dispatch.loadSourceDo(arr,contextKey);
	}
	else{
		alert("heeh?");
		alert(s);
	}
		
}
/*

	var node = document.createElement("script");
	node.text = "var ctx = Dispatch.deferred[" + ix + "]; if(ctx)ctx.giveBack(true);";
	node.setAttribute("type","text/javascript");
	hn.appendChild(node);
}
*/


/*
Dispatch.loadSourceDo = function(arg){
	var ctx = Dispatch.deferred[arg];
	if(ctx)ctx.giveBack(true);
	
}
*/


//==========================================================================
//												 (shared) (public) resend
//	resends deferred requests
//__________________________________________________________________________
/*
Dispatch.resend=function(){
	if(!Dispatch.defer){
		for(var i=0;i<this.requests.length;i++){
			if(this.requests[i].defer){
				this.requests[i].send();
			}
		}
	}
	Dispatch.update();
}
*/

//==========================================================================
//										            (private) onStateChange
//
//	handles state change events on the xmlhttp request
//
//	readyStates:
//	0 (uninitialized)
//	1 (loading)
//	2 (loaded)
//	3 (interactive)
//  4 (complete) 
//__________________________________________________________________________
Dispatch.onStateChange = function(req){
	//console.log("onstateCHnage",req);
	//alert(req);
	//alert(obj.transport);
	//debug.print(obj.transport);
	//debug.comment(req,req.transport,req.transport.readyState);
	
	var xh = req.transport;
	if (xh.readyState == 4) {
	
		////// testing dispatch return...
		/*
		if(!req.resume){
			var inp=document.createElement("input");
			inp.type="button";
			inp.value="resume";
			document.body.appendChild(inp);
			dom.addEvent(inp,"click",function(){document.body.removeChild(this);req.resume=true;Dispatch.onStateChange(req)});
			return false;
		}
		*/
		////// end testing
		var stat;
		try{
			stat = xh.status;
		}
		catch(e){
			stat = e;//alert(e);
		}
		//debug.comment(stat);
		
		
		var keepAlive = false;
		
		if (stat == 200) {//xh.status
			
			var s = xh.getResponseHeader("X-ERROR");
			var w = xh.getResponseHeader("X-WARNING");
			//console.log("Dispatch return",s,w);
			if(s && s.length > 0){
				if(s == "SESSION EXPIRED"){
					keepAlive = Dispatch.onSessionExpiredError(req);
				}
				else{
					keepAlive = Dispatch.onError(req,s);
				}
			}
			else if(w && w.length){
				keepAlive = Dispatch.onWarning(req,w,xh.responseText);
			}
			else{
				//if(req.requestType == "script") {
				//	keepAlive = Dispatch.onLoadScript(req, xh.responseText);
				//}
				//else {
					keepAlive = Dispatch.onSuccess(req,xh.responseText);
				//}
			}
		} 
		else {
			keepAlive = Dispatch.onTransportError(req,stat);
		}
		
		if( !keepAlive) Dispatch.destroy(req);
	}
}

Dispatch.onError = function(req,err){
	//debug.comment("Dispatch onError");
	if(Dispatch.alertErrors&&!req.quiet){
		alert(err);	
	}
	if(req.context){
		req.context.giveBackError(err);
	}
	else if(req.node){
		req.node.innerHTML = err;
	}
	return false; // do not keep request alive
}
Dispatch.onSessionExpiredError = function(req){
	Dispatch.sessionExpired = true;
	req.defer = true;
	//if(this.alertErrors){
	if(!Dispatch.quiet){
		window.location.href = "Login.aspx";
		//alert("Your server session has expired. Please refresh your browser and sign back in.");
	}
	// override this method to handle re-login
	//Dispatch.sessionExpired=true;
}
Dispatch.onTransportError = function(req, status){
	// override this method to handle this error differently..
	if(!Dispatch.quiet){
		var m = "Dispatch Transport Error: "
		+ "\nStatus:" + status
		+ "\nUrl:" + req.url
		+ "\nModule:" + req.module
		+ "\nMethod:" + req.method
		+ "\nParams:" + req.params;
		//alert(m);
		Dispatch.transportErrors.push(m);
		//debug.comnent(m);
	}
	
	//debug.comment("transport error");
	//Dispatch.destroy(req);
	return false; // do not keep request alive
}

Dispatch.onWarning = function(req, warningKey, warning){
	//debug.comment("Dispatch onWarning");
	// display the warning message and get a response from the user
	// if the user confirms the warning, then re-submit the request
	if(confirm(warning)){
		req.warnings.push({key:warningKey,response:true});
		//console.log("re-sending");
		req.send();
		return true;
	}
	else{
		// exit as with errors
		if(req.context){
			req.context.giveBackError(warning);
		}
		return false;
	}
}
/*
Dispatch.onLoadScript = function(req, data) {
	var s = document.createElement("script");
	s.innerHTML = data;
	s.type = "text/javascript";
	document.getElementsByTagName("head")[0].appendChild(s);
	if(req.context) {
		req.context.giveBack(data);
	}
	return false; // do not keep request alive
}
*/

Dispatch.onSuccess = function(req, data){
	//console.log(req);
	//console.log(data);
	
	if(req.context){
		var r;
		if(req.returnType == "json"){
			if(data){
				eval("r = " + data);
			}
			else{
				r = null;
			}
		}
		else{
			r = data;
		}
		req.context.giveBack(r);
		/*
		try{
			eval("r = " + data);
		}
		catch(e){
			r = data;
		}
		*/
	}
	else if(req.node){
		req.node.innerHTML = data;
	}
	
	/*
	else if(req.loadSource){
		var r;
		try{
			eval("r = " + data);
		}
		catch(e){
			r = data;
		}
		Dispatch.loadSourceDo(r);
		//$("body").prepend(data);
	}
	*/
	
	return false; // do not keep request alive
}


Dispatch.destroy = function(req){
	var arr = Dispatch.requests;
	for(var i = 0; i < arr.length; i ++){
		if(arr[i] == req){
			arr.splice(i,1);
			break;
		}
	}
	req.destroy();
	Dispatch.update();
}

Dispatch.update = function(){
	if(Dispatch.notify){
		Dispatch.notify({requestCount:Dispatch.requests.length});
	}
}

Dispatch.getStatus = function(){
	var s = [];

	var arr = Dispatch.requests;
	for(var i = 0; i < arr.length; i ++){
		s.push("<div class=\"request\">[" + arr[i].module + " " + arr[i].method + "] " + arr[i].message + "</div>");
	}
	
	return s.join("");
	
}


Dispatch.lastID = 0;
Dispatch.getID = function(){
	Dispatch.lastID ++;
	return Dispatch.lastID;
}



//====================================================================
//			 DispatchRequest: Should only be instantiated by Dispatch
//____________________________________________________________________

function DispatchRequest(arg){
	this.ID = Dispatch.getID();
	this.url = (arg.url) ? arg.url : Dispatch.url;
	this.module = arg.module;
	this.method = arg.method;
	
	// return handler: must specify either context or node
	this.context = arg.context;// if given, then the context will be called back with the data.
	this.node = arg.node; // if given, node.innerHTML will be set to the respose text
	
	// returnType:
	// json(default): response string is eval-ed to create a json object
	// text (or html): response is returned raw
	this.returnType = arg.returnType ? arg.returnType : "json";

	this.message = arg.message ? arg.message : "Loading";
	this.quiet = arg.quiet ? true : false;
	this.defer = arg.defer ? true : false;
	this.overrideDefer = arg.overrideDefer ? true : false;
	//this.requestType = arg.requestType ? arg.requestType : "default";
	
	this.alertErrors = (arg.alertErrors) ? true : false;
	//this.overrideDefer=(arg.overrideDefer)?true:false;
	this.warnings = [];

	if(typeof(arg.params) == "undefined"){
		this.params = "";
	}
	else{
		if(typeof(arg.params) == "object"){
			//alert("stringify");
			//alert(JSON.stringify(params));
			//this.params=escape(JSON.stringify(arg.params));
			this.params = JSON.stringify(arg.params);
			//debug.comment(this.params);
		}
			else{
			//alert(params);
			//alert("escape");
			this.params = arg.params;
		}
	}
	this.status = "new";
}

DispatchRequest.prototype.send = function(){
	this.defer = false;
	
	//if(this.defer)return false;
	//if(Dispatch.defer && (!this.overrideDefer)){
	//	Dispatch.defer.push(this);
	//}
	//else{
	//	debug.comment("sending");

	
	var xh = this.transport = this.getTransport();
	//alert(xh.open);
	//alert(this.url);
	
	xh.open('POST', this.url ? this.url : ".", true);
	xh.setRequestHeader('X-DISPATCH', 'true');
	//xh.setRequestHeader('X-DISPATCH', 'true');
	xh.setRequestHeader("X-MODULE",this.module);
	//xh.setRequestHeader("X-MODULE",this.module);
	xh.setRequestHeader("X-METHOD",this.method);
	//xh.setRequestHeader("X-METHOD",this.method);
	//console.log("DispatchRequest.send",this.ID,this.module,this.method,this.transport, xh == this.transport);
	
	for (var i = 0; i < this.warnings.length; i ++){
		var w = this.warnings[i];
		xh.setRequestHeader("X-WARNING-" + w.key, w.response);
	}
	//xh.setRequestHeader("X-PARAMS",this.params);
	xh.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	//alert("post");
	xh.send(this.params);  
	//}
}

DispatchRequest.prototype.destroy = function(){
	//console.log("DispatchResquest.destroy",this.ID);
	this.context = null;
	this.node = null;
	this.transport = null;
	this.status = "destroyed";
}

DispatchRequest.prototype.getTransport = function(){
	var obj;
	if (window.XMLHttpRequest) { // Mozilla, Safari, IE 7+ ...
		//alert("DispatchRequest.getTransport: window.XMLHttpRequest");
		obj = new XMLHttpRequest();
		//alert(obj);
		//if (obj.overrideMimeType) {
			//obj.overrideMimeType('text/xml');
			// See note below about this line
		//}
	} else if (window.ActiveXObject) { // IE
		try {
			obj = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			//alert(e);
			try {
				obj = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {}// alert(e); }
		}
	}
	//alert(obj);
	//alert(typeof(obj));
	
	if(obj){
		var me = this;
		//obj.onreadystatechange = function() { try{ Dispatch.onStateChange(me);} catch(e){} };
		obj.onreadystatechange = function(){ Dispatch.onStateChange(me); };
	}
	return obj;
}






//==================================================================================================================
// BinaryDispatch: Use this to retrieve things like XLS files. 
// Supported so far: Aspose.cells.workbook

var BinaryDispatch = {};
BinaryDispatch.url = "/" + dom.parseRootName(window.location) + "/Dispatch.aspx";

BinaryDispatch.send = function(arg){
	var doc = document;
	var frm = doc.createElement("form");
	frm.action = BinaryDispatch.url;
	frm.method = "post";
	
	var inp = BinaryDispatch.makeInput("X-DISPATCH","true");
	frm.appendChild(inp);
	
	var inp = BinaryDispatch.makeInput("X-MODULE",arg.module);
	frm.appendChild(inp);
	
	var inp = BinaryDispatch.makeInput("X-METHOD",arg.method);
	frm.appendChild(inp);
	
	if(typeof(arg.params) == "object"){
		inp = BinaryDispatch.makeInput("X-PARAMS",JSON.stringify(arg.params));
	}
	else{
		inp = BinaryDispatch.makeInput("X-PARAMS",arg.params);
	}
	frm.appendChild(inp);
	
	
	doc.body.appendChild(frm);
	frm.submit();
	doc.body.removeChild(frm);
	frm = null;
}

BinaryDispatch.makeInput = function(n,v){
	var inp = document.createElement("input");
	inp.type = "hidden";
	inp.name = n;
	inp.value = v;
	return inp;
}



//===============================================================    DEPRECATED FROM HERE

      /* Force "Connection: close" for Mozilla browsers to work around
       * a bug where XMLHttpReqeuest sends an incorrect Content-length
       * header. See Mozilla Bugzilla #246651.
       */
    //  if (this.transport.overrideMimeType)
  //      requestHeaders.push('Connection', 'close');
 //   }