
/*
 * SimpleServerBETA 
 * Provides an interface to the browser's asyncronous communication object,
 * along with some simple encoding\decoding apis.
*/ 

////////////////////////////////////////////////////////////////////////////
/// GLOBAL instance of the Server object for general use...
var SERVER;

////////////////////////////////////////////////////////////////////////////
/// Holds reference to Server instance that is currently waiting on response...
var ActiveServer;

function Server(){
	
	this.reqObj   = null;
	this.resTxt   = null;
	this.error    = false;
	this.notify   = null;
	this.base64   = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	
	////////////////////////////////////////////////////////////////////////////
	/// Set the method that will be called when transfer is complete...
	this.setNotify  = function(notifyMethod){
		this.notify = notifyMethod;
	}
	
	////////////////////////////////////////////////////////////////////////////
	/// Get the data returned by the servers...
	this.getContent = function(){
		return this.resTxt;
	}
	
	////////////////////////////////////////////////////////////////////////////
	/// Get the HTTP status code returned by the server...
	this.getStatus  = function(){
		return this.resSta;
	}
	
	////////////////////////////////////////////////////////////////////////////
	/// Initialize the server instance (always call this before using do(GET|POST) 
	this.init = function(){
		this.createReqObj();
	}
	
	////////////////////////////////////////////////////////////////////////////
	/// Private utility for detecting which browser we're running in and creating request object...
	this.createReqObj = function(){	
		if(window.ActiveXObject){
           this.reqObj = new ActiveXObject("Microsoft.XMLHTTP");
   		}else if(window.XMLHttpRequest){
           this.reqObj = new XMLHttpRequest();
        }
        this.error = (this.reqObj == null);  
	}
	
	////////////////////////////////////////////////////////////////////////////
	/// Execute a GET request to the given URL...
	this.doGET = function(url, callback){
		if(this.error)
		   return false;
 		
		if(callback != null)
		   this.setNotify(callback);   
		   
		ActiveServer = this; 
		this.reqObj.open('GET', url, true);
		this.reqObj.setRequestHeader("Connection", "close");
		this.reqObj.onreadystatechange = handleResponse;
		this.reqObj.send('');
	}
	
	////////////////////////////////////////////////////////////////////////////
	/// Execute a POST request to the given URL, NOTE: use the paramString method
	/// to prepare the content of the request...
	this.doPOST = function(url, content, callback){
		if(this.error)
		   return false;
		
		if(callback != null)
		   this.setNotify(callback);   
		   
		ActiveServer = this;   
		this.reqObj.open('POST', url, true);
		this.reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		this.reqObj.setRequestHeader("Content-length", content.length);
		this.reqObj.setRequestHeader("Connection", "close");
		this.reqObj.onreadystatechange = handleResponse;
		this.reqObj.send(content);		
	}
	
	
	////////////////////////////////////////////////////////////////////////////
	/// Creates a proper param string for you from an array of keys and array of corresponding values...
	this.paramString = function(keys, values){
		i = 0;
		s = '';
		if(keys.length != values.length)
		   return false;
		for(; i < keys.length; i++){
			s += keys[i] + "=" + this.urlencode(values[i]) + "&";
		}
		s = s.substr(0, s.length - 1);
		return s;
	}
	
	////////////////////////////////////////////////////////////////////////////
	/// Hex encodes a string of data...
	this.urlencode = function(data){
		return escape(data);
	}
	
	////////////////////////////////////////////////////////////////////////////
	/// Base64 (RFC 1421 & RFC 2045) encodes a string of data...
	this.base64_encode = function(input){
		var output = '';
   		var chr1, chr2, chr3;
   		var enc1, enc2, enc3, enc4;
   		i = 0;

   		do {
      	   chr1 = input.charCodeAt(i++);
      	   chr2 = input.charCodeAt(i++);
      	   chr3 = input.charCodeAt(i++);

      	   enc1 = chr1  >> 2;
      	   enc2 = ((chr1 & 3)  << 4) | (chr2 >> 4);
      	   enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      	   enc4 = chr3   & 63;

           if (isNaN(chr2)) {
               enc3 = enc4 = 64;
           }else if(isNaN(chr3)) {
               enc4 = 64;
           }
           output = output + this.base64.charAt(enc1) + this.base64.charAt(enc2) + 
           this.base64.charAt(enc3) + this.base64.charAt(enc4);
   		}while (i < input.length);
   
        return output;
	}
	
	////////////////////////////////////////////////////////////////////////////
	/// Base64 decodes a string of data that was encoded using the above method...
	this.base64_decode = function(input){
	    var output = "";
        var chr1, chr2, chr3;
   		var enc1, enc2, enc3, enc4;
   		var i = 0;
   		
   		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

   		do {
      	   enc1 = this.base64.indexOf(input.charAt(i++));
      	   enc2 = this.base64.indexOf(input.charAt(i++));
           enc3 = this.base64.indexOf(input.charAt(i++));
      	   enc4 = this.base64.indexOf(input.charAt(i++));

      	   chr1 = (enc1 << 2) | (enc2 >> 4);
           chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
           chr3 = ((enc3 & 3)  << 6) | enc4;

      	   output = output + String.fromCharCode(chr1);

      	   if(enc3 != 64) {
               output = output + String.fromCharCode(chr2);
           }
      	   if(enc4 != 64) {
               output = output + String.fromCharCode(chr3);
      	   }
   		}while (i < input.length);

        return output;	
		
	}
	
	
}

///////////////////////////////////////////////////////////////////////////
/// [SHARED] callback used by all ServerInstances...
function handleResponse(){
	if(ActiveServer.reqObj.readyState == 4){
		 ActiveServer.resSta = ActiveServer.reqObj.status;
		 ActiveServer.resTxt = ActiveServer.reqObj.responseText;
		 if(ActiveServer.notify != null)
			  ActiveServer.notify();
	}
}

////////////////////////////////////////////////////////////////////////////
/// Initialize the GLOBAL server instance...
   SERVER = new Server(); 
   SERVER.init();
    
    
  
