/**
* 
* AJAX Engine
* 
*
*/

/** 
* Declare a constructor function to which we can add real functions
* @constructor
*/
function Engine(){}


/**
* The ActiveX objects to use when we want to convert an xml string into a 
* DOM object.
* @private
*/
Engine._DOMDocument = ["Msxml2.DOMDocument.5.0","Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"];

/**
*	The ActiveX objects to use when we want to do an XMLHttpRequest call.
*	@private
*/
Engine._XMLHTTP = ["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];

/**
* Constants
*/
/*Engine.CONTENT_TYPE = 'application/x-www-form-urlencoded; charset="UTF-8"';*/
Engine.CONTENT_TYPE = 'text/xml; charset="ISO-8859-1"';
Engine.READY_STATE  = 4;
Engine.CODE_STATUS  = 200;
Engine.METHOD_POST	= 'POST';
Engine.METHOD_GET	= 'GET';

Engine.setErrorHandler = function(handler){
	Engine._errorHandler = handler;
}

Engine.setWarningHandler = function(handler){
	Engine._warningHandler  = handler;
}

Engine.setPreHook = function(handler){
	Engine._preHook = handler;
}

Engine.setPostHook = function(handler){
	Engine._postHook = handler;
}

Engine._errorHandler   = Engine.defaultMessageHandler;
Engine._warningHandler = Engine.defaultMessageHandler;
Engine._preHook  = null;
Engine._postHook = null;
Engine._callbacks = {};
Engine._batch = null;
Engine._verb = 'POST';
Engine.singleRequest = false;

/**
* Helper to find an ActiveX object that works.
* @return An ActiveX object from the first string in the array not to die
*/
Engine._newXMLHttpRequest = function(){
	var	objectXMLHTTP;
	// Mozilla (Firefox)
	if(window.XMLHttpRequest){
		objectXMLHTTP = new XMLHttpRequest(); 
	}else{
		var leng = Engine._XMLHTTP.length;
		for(var i=0; i<leng; i++){
			try{
				objectXMLHTTP = new ActiveXObject(Engine._XMLHTTP[i]);
			}catch(ex){}
		}// End For
	}// End if
	return objectXMLHTTP;
}// End Engine._newActiveXObject

/**
*
*/
Engine._newDOMDocument = function(){
	var	objectDOMDocument;
	var leng = Engine._DOMDocument.length;
	for(var i=0; i<leng; i++){
		try{
			objectDOMDocument = new ActiveXObject(Engine._DOMDocument[i]);
		}catch(ex){}
	}// End For
	return objectDOMDocument;
}

/**
* Send a request to the server
* This method is called by JavaScript that is emitted by server
* @param path : The part of the URL after the host and before the exec bit without leading or trailing /s
* @param target : The ID
* @param async : boolean true asyn false sync
* @param method : POST or GET
* @param callback : The callback function to wich any returned data should be passed if this is null, any returned data will be ignored
* @private
*/
Engine._execute = function(path, target, async, method, func){
    //
    if(Engine._batch==null){
	    Engine.beginBatch(path, target, async, method);
    }
    // Get an unique ID for this call
    var random = Math.floor(Math.random()*10001);
    var id = (random+"_"+new Date().getTime()).toString();
    Engine._callbacks[id]=func;
    Engine._batch.metadata.id=id;
	Engine._sendData(Engine._batch);
    Engine.endBatch();
}// End Engine._execute

/*
* You can group severeal calls together using a batch.
* This saves on round trips to the server so there is much less latency involved.
* @see Engine.endBatch()
*/
Engine.beginBatch = function(path, target, async, method){
	if(Engine._batch){
		if(Engine._errorHandler){
			Engine._errorHandler(Engine.ERROR_MSG_BATCH_IN_PROGRESS);
		}
		return;
	}
    // Setup a batch
    Engine._batch = new Batch();
   	Engine._batch.async = async;
	Engine._batch.method = method;
    if(Engine.METHOD_GET==method){
    	Engine._batch.path = path;
	    Engine._batch.target = target;
	}else{
		var aform = path;
	    Engine._batch.path = aform.action;
	    Engine._batch.parameters = Engine.getParameters(aform);
	}
}//End Engine.beginBatch

/**
*
*/
Engine._sendData = function(batch){
	//
	if(Engine._preHook){
		Engine._preHook();
	}
	// Get setup for XMLHttpRequest
	batch.req = Engine._newXMLHttpRequest();
	//
	if(batch.req){
		try{
			if(Engine.METHOD_GET==batch.method){		
				batch.req.onreadystatechange = function(){Engine._stateChange(batch) };
				batch.req.open(Engine.METHOD_GET, batch.path);
				batch.req.setRequestHeader("Content-Type", Engine.CONTENT_TYPE);
				batch.req.send(null);
			}else{
				batch.req.onreadystatechange = function(){ Engine._stateChange(batch) };
				batch.req.open(Engine.METHOD_POST, batch.path, batch.async);
				//batch.req.setRequestHeader("Connection", "close");
				batch.req.setRequestHeader("Content-type", Engine.CONTENT_TYPE);
				batch.req.setRequestHeader("Content-length", batch.parameters.length);
				batch.req.send(batch.parameters);
			}
		}catch(ex){
			if(Engine._errorHandler){
				Engine._errorHandler(ex);
			}
		}
	}	
}//End Engine._sendData

/**
*
*/
Engine.getParameters = function(aform){
	var parameters = new Array() ;
	var elements = aform.elements;
	for(var i=0; i<elements.length;i++){
		var key = elements[i].name;
		var value = elements[i].value;
		if((key!=null && key!='') && (value!=null && value!='')){
			parameters.push(key+'='+encodeURIComponent(value));
		}
	}//End For
	return parameters.join('&');
}//End Engine.getParameters

/*
* 
* 
* @see Engine.beginBatch()
*/
Engine.endBatch = function(){
    if(Engine._batch == null){
	    if(Engine._errorHandler){
	    	Engine._errorHandler(Engine.MSG_NO_BATCH_IN_PROGRESS);
	    }
	    return;
	}
	Engine._batch = null;
	
}//End Engine.endBatch

/**
* Called by XMLHttpRequest to indicate that something has happend
*/
Engine._stateChange = function(batch){
	//
	if(batch.req.readyState == Engine.READY_STATE && !batch.completed){
   		try{
			var reply;
   			if(batch.metadata.xml==true){
   				reply = batch.req.responseXML;
   			}else{
   				reply = batch.req.responseText;
   			}
   			if(reply!=null && reply!=''){
   				if(batch.req.status && batch.req.status == Engine.CODE_STATUS){
	   				batch.completed = true;
					Engine._handleResponse(batch,reply);
   				}
   			}else{
   				Engine._stateChangeError(batch,reply);
   			}
   		}catch(ex){
   			Engine._stateChangeError(batch,ex);
   		}
   		Engine._finalize(batch);
   	}
	
}//End Engine._stateChange

/**
*
*/
Engine._finalize = function(batch){
    if (Engine._postHook){
        Engine._postHook();
    }    
}

/*
*
*/
Engine._stateChangeError = function(batch, message){

    if(batch.metadata != null){
        Engine._abortRequest(batch);
    }
    if(Engine._errorHandler){
        if(message==null){
        	Engine._errorHandler(Engine.ERROR_MSG_UNKNOWN);
        }else{
			Engine._errorHandler(message);
        }
    }
}//End Engine._stateChangeError

/*
*
*/
Engine._handleResponse = function(batch,reply){
	var id = batch.metadata.id;
	var func = Engine._callbacks[id];
	// 
	Engine._callbacks[id] = null;
	if(func){
		try{
			func(reply,batch.target);
		}catch(ex){
			if(Engine._errorHandler){
				Engine._errorHandler(ex);
			}
		}
	}
}// End Engine._handleResponse

/**
* Called as a result of a request timeout or an http reply status !=200
*
* @private
*/
Engine._abortRequest = function(batch){

    if(batch && batch.metadata && batch.completed != true){
    	batch.completed = true;
    	if(batch.req!=null){
	    	batch.req.abort();
	    	if(batch.metadata.errorHandler){
	    		if(typeof batch.metada.errorHandler=='function'){
	    			batch.metada.errorHandler();
	    		}else if(typeof batch.metada.errorHandler=='string' ){
	    			eval(batch.metada.errorHandler);
	    		}else if(Engine._warningHandler ){
	    			Engine._warningHandler(Engine.ERROR_MSG_INERRORHANDLER);
	    		}//	    	
	    	}
	    }
    }
}//End Engine._abortRequest

/**
 * The default message handler.
 * Useful in calls to setErrorHandler() or setWarningHandler() to allow you to
 * get the default back.
 * @param message The message to display to the user somehow
 */
Engine.defaultMessageHandler = function(message){
    if (typeof message == "object" && message.name == "Error" && message.description){
        alert("Error: " + message.description);
    }else{
        alert(message);
    }
}//End Engine.defaultMessageHandler


/*****************************
* Constants MESSAGES 
******************************/
Engine.ERROR_MSG_BATCH_IN_PROGRESS	  = 'Batch en funcionament';//Batch already started.';
Engine.ERROR_MSG_NO_BATCH_IN_PROGRESS = 'Cap request en progress';//'No batch in progress.';
Engine.ERROR_MSG_UNKNOWN = 				'Error desconegut';	//'Unknown error occured';
Engine.ERROR_MSG_NO_DATA_RECEIVED =		'El servidor no envia informació';	//'No data received from server';
Engine.ERROR_MSG_INERRORHANDLER =		'El errorHandler no és cap string ni funció';// 'errorHandler is neither a string (for eval()) or a function.';


