//
//	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
2.2	10 Aug 2003 - added Opera support
2.3(beta)	10 Oct 2003 - added Konqueror support - **needs more testing**
*/

// callback pool needs global scope
var jsrsContextPoolSize = 0;
var jsrsContextMaxPool = 10;
var jsrsContextPool = new Array();
var jsrsBrowser = jsrsBrowserSniff();
var jsrsPOST = true;
var containerName;

// constructor for context object
function jsrsContextObj( contextID ){
	
	// properties
	this.id = contextID;
	this.busy = true;
	this.callback = null;
	this.container = contextCreateContainer( contextID );
	
	// 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( 'afterBegin', '<span id="SPAN' + containerName + '"></span>' );
			var span = document.all( "SPAN" + containerName );
			span.style.display = 'none';
			var html = '<iframe name="' + containerName + '" src="/blank.asp"></iframe>';
			span.innerHTML = html;
			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;
			iframe.style.visibility = 'hidden';
			iframe.id = 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;

		case 'KONQ':	
			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;

			// Needs to be hidden for Konqueror, otherwise it'll appear on the page
			span.style.display = 'none';
			iframe.style.display = 'none';
			iframe.style.visibility = 'hidden';
			iframe.height = '0px';
			iframe.width = '0px';

			break;
	}
	return container;
}

function contextPOST( rsPage, func, parms ){
	var d = new Date();
	var unique = d.getTime() + '' + Math.floor(1000 * Math.random());
	var doc = (jsrsBrowser == "IE" ) ? this.container.document : this.container.contentDocument;
	if ( ! doc ) {
		return false;
	} // end if
	var content = '<html><body>';
	content += '<form name="jsrsForm" method="post" target="" ';
	content += ' action="' + rsPage + '?U=' + unique + '">';
	content += '<input type="hidden" name="C" value="' + this.id + '">';

	// func and parms are optional
	if (func != null){
		content += '<input type="hidden" name="F" value="' + func + '" />';
		if (parms != null){
			if (typeof(parms) == 'string'){
				// single parameter
				content += '<input type="hidden" name="P0" ' + 'value="[' + jsrsEscapeQQ(parms) + ']">';
			} else {
				// assume parms is array of strings
				for( var i=0; i < parms.length; i++ ){
					content += '<input type="hidden" name="P' + i + '" ' + 'value="[' + jsrsEscapeQQ(parms[i]) + ']">';
				} // end for
			} // parm type
		} // parms
	} // func
//alert(content);
	doc.open();
	doc.write( content + '</form></body></html>');
	doc.close();
	if ( doc.forms['jsrsForm'] )
		doc.forms['jsrsForm'].submit();
	return false;
}

function contextGET( rsPage, func, parms ){

	// build URL to call
	var URL = rsPage;

	// always send context
	URL += "?C=" + this.id;

	// 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+'') + "]";
			} else {
				// assume parms is array of strings
				for( var i=0; i < parms.length; i++ ){
					URL += "&P" + i + "=[" + escape(parms[i]+'') + "]";
				}
			} // parm type
		} // parms
	} // func

	// unique string to defeat cache
	var d = new Date();
	URL += "&U=" + d.getTime();
 
	// 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;
		case 'KONQ':
			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':
		if ( ! this.container.document.forms['jsrs_Form']['jsrs_Payload'] ) {
			//alert(this.container);
		} else {
			return this.container.document.forms['jsrs_Form']['jsrs_Payload'].value;
		} // end if
	case 'MOZ':
           if ( ! window.frames[this.container.name] ) {
                //alert('No frame for ' + this.container.name);
                var frame = $(this.container.name);
                var d = frame.document ? frame.document : frame.contentDocument;
                return d.forms['jsrs_Form']['jsrs_Payload'].value;
            } else {
            return window.frames[this.container.name].document.forms['jsrs_Form']['jsrs_Payload'].value;
            }

		case 'OPR':
			var textElement = window.frames[this.container.name].document.getElementById("jsrs_Payload");
			return textElement.value;
		case 'KONQ':
			return window.frames[this.container.name].document.forms['jsrs_Form']['jsrs_Payload'].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';
		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

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
	if ( jsrsContextPoolSize <= jsrsContextMaxPool ){
		// create new context
		var contextID = "jsrs" + (jsrsContextPoolSize + 1);
		jsrsContextPool[ contextID ] = new jsrsContextObj( contextID );
		jsrsContextPoolSize++;
		return contextID;
	} else {
		alert( "jsrs Error:	context pool full" );
		jsrsContextPoolSize = 0;
		return null;
	}
}

function jsrsExecute( rspage, callback, func, parms, 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
	// visibility	- optional boolean to make container visible for debugging

	// get context
	var contextObj = jsrsContextPool[ jsrsGetContextID() ];
	contextObj.callback = callback;

	var vis = (visibility == null)? false : visibility;
	contextObj.setVisibility( vis );

	if ( jsrsPOST && ((jsrsBrowser == 'IE') || (jsrsBrowser == 'MOZ'))){
		if ( ! contextObj.POST( rspage, func, parms ) ) {
			return false;
		} // end if
	} else {
		contextObj.GET( rspage, func, parms );
	}
	
	return contextObj.id;
}

function jsrsLoaded( contextID ){
	// get context object and invoke callback
	var contextObj = jsrsContextPool[ contextID ];
	if ( contextObj ) {
		if ( contextObj.callback != null ){
			contextObj.callback( jsrsUnescape( contextObj.getPayload() ), contextID );
		}
		// clean up and return context to pool
		contextObj.callback = null;
		contextObj.busy = false;
	} // end if
}

function jsrsError( contextID, str ){
	//alert( unescape(str) );
	jsrsContextPool[ contextID ].busy = false
}

function jsrsEscapeQQ( thing ){
	if ( typeof(thing) == 'string' ) {
		return thing.replace(/"/g, '&quot;');
	} else if ( typeof(thing) == 'number' ) {
		return thing;
	} else {
		//alert("jsrsEscapeQQ: " + thing + typeof(thing));
		return thing;
	} // end if
} // end function jsrsEscapeQQ( thing )

function jsrsUnescape( str ){
	// payload has slashes escaped with whacks
	//str = str.replace( /\&amp;/g, '&' );
	return str.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);
		var is_konq = (agt.indexOf("konqueror") != -1);
		if(is_opera) {
			return "OPR";
		} else {
			if(is_konq) {
				return "KONQ";
			} else {
				// Really is IE
				return "IE";
			}
		}
	} else if (document.getElementById) {
		var agt=navigator.userAgent.toLowerCase();
		if ( agt.indexOf('safari') != -1 ) {
			return 'MOZ';
		} // en dif
		return "MOZ";
	} // end if
	return "OTHER";
}

/////////////////////////////////////////////////
//
// user functions

function jsrsArrayFromString( s, delim ){
	// rebuild an array returned from server as string
	// optional delimiter defaults to ~
	var d = (delim == null)? '~' : delim;
	return s.split(d);
}

function jsrsDebugInfo(){
	// use for debugging by attaching to f1 (works with IE)
	// with onHelp = "return jsrsDebugInfo();" in the body tag
	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];
		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>' + contextObj.container.document.body.innerHTML + '</td></tr></table>' );
	}
	doc.write('</table>');
	doc.close();
	return false;
}

