/* The TBLRequestor handles asynchronous data loading requests. */

function TBLRequestor() {}

TBLRequestor.staticrequestor=null;
TBLRequestor.XMLHttpRequest=1;
TBLRequestor.IFrame=2;
TBLRequestor.upstream=0;
TBLRequestor.downstream=0;

TBLRequestor._preHook=null;

TBLRequestor._postHook=null;

TBLRequestor._calls=new Object();

TBLRequestor._method=TBLRequestor.XMLHttpRequest; //default remoting method

TBLRequestor._paramCount=0;

/* clean up raw data reply */
TBLRequestor.cleanReply=function( reply ){
	var lines=reply.split('\n');
	var results=[];
	var z=lines.length;
	for(var i=0; i<z; i++){
		if(lines[i].length > 0){
			results[results.length]=lines[i];
		}
	}
	return results;
}

/* convert reply results to array object */
TBLRequestor.convertToObjectArray=function( reply ){
	var lines=TBLRequestor.cleanReply( reply );
	var header=lines[0];
	var columns=header.split("|");
	var datatypes=lines[1].split("|");

	var data=[];
	var count=data.length;
	var z=lines.length;
	for( var idx=2; idx<z; idx++ ){
		var parts=lines[idx].split("|");
		data[count]=[];
		var partsLength=parts.length;
		for( var partsIdx=0; partsIdx<partsLength; partsIdx++ ){
			data[count][columns[partsIdx]]=parts[partsIdx]; //data[1]['id']
		}
		count++;
	}
	return data;
}

TBLRequestor.setErrorHandler=function(handler){
	TBLRequestor._errorHandler=handler;
}

TBLRequestor.setPreHook=function(handler){
	TBLRequestor._preHook=handler;
}

TBLRequestor.setPostHook=function(handler){
	TBLRequestor._postHook=handler;
}

/* Set method to use for remoting */
TBLRequestor.setMethod=function(newmethod){
	if(newmethod != TBLRequestor.XMLHttpRequest && newmethod != TBLRequestor.IFrame){
		throw newmethod;
	}
	TBLRequestor._method=newmethod;
}

TBLRequestor._errorHandler=function(data){
	if(typeof data=="object" && data.name=="Error" && data.description){
		//DEBUG("Error: " + data.description);
	}
	else{
		//DEBUG(data);
	}
}

TBLRequestor.handleResponse=function(id, reply){
	var call=TBLRequestor._calls[id];
	if(call == null){
		var known="";
		for(call in TBLRequestor._calls){
			known += call + '\n';
		}
		//DEBUG("Internal Error: Call with id='"+id+"' unknown.I do know about the following:"+known);
		return;
	}

	TBLRequestor._calls[id]=undefined;

	if(call.iframe != null){
		call.iframe.parentNode.removeChild(call.iframe);
	}

	if(TBLRequestor._postHook != null){
		TBLRequestor._postHook();
	}

	if(call.callback == null){
		if (reply != null){
			//DEBUG("Missing callback for reply "+reply);
		}
	}else{
		try{
			call.callback(reply);
		}
		catch(ex){
			TBLRequestor._errorHandler(ex);
		}
	}

	call.callback=null;
	call.iframe=null;
	call.map.methodname=null;
	call.map.id=null;
	call.map=null;
	call.req=null;
	TBLRequestor._calls[id]=null;
}

TBLRequestor.handleError=function(id, reason){
	var call=TBLRequestor._calls[id];
	if(call != null){
		TBLRequestor._calls[id]=undefined;
		if(call.iframe != null){
			call.iframe.parentNode.removeChild(call.iframe);
		}
	}
	else { }

	if(TBLRequestor._postHook != null){
		TBLRequestor._postHook();
	}

	TBLRequestor._errorHandler(reason);
}

/* Execute HttpRequest */
TBLRequestor.execute=function(func, convertresults, path, param){

	if(func != null && typeof func != "function" && typeof func != "object"){
		//DEBUG("Supplied callback function is neither null nor a function: "+func);
		throw func;
	}

	var call=new Object();
	call.callback=func;
	call.convertresults=convertresults;

	// Cal unique ID
	//var random=Math.floor(Math.random() * 10001);
    // use timestamp instead
    var random=new Date().getTime();
	call.id=( path + "?r=" + random );

	TBLRequestor._calls[call.id]=call;

	if(TBLRequestor._preHook != null){
		TBLRequestor._preHook();
	}

	call.callback=func;

	// Build a map containing all the values to pass to the server.
	TBLRequestor._paramCount=0;

	call.map=new Object();
	call.map.id=call.id;

	// Get setup for XMLHttpRequest if possible
	if(TBLRequestor._method == TBLRequestor.XMLHttpRequest){
		if(window.XMLHttpRequest){
			call.req=new XMLHttpRequest();
		}
		else if(window.ActiveXObject && (!MAC)){
			call.req=new ActiveXObject("Microsoft.XMLHTTP");
			if(!call.req){
				//DEBUG("Creation of Microsoft.XMLHTTP failed.");
			}
		}
	}

	if(call.req){
		call.map.xml=true;

		// Proceed using XMLHttpRequest
		call.url=path + "?r=" + random;

		if(param){
			call.req.onreadystatechange=function() { TBLRequestor._stateChange(call,param); };
		}else{
			call.req.onreadystatechange=function() { TBLRequestor._stateChange(call); };
		}
		call.req.open("GET", call.url, true);
		call.req.send(null);
		TBLRequestor.upstream=TBLRequestor.upstream + call.url.length;
	}else{
		call.map.xml=false;

		// Proceed using iframe
		call.url=path + "?r=" + random;

		call.iframe=document.createElement('iframe');
		call.iframe.setAttribute('id', 'ddr-iframe');
		call.iframe.setAttribute('style', 'width:600px; height:100px; border:1px;');
		call.iframe.setAttribute('src', call.url);
		document.body.appendChild(call.iframe);
	}
}

/* Processes state changes from HttpRequest call */
TBLRequestor._stateChange=function(call, param){

	if(call.req.readyState == 4){
		if(call.req.status){
			try{
				if(call.req.status == 200){
					TBLRequestor.downstream += call.req.responseText.length;
					// convert text data results into array
					if( call.convertresults == 1 ){
						var data=TBLRequestor.convertToObjectArray( call.req.responseText );
						if(param){ call.callback( data, param ); }
						else{ call.callback( data ); }
					}
					// results as DOM XML obj
					else if( call.convertresults == 'xml'){
						if(param){ call.callback( call.req.responseXML, param ); }
						else{ call.callback( call.req.responseXML);}
					}
					// results as JSON
					else if( call.convertresults == 'json'){
						var json_text=call.req.responseText;
						var json_obj=eval( '(' + json_text + ')' );
						if(param){ call.callback( json_obj, param); }
						else{ call.callback( json_obj ); }
					}
					// text results
					else{
						if(param){ call.callback( call.req.responseText, param ); }
						else{ call.callback( call.req.responseText ); }
					}
				}else{
					TBLRequestor.handleError(call.id, call.req.responseText);
				}
			}
			catch(ex){
				TBLRequestor.handleError(call.id, ex);
			}
		}else{
			TBLRequestor.handleError(call.id, "No response from remote server.");
	        if(param){ call.callback( '', param ); }
            else{ call.callback( '' ); }
        }
	}
}
