//
//  jsrsClient.js - javascript remote scripting client include
//  
//  Author:  Brent Ashley [jsrs@megahuge.com]
//
//  make asynchronous remote calls to server without client page refresh
//
//  see license.txt for copyright and license information

/*
see history.txt for full history
2.0  26 Jul 2001 - added POST capability for IE/MOZ
*/

// callback pool needs global scope
var jsrsContextPoolSize = 0;
var jsrsContextMaxPool = 10;
var jsrsContextPool = new Array();
var jsrsBrowser = jsrsBrowserSniff();
var jsrsPOST = false;
var jsrsSearching = false;
var jsrsSearchCheckTimes = 0;

function resultIsError(obj) {
	if (typeof(obj) == "string" && obj.substring(0, 6) == "Error:") {
		alert(obj);
		return true;
	}
	return false;
}

// constructor for context object
function jsrsContextObj( contextID ){
	// properties
	this.id = contextID;
	this.busy = true;
	this.callback = null;
	this.container = contextCreateContainer( contextID );
	this.callbackArgs = null;

	// methods
	this.GET = contextGET;
	this.POST = contextPOST;
	this.getPayload = contextGetPayload;
	this.setVisibility = contextSetVisibility;
}

//  method functions are not privately scoped 
//  because Netscape's debugger chokes on private functions
function contextCreateContainer( containerName ){
	// creates hidden container to receive server data 
	var container;
	switch( jsrsBrowser ) {
		case "NS":
			container = new Layer(100);
			container.name = containerName;
			container.visibility = "hidden";
			container.clip.width = 100;
			container.clip.height = 100;
			break;

		case "IE":
			document.body.insertAdjacentHTML( "afterEnd", "<span id='SPAN" + containerName + "'></span>" );
			var span = document.all( "SPAN" + containerName );
			var html = "<iframe name='" + containerName + "' src=''></iframe>";
			span.innerHTML = html;
			span.style.display = "none";
			container = window.frames[ containerName ];
			break;
		    
		case "MOZ":  
			var span = document.createElement("SPAN");
			span.id = "SPAN" + containerName;
			document.body.appendChild( span );
			var iframe = document.createElement("IFRAME");
			iframe.name = containerName;
			span.appendChild( iframe );
			container = iframe;
			break;
			
		case 'OPR':  
			var span = document.createElement('SPAN');
			span.id = "SPAN" + containerName;
			document.body.appendChild( span );
			var iframe = document.createElement('IFRAME');
			iframe.name = containerName;
			iframe.id = containerName;
			span.appendChild( iframe );
			container = iframe;
			break;
	}
	return container;
}

function contextPOST( rsPage, func, parms ){
 
  var d = new Date();
  var unique = d.getTime() + "" + Math.floor(1000 * Math.random());
  var doc = this.container.document;
  doc.open();
  doc.write("<html><body>");
  doc.write("<form name='jsrsForm' method='post' target='' ");
  doc.write("action='" + rsPage + "?U=" + unique + "'>");
  doc.write("<input type='hidden' name='C' value='" + this.id + "'>");

  // func and parms are optional
  if (func != null){
  doc.write("<input type='hidden' name='F' value='" + func + "'>");

    if (parms != null){
      if (typeof(parms) == "string"){
        // single parameter
        doc.write( "<input type='hidden' name='P0' value=\"[" + jsrsEscapeQQ(parms) + "]\">");
        doc.write( "<input type='hidden' name='PC' value=\"1\">");
      } else {
        // assume parms is array of strings
        for( var i=0; i < parms.length; i++ ) {
          doc.write( "<input type='hidden' name='P" + i + "' value=\"[" + jsrsEscapeQQ(parms[i]) + "]\">");
         }
         
         doc.write( "<input type='hidden' name='PC' value=\"" + parms.length + "\">");         
      } 
    } 
  } 

  doc.write("</form></body></html>");
  doc.close();
  doc.forms["jsrsForm"].submit();
}


