// Copyright (c) 2007 Ric Hardacre 
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

// filename    : cyclomedia_ajax.js
// description : ajax request functions
// namespace   : all functions and variables are prefixxed "ajax_"
// www         : http://www.cyclomedia.co.uk/ajax/
// author      : Ric Hardacre
// email       : ric.hardacre at above domain


var ajax_release_version = "1.0.0";
var ajax_release_date    = "2007-03-15";
var ajax_enabled         = ( window.XMLHttpRequest || window.ActiveXObject );


// TODO
// make it easier for users to generate post / get requests with a custom field/value collection and encoder
// similar to ASP's Request.Form - but in reverse? some kind of parseForm( formName ) function might be a 
// cool way of submitting a form via ajax.


//request a string from the given URL
function ajax_RequestString( hCallback , URL , POST , userObject )
{
	return ajax_CreateRequest( hCallback , URL , POST , userObject , ajax_requestType_string )
}





//constants
var ajax_requestType_null   = 0;
var ajax_requestType_string = 1;

var ajax_statusCode_null    = 0;
var ajax_statusCode_ok      = 200;
var ajax_statusCode_error   = 500;
var ajax_statusCode_user    = 600;
//you can also send your own status codes provided they are > 599 and < 1000



//delocalize newlines
function ajax_newlines( s )
{
    return s.replace(/\r\n|\r/g,"\n")
}

// spawns and returns a requestObject
function ajax_CreateRequest( hCallback , sURL , sPost , userObject , requestType  )
{
    if( !hCallback || !ajax_enabled )
        return null;
       
    var hRO = new ajax_requestObject( hCallback , sURL , sPost , userObject , requestType )
    
    if( !hRO.HttpRequest )
        hRO = null;
        
    return hRO;
} 

// AJAX request object

// hCallback	= handle to callback function
// sURL			= url to make request to
// sPost		= POST form data to send (leave as "" for GET request)
// userObject   = user var - passed to callback
// requestType	= request type enum
function ajax_requestObject( hCallback , sURL , sPost , userObject , requestType  )
{
	var me              = this;
	this.hCallback      = hCallback;
	this.URL            = sURL;
	this.POST           = sPost;
	this.requestType	= requestType;
	this.userObject     = userObject;
	this.retry          = function(){ ajax_retry( me ); };

	//spawn and attatch the request
	this.HttpRequest	= ajax_spawnRequest( me );
}	

// create a native httpRequest object from the paramrs in a requestObject and return
// hRO		= handle to request object
function ajax_spawnRequest( hRO )
{
	var l_HttpRequest = null;
	
	if( window.XMLHttpRequest )	//FF,NS,OP,IE7
	{
		l_HttpRequest = new XMLHttpRequest();
	}
	else
	if( window.ActiveXObject )	//IE5/6
	{
		l_HttpRequest = new ActiveXObject("Microsoft.XMLHTTP"); 
	}

	if( l_HttpRequest )
	{
		if( hRO.POST != "" )
		{
			l_HttpRequest.open( 'POST', hRO.URL , true );
			l_HttpRequest.setRequestHeader('Content-type','application/x-www-form-urlencoded');
			l_HttpRequest.onreadystatechange = function(){ ajax_stateChange( hRO ); };
			l_HttpRequest.send( hRO.POST );	
		}
		else
		{
			l_HttpRequest.open( 'GET', hRO.URL , true );
			l_HttpRequest.onreadystatechange = function(){ ajax_stateChange( hRO ); };
			l_HttpRequest.send( null );	
		}
	}
	
	return l_HttpRequest;
}

// .retry() - resends a request
// hRO		= request object
function ajax_retry( hRO )
{
	//dont usurp a request in action
	if( hRO.HttpRequest && hRO.HttpRequest.readyState != 4 )
		return;
		
	hRO.HttpRequest = ajax_spawnRequest( hRO );
}

// ..onreadystatechange()
// hRO		= request object
function ajax_stateChange( hRO )
{
    //got a response?
	if( hRO && hRO.HttpRequest && hRO.HttpRequest.readyState == 4 )
	{
		var s = hRO.HttpRequest.responseText;
		var f = hRO.hCallback;
		
		//if the http status is 200 then we have a response!
		var statusCode = ajax_statusCode_error;
		if( hRO.HttpRequest.status == "200" )
		{
			//attempt to convert the first three chars into an int to get the ajax_status code
		    statusCode = parseInt( s.substr(0,3) );
		    
		    //bound to know codes but allow user to pass through 600 etc.
		    if( statusCode != ajax_statusCode_ok && statusCode != ajax_statusCode_error && statusCode < ajax_statusCode_user )
		        statusCode = ajax_statusCode_error;
		}
		
		// user recieves a null object if the status = 500
		// but they can still manually get to the http request response text if they need to
		var obj = null;
		if( statusCode == ajax_statusCode_ok || statusCode >= ajax_statusCode_user )
		{
			if( hRO.requestType == ajax_requestType_string )
				obj = s.substring(4)
		}
		
        //invoke user callback
		f( obj , statusCode , hRO );
	}
}

