/*
Modified 2008-11-25 by Richter (richter@wpdom.com)
*/

function define(varName, value)
{
	window[varName]=value;
}

//document.write('<script type="text/javascript" src="./eajax.cfg"></script>');//Loading config (config file should be placed in the same folder, in which there is html-doc requiring this script file OR you should manually add including the config script file)

function urlEncode(uri)
{
  s = encodeURIComponent(uri);
  return s.replace(/~/g,'%7E').replace(/%20/g,'+');
}

function Channel()
{
	this.free  =true;
	this.func  =null;
	this.xhr   =null;
	this.iframe=null;
	this.form  =null;
}

var sChans=new Array(),dChans=new Array();//static and dynamic channels

function res(val,wnd)
{
	if (!wnd.name) return; // Stupid MSIE call this function twice when form submitted
	document.getElementById(wnd.name).channel.func(val);
}

// Creates a object for request
function getXMLHttpRequest()
{
  if (window.XMLHttpRequest) // For native XMLHttpRequest object
  {
  	try {req = new XMLHttpRequest();}
  	catch (e) {req = false;}
  }
  else if (window.ActiveXObject) // For IE/Windows ActiveX version
  {
  	try {req = new ActiveXObject("Msxml2.XMLHTTP");}
  	catch (e)
  	{
  		try {req = new ActiveXObject("Microsoft.XMLHTTP");}
  		catch (e) {req = false;}
  	}
  }
  return req;
}

// Simplified request (GET)
function simpleRequest(uri, vars)
{
  // Preparing of variables
  if (vars.length==null || vars.elements!=null) vars=[vars]; // Making var Array of containers
  var params=new Array();
  for (var i=0;i<vars.length;i++)
    for (p in vars[i])
      params.push({name : p,
        value : vars[i][p],
          toString : function () {return urlEncode(this.name)+'='+urlEncode(this.value)}});
  var qstring = params.join('&');

  var xmlhttp = getXMLHttpRequest();
  xmlhttp.open('GET', uri+'?'+qstring, true);
  xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4) {
      if (xmlhttp.status == 200) {
        func = function (val) {return eval(val)};

        var parent = {res:func};
        var mes = xmlhttp.responseText.replace(/<script>([^<]*)<\/script>/gi,function(str,code) {eval(code); return ''});

        if (mes) alert(mes.replace(/<br[^>]*>/gi,'\n')); // Possibly it is errors message
      }
    }
  }
  xmlhttp.send(null);
}