function buildURL(rsPage, func, parms, contextID) {
	// build URL to call
	var URL = rsPage;

	// always send context
	URL += "?C=" + contextID;

	// func and parms are optional
	if (func != null) {
		URL += "&F=" + escape(func);

		if (parms != null) {
			if (typeof(parms) == "string") {
				// single parameter
				URL += "&P0=[" + escape(parms + "") + "]";
				URL += "&PC=1";
			} else {
				// assume parms is array of strings
				for( var i=0; i < parms.length; i++ ) {
					URL += "&P" + i + "=[" + escape(parms[i] + "") + "]";
				}
				URL += "&PC=" + parms.length;
			} 
		} else {
			URL += "&PC=0";
		}	
	} 

	// unique string to defeat cache
	var d = new Date();
	URL += "&U=" + d.getTime();

	return URL;
}

function contextGET( rsPage, func, parms ){

	var URL = buildURL(rsPage, func, parms, this.id);	

	// make the call
	switch( jsrsBrowser ) {
		case "NS":
			this.container.src = URL;
			break;
		case "IE":
			this.container.document.location.replace(URL);
			break;
		case "MOZ":
			this.container.src = "";
			this.container.src = URL; 
			break;
		case 'OPR':
			this.container.src = '';
			this.container.src = URL; 
			break;
	}  
}

function contextGetPayload(){
	switch( jsrsBrowser ) {
		case "NS":
			return this.container.document.forms["jsrs_Form"].elements["jsrs_Payload"].value;
		case "IE":
			return this.container.document.forms["jsrs_Form"]["jsrs_Payload"].value;
		case "MOZ":
			return window.frames[this.container.name].document.forms["jsrs_Form"]["jsrs_Payload"].value; 
		case 'OPR':
			return window.frames[this.container.name].document.forms["jsrs_Form"]["jsrs_Payload"].value; 
			//var textElement = window.frames[this.container.name].document.getElementById("jsrs_Payload");
			//return textElement.value;
	}  
}

function contextSetVisibility( vis ){
	switch(jsrsBrowser) {
		case "NS":
			this.container.visibility = (vis)? "show" : "hidden";
			break;
		case "IE":
			document.all("SPAN" + this.id ).style.display = (vis)? "" : "none";
			break;
		case 'MOZ':
			document.getElementById("SPAN" + this.id).style.visibility = (vis)? '' : 'hidden';
			break;
		case 'OPR':
			document.getElementById("SPAN" + this.id).style.visibility = (vis)? '' : 'hidden';
			this.container.width = (vis)? 250 : 0;
			this.container.height = (vis)? 100 : 0;
			break;
	}  
}

// end of context constructor


// Synchronous request functions
function getSynchronousHttpObject() {
  var remote = null;
  try {
    remote = new XMLHttpRequest();
  } catch (e) {
	try {
      remote = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      remote = new ActiveXObject("Microsoft.XMLHTTP");
    }
  }
  return remote;
}



function doSynchronousGet(url) {
  var remote = getSynchronousHttpObject();
  
  if (remote != null) {
	remote.open("GET",url,false);
	remote.send(null);
	return remote.responseText;
  }
}


function synchronousExecute(rspage, func, parms){
	// synchronously call a server routine from client code
	//
	// rspage      - href to asp file
	// func        - sub or function name  to call
	// parm        - string parameter to function
	//               or array of string parameters if more than one
	
	var URL = buildURL(rspage, func, parms, 0)	
	var html = doSynchronousGet(URL)
	var obj;		
	
	if (html != null) {
		// get context
		var contextObj = jsrsContextPool[jsrsGetContextID()];		
		
		// get payload data
		var oNewDoc = contextObj.container.document.open("text/html", "replace");
		//contextObj.container.document.write(html);
		oNewDoc.write(html);
		obj = eval(contextObj.getPayload());
				
		// clean up and return context to pool
		jsrsCleanUp(contextObj);		
	}

	return obj;
}



