/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

   AjaxEngine v1

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

var AjaxEngine={
	'method':'POST',
	'requestUri':'',
	'debug':false,
	'debugDivId':'ajaxEngineDebug',
	'debugReqDivId':'ajaxEngineDebug#',
	'debugReqLogDivId':'ajaxEngineDebug#Log',
	'debugWindow':false,
	'debugWindowObj':null,
	'debugDefaultStyle':true,
	'requests':new Array,
	'loaded':false
};

AjaxEngine.$=function(str,doc){
	var rv=null;
	if(str&&typeof(str)=='string'){
		doc=doc||document;
		rv=doc.getElementById(str);
	}
	return rv;
};

AjaxEngine.call=function(funcName,funcArgs){
	this.method=this.method.toUpperCase();
	var requestId=this.requestIdGenerate(funcName);
	this.requests[requestId]={
		'xhr':null
	};
	var r=this.requestObjectCreate(requestId);
	if(r){
		try{
			r.AjaxEngine={
				'requestId':requestId,
				'requestUri':this.requestUri
			};
		}catch(e){}
		this.requests[requestId].xhr=r;
		var uri=this.requestUri;
		var params='';
		var postData=null;
		uri+=(this.requestUri.indexOf('?')==-1)?'?':'&';
		params+='ajaxEFunc='+funcName;
		params+='&ajaxEReqId='+requestId;
		for(i=0;i<funcArgs.length;i++) params+='&ajaxEArgs[]='+encodeURIComponent(funcArgs[i]);
		var s=new Array();
		for(i=0;i<funcArgs.length;i++) s[i]='"'+funcArgs[i]+'"';
		this.trace(requestId,'[JS] AjaxEngine.call','<strong>Remote call:</strong> '+funcName+'('+s.join(',')+')<br /><strong>URI:</strong> '+uri+'<br /><strong>Params:</strong> '+params+'<br /><strong>Method:</strong> '+this.method);
		if(this.method=='GET') uri+=params;
		r.open(this.method,uri,true);
		if(this.method=='POST'){
			postData=params;
			var e;
			try{
				r.setRequestHeader('Method','POST '+uri+' HTTP/1.1');
				r.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
			}catch(e){
				this.debug(requestUri,'call','Can\'t create POST request.');
				return;
			}
		}
		r.onreadystatechange=function(){
			var obj=(navigator.userAgent.indexOf('MSIE 6')==-1)?this:r;
			if(obj.readyState!=4) return;
			if(obj.status==200){
				var requestId=AjaxEngine.requestIdGet(obj);
				AjaxEngine.trace(requestId,'[JS] AjaxEngine.call','<strong>Request status:</strong> '+obj.status+'<br /><strong>Received:</strong> '+AjaxEngine.htmlentities(obj.responseText));
				if(obj.responseXML&&obj.responseXML.documentElement) AjaxEngine.processResponse(requestId,obj.responseXML);
			}else{
				AjaxEngine.trace(requestId,'[JS] AjaxEngine.call','<strong>Request status:</strong> '+obj.status);
			}
		};
		r.send(postData);
		this.trace(requestId,'[JS] AjaxEngine.call','Sent. Waiting for returning data...');
	}
};

AjaxEngine.commandAlert=function(v){
	alert(v);
}

AjaxEngine.commandAssign=function(attr,v){
	var t=(typeof(attr.t)=='string')?this.$(attr.t):null;
	var a=(typeof(attr.a)=='string')?attr.a:'';
	if(t&&a&&typeof(t[a])=='string'){
		t[a]=v;
	}
}

AjaxEngine.commandInclude=function(str){
	var h=document.getElementsByTagName('head');
	var o=document.createElement('script');
	o.type='text/javascript';
	o.src=str;
	h[0].appendChild(o);
}

AjaxEngine.processResponse=function(requestId,response){
	this.trace(requestId,'[JS] AjaxEngine.processResponse','Data received. Processing...');
	var xml=response.documentElement;
	var a,c,i,j,n,o,t,v;
	var attr=new Array('a','t');
	var r=xml.childNodes[0];
	var errors=0;
	for(i=0;i<xml.childNodes.length;i++){
		n='[Unknown]';
		v='[void]';
		o=xml.childNodes[i];
		if(o.nodeType!=1) continue;
		if(o.nodeName=='cmd'){
			c=o.getAttribute('c');
			v=(o.firstChild)?o.firstChild.nodeValue:'';
			a=new Array();
			for(j in attr){
				if(t=o.getAttribute(attr[j])) a[attr[j]]=t;
			}
			try{
				if(c=='js'){
					n='JS Eval';
					v=v.replace(/[\n]/g,'\\'+'n');
					eval(v);
				}else if(c=='al'){
					n='Alert';
					this.commandAlert(v);
				}else if(c=='as'){
					n='Assign';
					this.commandAssign(a,v);
				}else if(c=='inc'){
					n='Include';
					this.commandInclude(v);
				}
			}catch(e){
				this.trace(requestId,'[JS] AjaxEngine.processResponse','Can\'t process "'+n+'" operation.\nValue: "'+v+'").\nEvent: '+e);
				errors++;
			}
		}
	}
	if(errors==0) this.trace(requestId,'[JS] AjaxEngine.processResponse','Data processing ended.');
	else this.trace(requestId,'[JS] AjaxEngine.processResponse','Process ended with '+errors+' error'+((errors>1)?'s':'')+'.');
	this.requests[requestId]=null;
};

AjaxEngine.htmlentities=function(str){
	str=str.replace(/&/g,'&amp;');
	str=str.replace(/</g,'&lt;');
	str=str.replace(/>/g,'&gt;');
	return str;
}

