Ajax =function( o ){
	this.clearCache()
	this.extend([ o ? o : {} , Ajax.oDefaultSettings ] , true )
	}

Ajax.extend({
	oDefaultSettings :{
		bCache : false,
		bDebug : false,
		bMode : true,
		bParallel : true,
		sMethod : "GET" , // || "POST"
		sParameters : "",
		sResponseType : "js" // || "xml" || "text"
		},
	_onerror :function( o ){
		var a = [ "url" , "description" , "message" , "responseHeaders" , "responseText" , "responseType" ]
		, aDesc = []
		a.each( function( s ){ o[s] ? aDesc.push( s + " = " + o[s] ) : "" }, [String])
		throw new Error ( "Ajax :: \n" + aDesc.join ( ", \n" ))
		},
	_onstatechange :function( o , n ){
		return function(){
			if( ! o ) return ;
			var o1 = o.aInfo[n]
			, o2 = o1.oRequest
			if( o2 && o2.readyState == 4 ){
				var b = false
				try{ b = in_array( o2.status , [ 200 , 404 , 403 ])}catch( e ){ return false }
				if( b ){
					o.aInfo[n].status = o2.status
					o[ "_onreply" ]( n )
					o.aInfo[n].oRequest = null
					} else Ajax._onerror({ message: "HTTP protocol ???" })
				}
			}
		}
	})

Ajax.prototype.extend ({
	clearCache :function(){
		this.aInfo = []
		this.oCache = {GET:{js:{},xml:{},text:{}},POST:{js:{},xml:{},text:{}}}
		},
	get :function( sUrl , sResponseType , s , o , bDebug ){
		var oRestore = {
			sMethod : this.sMethod,
			sResponseType : this.sResponseType
			}
		this.sMethod = 'GET'
		this.sResponseType = sResponseType
		var n = this.send( sUrl , s , o , bDebug )
		this.extend( oRestore )
		return n
		},
	post :function( sUrl , sResponseType , s , o , bDebug ){
		var a = sUrl.split( "?" )
		, oRestore = {
			sMethod : this.sMethod ,
			sResponseType : this.sResponseType ,
			sParameters : ''
			}
		this.sMethod = 'POST'
		this.sResponseType = sResponseType
		this.sParameters = a[1] || ""
		var n = this.send( a[0] , s , o , bDebug )
		this.extend( oRestore )
		return n
		},
	remove :function( sUrl , sMethod , sResponseType ){
		var oCache = this.oCache[ sMethod ][ sResponseType ]
		, sCacheID = sUrl
		if( ! oCache ) Ajax._onerror({ message : 'Cache error' })
		if( ! isNaN( oCache[ sCacheID ])){
			var n = oCache[ sCacheID ]
			delete oCache[ sCacheID ]
			this.aInfo[n] = 0
			}
		},
	send :function( sUrl , s , o , bDebug ){
		var sResponseType = this.sResponseType.toLowerCase()
		, sMethod = this.sMethod
		, sParameters = this.sParameters
		if( this.bDebug || bDebug )
			switch( sMethod ){
				case 'GET' : return window.open( sUrl , "" , "" )
				case 'POST' :
					var eForm = Tag( 'FORM' , { method: 'POST' , action: sUrl , target: '_blank' })
					, a = sParameters.split( "&" )
					for( var i = 0 , ni = a.length ; i < ni ; i++ ){
						var ai = a[i].split( "=" )
						eForm.appendChild( Tag( "INPUT" , { name: ai[0] , value:ai[1] , type:'hidden' }))
						}
					var e = getElementsByTagName( "BODY" )[0]
					e.appendChild( eForm )
					eForm.submit()
					return e.removeChild( eForm )
				}
		if( this.bCache ){
			var oCache = this.oCache[ sMethod ][ sResponseType ]
			, sCacheID = sUrl + ( sParameters ? '?' + sParameters : '' )
			if( ! oCache ) Ajax._onerror({ message : 'Cache error.' })
			if( ! isNaN( oCache[ sCacheID ])) return this._process( oCache[ sCacheID ] , true )
			}
		var n = this.aInfo.length
		, s = s || this.sFunction
		, o = o || this.oInstance
		, f = function(){
			return window.XMLHttpRequest 
				? new XMLHttpRequest ()
				: ( window.ActiveXObject ? new ActiveXObject ( "Microsoft.XMLHTTP" ) : 0 )
			}
		if( this.bParallel ) var oRequest = f()
		else if( ! this.oRequest ) this.oRequest = oRequest = f()
		else oRequest = this.oRequest
		
		if( ! oRequest ) return Ajax._onerror({ message : 'Your browser cannot handle Ajax.' })
		this.aInfo[n] = {
			dSend: new Date (),
			oInstance: o,
			oRequest: oRequest,
			sFunction: s,
			sMethod: sMethod,
			sParameters: sParameters,
			sResponseType: sResponseType ,
			sUrl: sUrl
			}
		oRequest.onreadystatechange = Ajax._onstatechange( this , n )
		oRequest.open( sMethod, sUrl , this.bMode )
		if( sMethod == "POST" ){
			sParameters = str_replace([ "%" , "+" ] , [ "%25" , "%2B" ] , sParameters )
			oRequest.setRequestHeader( "Content-type" , "application/x-www-form-urlencoded" );
			oRequest.setRequestHeader( "Content-length" , sParameters.length );
			oRequest.setRequestHeader( "Connection" , "close" );
			}
		oRequest.send( sMethod == "GET" ? null : sParameters )
		return n
		},
	_onreply :function( n ){
		var m , o , oInfo = this.aInfo[n]
		oInfo.sReceive = new Date ().getTime() - oInfo.dSend.getTime() + "ms"
		try{
			if( oInfo.status == 200 )
				switch( oInfo.sResponseType ){
					case "js" : eval( "m = " + oInfo.oRequest.responseText ); break
					case "text" : m = oInfo.oRequest.responseText ; break
					case "xml" : 
						o = oInfo.oRequest.responseXML
						m = o ? o.documentElement : null
						break
					default: Ajax._onerror({ message : "Response type unknown." })
					}
			}catch(e){
				Ajax._onerror({
					description: e.description,
					url: oInfo.sUrl,
					responseType: oInfo.sResponseType,
					responseText: oInfo.oRequest.responseText,
					message: e.message
					})
				 }
		oInfo.mResponse = m || ""
		if( this.bCache ){
			var sCacheID = oInfo.sUrl + ( oInfo.sParameters ? '?' + oInfo.sParameters : '' )
			this.oCache[ oInfo.sMethod ][ oInfo.sResponseType ][ sCacheID ] = n
			}
		this._process( n )
		},
	_process :function( n1 , b ){
		var oInfo = this.aInfo[n1]
		, b = b || false
		, m = oInfo.mResponse || ''
		var mFunction = oInfo.sFunction 
		, o = oInfo.oInstance
		if( o ) o[ mFunction ].call( o , m , b )
			else if( mFunction ){
				var f = mFunction.constructor == Function ? mFunction : eval( mFunction )
				if( f && f.constructor == Function ) f( m , b )
				}
		if( ! b ) oInfo.sEnd = new Date ().getTime() - oInfo.dSend.getTime() + "ms"
		if( ! this.bCache ) this.aInfo[n1] = 0
		return n1
		}
	})
	
AJAX_LOADED = true