function jsrsGetContextID(){
	var contextObj;
	for (var i = 1; i <= jsrsContextPoolSize; i++){
		contextObj = jsrsContextPool[ "jsrs" + i ];
		if ( !contextObj.busy ){
			contextObj.busy = true;      
			return contextObj.id;
		}
	}
	// if we got here, there are no existing free contexts - create new context
	if ( jsrsContextPoolSize <= jsrsContextMaxPool ){
		var contextID = "jsrs" + (jsrsContextPoolSize + 1);
		jsrsContextPool[contextID] = new jsrsContextObj(contextID);
		jsrsContextPoolSize++;
		return contextID;
	} else {
		alert("jsrs Error:  context pool full");
		return null;
	}
}

function jsrsExecute(rspage, callback, func, parms, callbackArgs, visibility ){
	// call a server routine from client code
	//
	// rspage      - href to asp file
	// callback    - function to call on return 
	//               or null if no return needed
	//               (passes returned string to callback)
	// func        - sub or function name  to call
	// parm        - string parameter to function
	//               or array of string parameters if more than one
	// callbackArgs - arguments to pass to the callback
	// visibility  - optional boolean to make container visible for debugging

	jsrsSearching = true;
	
	// get context
	var contextObj = jsrsContextPool[jsrsGetContextID()];
	contextObj.callback = callback;
	contextObj.callbackArgs = callbackArgs;

	var vis = (visibility == null) ? false : visibility;
	contextObj.setVisibility(vis);

	if (jsrsPOST && ((jsrsBrowser == "IE") || (jsrsBrowser == "MOZ"))){
		contextObj.POST(rspage, func, parms);
	} else {
		contextObj.GET(rspage, func, parms);
	}  

	return contextObj.id;
}

function jsrsLoaded(contextID) {
		jsrsSearching = false;
		jsrsSearchCheckTimes = 0;

		// get context object and invoke callback
		var contextObj = jsrsContextPool[ contextID ];
	
		if (contextObj != null) {
			if(contextObj.callback != null) {
				//alert(contextObj.getPayload());
				var obj = eval(contextObj.getPayload());
				contextObj.callback(obj, contextObj.callbackArgs);
			}
			// clean up and return context to pool
			jsrsCleanUp(contextObj);
		}
}

function jsrsError(contextID)	{
	jsrsSearching = false;
	jsrsSearchCheckTimes = 0;

	// get context object
	var contextObj = jsrsContextPool[ contextID ];
	
	if (contextObj != null) {
		alert(unescape(contextObj.getPayload()));
		
		// clean up and return context to pool
		jsrsCleanUp(contextObj);
	}		
}

function jsrsCleanUp(contextObj) {
	contextObj.callback = null;
	contextObj.callbackArgs = null;
	contextObj.busy = false;
}

// used by post
function jsrsEscapeQQ( thing ){
	return thing.toString().replace(/'/g, "\'");
	return thing.toString().replace(/"/g, "\\\"");
}

function jsrsBrowserSniff(){
	if (document.layers) return "NS";
		if (document.all) {
		// But is it really IE?
		// convert all characters to lowercase to simplify testing
		var agt=navigator.userAgent.toLowerCase();
		var is_opera = (agt.indexOf("opera") != -1);
		if(is_opera) {
			return "OPR";
		} else {
			return "IE";
		}
	}
	if (document.getElementById) return "MOZ";
	return "OTHER";
}

function jsrsDebugInfo(){
	// use for debugging by attaching to f1 (works with IE)
	// with onHelp = "return jsrsDebugInfo();" in the body tag
	var script = "";
	var doc = window.open().document;

	doc.open;
	doc.write( "Pool Size: " + jsrsContextPoolSize + "<br><font face='arial' size='2'><b>" );
	for( var i in jsrsContextPool ){
		var contextObj = jsrsContextPool[i];
		var errormsg = contextObj.getPayload();

		doc.write( "<hr>" + contextObj.id + " : " + (contextObj.busy ? "busy" : "available") + "<br>");
		doc.write( contextObj.container.document.location.pathname + "<br>");
		doc.write( contextObj.container.document.location.search + "<br>");
		doc.write( "<table border='1'><tr><td>" + errormsg + "</td></tr></table>" );
	}
	doc.write("</table>");
	doc.close();
	return false;
}