/* Parameters decription:
	uri:  request URI to which requests will be made; specify address of php-script, which process the request
	vars: {container | Array of containers}; container: {HTML Form Element | form name ("string") | assoc array ("object")}
	func: callback function (may be "eval" or null/undefined for JSON concept)
	channel: id Number for the channel or null/undefined for dynamic request channel creation; sending request via the sertain channel, in which prev request haven't finished, will override that prev request by stop them before starting new request
	is_long_request: set "true" if use POST-method (for instance in forms)
*/
function eajaxRequest(uri, vars, func, channel, is_long_request)
{
	if (typeof vars != 'object')
	{
		alert('eajaxRequest: Wrong parameter <vars>');
		return;
	}

	if (func==eval || func==null) func=function (val) {return eval(val)};//for stupid Opera

	if (vars.length==null || vars.elements!=null) vars=[vars];//making var Array of containers

	//Preparing query string
	var params=new Array();
	for (var i=0;i<vars.length;i++)
		switch (typeof vars[i])
		{
		case 'string':
			vars[i]=document.forms[vars[i]];
			i--;
			continue;
		case 'object':
			if (vars[i].nodeType==1 && typeof(vars[i].tagName)=='string' && vars[i].tagName.toLowerCase()=='form')//HTML Form Element
			{
				for (var j=0,els=vars[i].elements;j<els.length;j++)
					if (els[j].name) with (els[j])
						params.push({name : name,
									 value : value,
									 toString : function () {return urlEncode(this.name)+'='+urlEncode(this.value)}});
			}
			else//assoc array
			{
				for (p in vars[i])
					params.push({name : p,
								 value : vars[i][p],
								 toString : function () {return urlEncode(this.name)+'='+urlEncode(this.value)}});
			}
			break;
		default:
			alert('eajaxRequest: Wrong element in <vars> array');
			return;
		}

	var qstring=params.join('&');

	// Prepairing channel to transfer
	var chan;

	if (channel!=null) // Take a static channel
	{
		if (sChans[channel]==null)
		{
			chan=new Channel();
			sChans[channel]=chan;
		}
		else
		{
			chan=sChans[channel];
			if (!chan.free && chan.xhr)
				chan.xhr.abort();
		}
	}
	else//allocate dynamic channel
	{
		for (var i=0;i<dChans.length;i++)
			if (dChans[i].free)
			{
				chan=dChans[i];
				break;
			}

		if (i==dChans.length)
		{
			chan=new Channel();
			dChans.push(chan);
		}
	}

	chan.free = false;
	chan.func = func;

	function allocIFrame()
	{
		do var r=parseInt(Math.random()*1000000);
		while (window['iframe'+r]);

		var el=document.createElement('iframe');
		el.style.display='none';
		el.id=el.name='iframe'+r;
		document.getElementsByTagName('body')[0].appendChild(el);

		setTimeout(function ()//OnLoad event should be set up just when element would be created and page 'about:blank' loaded
		{
			el.onload=el.onload_=function ()//stupid MSIE
			{
			    //Здесь this везде заменено на el, т.к. Эксплорер чё-то глючит
				el.channel.free=true;
				clearTimeout(el.timeout);

				//_-This is need no more-_
	            //if (window[this.name].location.href=='about:blank') return;

				if (window[el.name].document.getElementsByTagName('meta').length) return;//primitive test for 404 error
				
				//Check for error messages
				var mes='';
				function traverseNode(node)
				{
					switch (node.nodeType)
					{
					case 1://ELEMENT_NODE
					    switch (node.tagName.toLowerCase())
					    {
						case 'br':
							mes+='\n';
							break;
						case 'script':
						    break;
						default:
							for (var i=0;i<node.childNodes.length;i++)
								traverseNode(node.childNodes[i]);
						    break;
						}
						break;
					case 3://TEXT_NODE
						mes+=node.data;
						break;
					}
				}
				var node=window[el.name].document.documentElement;
				//Нужно на случай, когда сервер ничего не возвращает (в этом случае в Опере node=null)
				if (node) traverseNode(node);//.getElementsByTagName('body')[0]);
				if (mes) alert(mes);
			};
			el.onreadystatechange=function () {if (this.readyState=='complete') this.onload_()};//for MSIE
		},0);

		/*window[el.name].res=func;

		if (channel==null)//dynamic channel
			el.timeout=setTimeout(function () {chan.free=true;},EAJAX_REQUEST_TIMEOUT),
			el.channel=chan;*/

		return el;
	}

	if ((uri.length+1+qstring.length>512) || is_long_request) // Use XmlHttpRequest
	{
		var req = chan.xhr; // False;

		if (!req)
		{
                  req = getXMLHttpRequest();
		}

		if (req)
		{
			chan.xhr = req;
			//req.channel = chan;
			if (channel==null)//dynamic channel
				var timeout=setTimeout(function () {req.abort(); chan.free=true;},EAJAX_REQUEST_TIMEOUT);

			req.onreadystatechange = function ()
			{
				if (req.readyState == 4) // If "complete"
				{
					if (req.status == 200)
					{
						var parent={res:func}; // Simple work around
						//function res(val) {this.channel.func(val)}
						var mes=req.responseText.replace(/<script>([^<]*)<\/script>/gi,function(str,code) {eval(code); return ''});
						if (mes) alert(mes.replace(/<br[^>]*>/gi,'\n')); // possibly it is errors message
						chan.free = true;
						clearTimeout(timeout);
					} else {
						alert("There was a problem retrieving the XML data:\n"+req.statusText);
					}
				}
			};
			req.open("POST", uri, true);
			if (!window.opera || req.setRequestHeader) // for Opera 8.0
				req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			//req.overrideMimeType('text/plain');
			req.send(qstring);
		}
		else // Form submit
		{
			if (!chan.iframe) chan.iframe=allocIFrame();
			setTimeout(function ()
			{
				with (window[chan.iframe.name])
					/*self.res=func,*/self.name=chan.iframe.name;
			},0);

			chan.iframe.channel=chan;
			if (channel==null)//dynamic channel
				chan.iframe.timeout=setTimeout(function () {chan.free=true;},EAJAX_REQUEST_TIMEOUT);

			if (chan.form) chan.form.parentNode.removeChild(chan.form);

			with (chan.form=document.createElement('form'))
				style.display='inline',action=uri,target=chan.iframe.name,method='post';

			for (var i=0;i<params.length;i++)
			{
				var el=document.createElement('input');
				el.type='hidden';
				el.name=params[i].name;
				el.value=params[i].value;
				chan.form.appendChild(el);
			}

			document.getElementsByTagName('body')[0].appendChild(chan.form);
			setTimeout(function () {chan.form.submit();},0);
		}
	}
	else // Use iframe.replace method, i.e. via GET
	{
		if (!chan.iframe) chan.iframe=allocIFrame();
		setTimeout(function ()
		{
			with (window[chan.iframe.name])
				/*self.res=func,*/self.name=chan.iframe.name,location.replace(uri+'?'+qstring);
		},0);

		chan.iframe.channel=chan;
		if (channel==null)//dynamic channel
			chan.iframe.timeout=setTimeout(function () {chan.free=true;},EAJAX_REQUEST_TIMEOUT);
	}
}