/*	Ajax class

	Használati példa:

		var id = Ajax.call("id", "server.php", fupdate, Ajax.OP_SETHTML, {nodeId: "contentNode", post: {x: 1, y: 2} }, true);
			 Meghívja a server.php szkriptet az x=1,y=2 POST paraméterekkel, és a visszadott eredményt
			 a document.body tartalmába másolja. A betöltődéskor, meghívódik az fupdate függvény.
			 fupdate megadható 2 formában: 	- függvényNév		   	(a window objektum metódusa)
										   		- {obj: objektumNév, method: metódusNév}
			 A kérés szinkron módon történik.


		function fupdate(call)
		{
			if( call.aborted )	// ha a műveletet megszakították
			{
				...
			}
			else
			{
				...
			}
		}

*/

// Konstruktor, létrehozz egy Ajax objektumot.
function Ajax()
{
	try
	{
	    if (window.__AJAX == undefined)
	        window.__AJAX = [];

	    this.UID = Ajax.prototype.nextUID++;
	    this.self = "window.__AJAX["+this.UID+"].";

	    window.__AJAX[this.UID] = this;
	}
	catch (e) {};
}

Ajax.prototype =
{
	ST_UNINITIALIZED	: 0x0001,
	ST_UPLOADING		: 0x0002,
	ST_UPLOADED			: 0x0004,
	ST_DOWNLOADING		: 0x0008,
	ST_COMPLETED		: 0x0010,
	ST_ABORTED			: 0x0020,

	EV_ABORT			: 0x0001,
	EV_UL_START			: 0x0002,
	EV_DL_START			: 0x0004,
	EV_COMPLETE			: 0x0008,

	OP_NONE		    : 0x0000,		//	Nincs művelet
	OP_SETHTML		: 0x0001,		//	InnerHTML beállítás
	OP_REDIRECT		: 0x0002,		//	Ugrás adott URL címre
	OP_SELECT		: 0x0003,		//	Legördülő lista feltöltése
	OP_EVAL 		: 0x0004,		//	Kód végrehajtása
	OP_ALERT 		: 0x0005,		//	Szöveg megjelenítése
	OP_SETVALUE    	: 0x0006,		//	Űrlap egy elemének értékbeállítása
	OP_SAVERESPONSE : 0x0007,		//	Kapott tartalom mentése
	OP_AUTO		    : 0x00FF,		//	Automatikus
	calls			: {},
	nextUID			: 1,
	callTimer		: null,

	// Visszad egy XMLHttpRequest objektumot.
	http: function()
	{
		try{return new XMLHttpRequest();}catch(e){}

		var list = ['Microsoft.XMLHTTP', 'MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP'];
		for (var i=0;i<list.length;i++)
			try {return new ActiveXObject(list[i]);} catch(e) {}

		return false;
	},

    _serializeXData: function(v, pfx, res)
    {
    	if( typeof(v) == "object" )
    	{
    		res[pfx] = "";
    		for(var i in v)
    			this._serializeXData(v[i], pfx+"["+i+"]", res);
    	}
    	else if( pfx == "" )
    		res = v;
    	else
    		res[pfx] = v;
    },

	// Összeállít egy x-www-form-urlencoded stringet a megadott asszociatív tömb értékeiből.
	// data	: egy asszociatív tömb.
    serializeXData: function(v)
    {
		try
		{
        	if( typeof(v) != "object" )
        		return false;
        
        	var data = {};
        
        	for(var i in v)
        		this._serializeXData(v[i], i, data);
        
        	var res = [];
        	for(var i in data) 
        		res.push(encodeURIComponent(i)+"="+encodeURIComponent(data[i]));
        
        	return res.join("&");
		}
		catch (e) {return null};
    },
    
    /*

	// Összeállít egy x-www-form-urlencoded stringet a megadott asszociatív tömb értékeiből.
	// data	: egy asszociatív tömb.
	_composeData: function( data )
	{
		try
		{
			var res = "";
			for(var i in data) 
			    res += encodeURIComponent(i)+"="+encodeURIComponent(data[i])+"&";
			return res;

		}
		catch (e) {return null};
	},*/

	// Ajax müvelet indítása. Egy integer azonosítót ad vissza.
	// call_id	: kérés egyedi azonosítója
	// url		: a http kérés címe.
	// update	: a betöltés után visszahívandó callback függvény.
	// op		: a kért művelet. (pl.: Ajax.OP_SETHTML )
	// params	: opcionális paraméterek.
	//				post 	: a post-ként küldendő adatok tömbje. Ha meg van adva,
	//						  akkor a kérés metódusa POST lesz.
	//				get	 	: a get-ként küldendő adatok tömbje.
	//				nodeId	: OP_SETHTML esetén a cél node azonosítója.
	// sync		: ha true akkor a kérés szinkron módon történik
	call: function(call_id, url, update, op, params, sync)
	{
		try
		{
			this.stop(call_id);
			var call = {};
			call.id 	= call_id;					// A művelet azonosítája.
			call.url	= url;						// A http kérés címe.

			if( update && update.obj && update.method )
			{
				call.update_o = update.obj;
				call.update_m = update.method;
			}
			else
			{
				call.update_o = window;
				call.update_m = update;
			}

			if( params == null ) params = {};
			if( op == null ) op = false;
			if( sync )
				call.sync = true;
			else
				call.sync = false;

			call.op		= op;						// A kért művelet kódja.
			call.params = params;					// Opcionális paraméterek tömbbje.
			call.postString	= (params.post) ? Ajax.serializeXData( params.post ) : "";		// POST adatok, kódolt formában.
			call.getString	= (params.get) ? Ajax.serializeXData( params.get ) : "";		// GET adatok, kódolt formában.
			call.method 	= (params.post) ? "POST" : "GET";						// A kérés metódusa. (GET/POST)
			call.aborted 	= false;												// A kérés megszakítása. (Ajax.stop hivása esetén true lesz)
			call.state		= Ajax.ST_UNINITIALIZED;
			call.event		= false;
			call.prevState	= Ajax.ST_UNINITIALIZED;
			call.prevEvent	= false;
			
			this.calls[call.id] = call;		// A művelet bejegyzése.

			if( call.sync )
				return Ajax._call(call_id);

			clearTimeout(this.callTimer);
			this.callTimer = setTimeout("Ajax._call('"+call.id+"')",0);

			return true;
		}
		catch (e) {return false};
	},

	_call: function(call_id)
	{
		try
		{
			var call	= this.calls[call_id];
			call.http	= this.http();				// A HTTPRequest objektum.
			eval("call.http.onreadystatechange = function () {"+this.self+"_updateState('"+call.id+"');}");
			
			if( call.params.get )
			{
				if( call.url.indexOf("?") != -1)
					call.url += "&" + call.getString;
				else
					call.url += "?" + call.getString;
			}
			
			call.http.open(call.method, call.url, !call.sync);
			
			call.http.setRequestHeader("Cache-Control", "no-cache");
			call.http.setRequestHeader("If-Modified-Since", "Wed, 31 Dec 1980 00:00:00 GMT");
			call.http.setRequestHeader("Expires", "Wed, 31 Dec 1980 00:00:00 GMT");
			
			call.http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			if( call.params.post )
				call.http.setRequestHeader("Content-length", call.postString.length );
			//call.http.setRequestHeader("Connection", "close");
			call.http.send( call.postString );
			if( call.sync )
				Ajax._updateState(call.id);
		}
		catch(e){};
	},

	// Megszakítja a megadott azonosítójú müveletet.
	// call_id	: a művelet azonosítója.
	stop: function( call_id )
	{
		try
		{

			var call = this.calls[call_id];
			if( call )
			{
				call.aborted = true;
				call.http.abort();
			}
		}
		catch (e) {};
	},

	// Visszadja az aktuális művelet állapotát.
	// call_id	: a művelet azonosítója.
	getState: function( call_id )
	{
		try
		{

			var call = this.calls[call_id];
			return call.status;

		}
		catch (e) {return null};
	},

	// Visszadja az aktuális művelet HTTP státuszát.
	// call_id	: a művelet azonosítója.
	getHttpStatus: function( call_id )
	{
		try
		{
			var call = this.calls[call_id];
			return call.http.status;
		}
		catch (e) {return null};
	},

	// readyState értékek:
	// 0 - uninitialized
	// 1 - loading
	// 2 - loaded
	// 3 - interactive
	// 4 - completed

	// Visszadja az aktuális művelet HTTP.readyState állapotát.
	// call_id	: a művelet azonosítója.
	getReadyState: function( call_id )
	{
		try
		{
			var call = this.calls[call_id];
			return call.http.readyState;
		}
		catch (e) {return null};
	},

	processOperation: function(call_id,op, responseText, params)
	{
		switch( op )
		{
			case this.OP_SETHTML	:	if( document.getElementById(params.nodeId) )
			                                document.getElementById(params.nodeId).innerHTML = responseText;
							 			break;
			case this.OP_REDIRECT	:	var redirect_url = responseText;
			                            if( redirect_url )
			                                window.location = redirect_url;
							 			break;
			case this.OP_SELECT		:	try
											{eval("var list="+responseText);}
										catch(e)
											{var list = [];}

										var node = document.getElementById(params.nodeId);
										if( node && (node.nodeName == "SELECT") )
										{
											node.innerHTML = "";
											node.length = 0;
											for(var i=0;i<list.length;i++)
											{
												node.length++;
												node.options[i].value = list[i].value;
												node.options[i].text = list[i].text;
											}
										}
										break;
	        case this.OP_EVAL       :   if( responseText )
	                                        eval(responseText);
	                                    break;
	        case this.OP_ALERT      :   if( responseText )
	                                        alert(responseText);
	                                    break;
	        case this.OP_SETVALUE   :   if( (form=document.forms[params.formName]) )
	                                       if( form.elements[params.inputName] )
	                                           form.elements[params.inputName].value = responseText;
	                                    break;
	        case this.OP_SAVERESPONSE:  this.calls[call_id]['responseText'] = responseText;
	                                    break;
		    case this.OP_AUTO       :   try
											{eval("var responseParam="+responseText);}
										catch(e)
											{var responseParam = {"op":this.OP_NONE, "responsetext" : "", "param": {} };}

		                                this.processOperation(call_id,responseParam.op, responseParam.responsetext, responseParam.param);
		                                break;
		}
    },
    
    getResponseText: function(call_id)
    {
        if( this.calls[call_id] )
            if( this.calls[call_id]['responseText'] )
                return this.calls[call_id]['responseText']        ;
                
        return null;
    },

	// A betöltési események kezelője. Ha a betöltés kész, vagy hiba lépett fel,
	// akkor meghívja az Ajax.call fügvénynél megadott update függvényt,
	// és átadja a call objektumot paraméterként.
	// call_id: a művelet azonosítója.
	_updateState: function( call_id )
	{
		try
		{
			var call = this.calls[call_id];

			call.prevState = call.state;
			call.prevEvent = call.event;

			switch( Ajax.getReadyState( call.id ) )
			{
				case 0 : call.state	= Ajax.ST_UNINITIALIZED;
						 call.event	= false;
						 break;
				case 1 : call.state = Ajax.ST_UPLOADING;
						 call.event = Ajax.EV_UL_START;
						 break;
				case 2 : call.state = Ajax.ST_UPLOADED;
						 call.event = false;
						 break;
				case 3 : call.state	= Ajax.ST_DOWNLOADING;
						 call.event	= Ajax.EV_DL_START;
						 break;
				case 4 : call.state = Ajax.ST_COMPLETED;
						 call.event = Ajax.EV_COMPLETE;
						 break;
			}

			if( call.aborted )
			{
				call.state	= Ajax.ST_ABORTED;
				call.event 	= Ajax.EV_ABORT;
			}

			if( call.event && (call.event != call.prevEvent) )
			{
				if( (call.state == Ajax.ST_COMPLETED) && (Ajax.getHttpStatus( call.id ) == 200) )
				{
				    this.processOperation(call_id,call.op,call.http.responseText,call.params);
				}

				if( call.update_o && call.update_m )
					call.update_o[call.update_m]( call );

			}
		}
		catch (e) {};
	}
}



window.Ajax = new Ajax();