AjaxEngine.requestIdGenerate=function(prefix){
	var rv='',tmp;
	do{
		tmp=Math.random()+'';
		rv=prefix+tmp.substr(2);
		rv=rv.substr(0,16);
	}while(typeof(this.requests[rv])!='undefined'&&this.requests[rv]!=null);
	return rv;
};

AjaxEngine.requestIdGet=function(obj){
	var rv='Unknown';
	if(typeof(obj.AjaxEngine)!='undefined'){
		rv=obj.AjaxEngine.requestId;
	}else if(typeof(obj.responseText)=='string'){
		var r=new RegExp(' request="([^"]+)"');
		var t=r.exec(obj.responseText);
		if(typeof(t[1]!='undefined')) rv=t[1];
	}
	return rv;
}

AjaxEngine.requestObjectCreate=function(requestId){
	var rv=null;
	if(typeof XMLHttpRequest!='undefined') rv=new XMLHttpRequest();
	if(!rv){
		if(typeof(ActiveXObject)!='undefined'){
			try{rv=new ActiveXObject('Msxml2.XMLHTTP');}
			catch(e){
				try{rv=new ActiveXObject('Microsoft.XMLHTTP');}
				catch(e2){
					try{rv=new ActiveXObject('Msxml2.XMLHTTP.4.0');}
					catch(e3){
						rv=null;
					}
				}
			}
		}
	}
	if(!rv&&window.createRequest) req=window.createRequest();
	if(!rv) this.trace(requestId,'[JS] AjaxEngine.requestObjectCreate','Request object instantiation failed.');
	return rv;
}

AjaxEngine.timestamp=function(){
	var d=new Date();
	var rv=d.toString();
	return rv;
};

AjaxEngine.trace=function(requestId,func,str,clear){
	if(!this.debug) return;
	var doc=null,traceObj=null;
	if(this.debugWindow){
		if(!this.debugWindowObj){
			var h='<html><head><title>AjaxEngine debug window</title>';
			h+='<style type="text/css"><!-- pre{border:1px solid #aaa;margin:2px;} --></style>';
			h+='</head><body><h1>AjaxEngine debug</h1><div id="'+this.debugDivId+'"></div></body></html>';
			this.debugWindowObj=window.open('about:blank','AjaxEngine_Debug');
			if(this.debugWindowObj) this.debugWindowObj.document.write(h);
		}
		if(this.debugWindowObj){
			doc=this.debugWindowObj.document;
		}
	}else{
		doc=document;
	}
	traceObj=this.$(this.debugDivId,doc);
	if(!traceObj) traceObj=this.traceBuildContainer(doc);
	if(!traceObj) return;
	if(this.debugDefaultStyle){
		this.debugDefaultStyle=false;
		var elm=doc.createElement('style');
		elm.type='text/css';
		elm.innerHTML='\n<!--\n';
		elm.innerHTML+='#'+this.debugDivId+' div,#'+this.debugDivId+' a{padding:0 4px;}\n';
		elm.innerHTML+='#'+this.debugDivId+' div.title{margin-bottom:2px;}\n';
		elm.innerHTML+='#'+this.debugDivId+' div.title a{display:block;background-color:#eee;color:#000;font-weight:bold;text-decoration:none;}\n';
		elm.innerHTML+='-->\n';
		var h=doc.getElementsByTagName('head');
		if(h[0]) h[0].appendChild(elm);
	}
	var req=this.debugReqDivId.replace('#',requestId);
	var reqObj=this.$(req,doc);
	if(!reqObj){
		var more=(this.debugWindow)?'':'AjaxEngine.traceDisplay(\''+requestId+'\');';
		var reqObj=doc.createElement('div');
		reqObj.id=req;
		reqObj.className='title';
		reqObj.innerHTML='<a href="#Request-trace" onclick="'+more+'return(false);">Request <q>'+requestId+'</q></a>';
		reqObj=traceObj.insertBefore(reqObj,traceObj.firstChild);
	}
	if(!reqObj) return this.traceDefault(requestId,func,str);
	var reqLog=this.debugReqLogDivId.replace('#',requestId);
	var reqLogObj=this.$(reqLog,doc);
	if(!reqLogObj){
		var reqLogObj=doc.createElement('div');
		reqLogObj.id=reqLog;
		reqLogObj.className='log';
		reqLogObj=reqObj.insertBefore(reqLogObj,reqObj.firstChild.nextSibling);
	}
	if(!reqLogObj) return this.traceDefault(requestId,func,str);
	var elm=doc.createElement('div');
	elm.innerHTML='<div class="item"><strong>'+func+'()</strong> <em>'+this.timestamp()+'</em><div class="text">'+str+'</div></div>';
	reqLogObj.insertBefore(elm,reqLogObj.firstChild);
};

AjaxEngine.traceBuildContainer=function(doc){
	var elm=false;
	var b=doc.getElementsByTagName('body');
	if(typeof(b[0])!='undefined'){
		elm=doc.createElement('div');
		elm.id=this.debugDivId;
		elm=b[0].appendChild(elm);
	}
	return elm;
};

AjaxEngine.traceDefault=function(requestId,func,str){
	alert('AjaxEngine debug\n['+requestId+'] '+func+'()\n'+str);
};

AjaxEngine.traceDisplay=function(requestId){
	var elm=this.$(this.debugReqLogDivId.replace('#',requestId));
	if(elm){
		if(elm.style.display=='none') elm.style.display='';
		else elm.style.display='none';
	}
};

AjaxEngine.loaded=true;
