/************************************************************************************************************/
/* general																									*/
/************************************************************************************************************/

// removes all child nodes from passed node
function removeChildNodes(node)
{
	while (node.hasChildNodes())
	{
		node.removeChild(node.firstChild);
	}
}

/************************************************************************************************************/
/* ajax_exception																							*/
/************************************************************************************************************/

function ajax_error(message)
{
	this.message = message;
	this.name = "AjaxError";
}

new ajax_error();

// extend Error class
ajax_error.prototype = new Error();

ajax_error.prototype.toString = function()
{
	return this.name +  ": " + this.message;
}

/************************************************************************************************************/
/* ajax_preloader																							*/
/************************************************************************************************************/

function ajax_preloader()
{
	this.displayed = false;
}

ajax_preloader.prototype.display = function(){}

ajax_preloader.prototype.hide = function(){}

ajax_preloader.prototype.setParent = function(parentNode){}

/************************************************************************************************************/
/* admin_preloader																							*/
/************************************************************************************************************/

function admin_preloader()
{
	this.displayed = false;
	this.parentNode;
	this.preloaderNode;
}

/**
 * @extends ajax_preloader
 */
admin_preloader.prototype = new ajax_preloader();

/**
 * Implementation of display method
 */
admin_preloader.prototype.display = function()
{
	function findPosX(obj)
	{
		var curleft = 0;

		if (obj.offsetParent)
		{
			while(true) 
			{
				curleft += obj.offsetLeft;
				
				if(!obj.offsetParent)
				{
					break;
				}
				
				obj = obj.offsetParent;
			}
		}
		else if(obj.x)
		{
			curleft += obj.x;
		}
		
		return curleft;
	}

	function findPosY(obj)
	{
		var curtop = 0;
		
		if (obj.offsetParent)
		{
			while(true)
			{
				curtop += obj.offsetTop;
				
				if (!obj.offsetParent)
				{
					break;
				}
				
				obj = obj.offsetParent;
			}
		}
		else if(obj.y)
		{
			curtop += obj.y;
		}
		
		return curtop;
	}
	
	this.hide();

	var div = document.createElement("div");
	var img = document.createElement("img");

	this.preloaderNode = div;

	img.src = CONST_ADMIN_FRONT+'img/preloader.gif';
	img.width = 150;
	img.height = 13;

	div.id = 'ajax-preloader';
	div.style.position = 'absolute';
	div.style.top = findPosY(this.getParent())+20+'px';
	div.style.left = findPosX(this.getParent())+(Math.round(this.getParent().offsetWidth / 2))-Math.round(img.width / 2)+'px';
	div.style.backgroundColor = 'White';
	div.style.padding = '6px';
	div.style.border = '1px solid #96989B';
	div.appendChild(img);

	this.getParent().appendChild(div);
	this.displayed = true;
}

/**
 * Implementation of hide method
 */
admin_preloader.prototype.hide = function()
{
	var div = document.getElementById('ajax-preloader');

	if (this.displayed)
	{
		try
		{
			this.getParent().removeChild(this.preloaderNode);
		}
		catch (e)
		{}
		
		this.displayed = false;
	}
}

admin_preloader.prototype.setParent = function(parentNode)
{
	this.parentNode = parentNode;
}

admin_preloader.prototype.getParent = function()
{
	if (!this.parentNode)
	{
		this.parentNode = document.body;
	}
	
	return this.parentNode;
}

/************************************************************************************************************/
/* ajax_request																								*/
/************************************************************************************************************/

function ajax_request()
{
	this.xmlhttp = (window.XMLHttpRequest ? new XMLHttpRequest : (window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : false));
	this.handler = new Object();
	this.url;
	this.method = 'GET';
	this.content;
	this.headers = new Array();
	this.checkXmlResponse = true;
	this.trace;
	this.preloader;
}

new ajax_request();

ajax_request.prototype.setHandler = function(handlerName, handlerParameter)
{
	this.handler.name = handlerName;
	this.handler.parameter = handlerParameter;
}

ajax_request.prototype.setUrl = function(url)
{
	this.url = url;
}

ajax_request.prototype.setMethod = function(method)
{
	this.method = method;
}

ajax_request.prototype.setContent = function(content)
{
	this.content = content;
}

ajax_request.prototype.setHeaders = function(headers)
{
	this.headers = headers;
}

ajax_request.prototype.setTrace = function(trace)
{
	this.trace = trace;
}

ajax_request.prototype.setPreloader = function(preloader)
{
	this.preloader = preloader;
}

ajax_request.prototype.send = function(handler)
{
	var xmlhttp = this.xmlhttp;
	var handler = this.handler;
	var self = this;
	var url = this.url;

	if (!xmlhttp)
	{
		return false;
	}
	
	// encode all plus signs
	url = url.replace(/\+/g, '%2B');
	
	this.traceStart();
	this.preloaderDisplay();

	xmlhttp.open(this.method, url);

	xmlhttp.onreadystatechange = function()
	{
		if (xmlhttp.readyState != 4)
		{
			return;
		}

		try
		{
			// invalid requested url
			if (xmlhttp.status != 200)
			{
				throw new ajax_error("Invalid requested url:\n" + self.url);
			}

			// check response XML
			if (self.checkXmlResponse)
			{
				self.getXmlResponse(xmlhttp);
			}

			// hide preloader
			self.preloaderHide();
			
			// finish trace
			self.traceFinish();

			// call cutom mhandler
			handler.name(xmlhttp, handler.parameter);
		}
		catch(e)
		{
			// try log error
			try
			{
				// is instance of Error
				if (!(e instanceof Error))
				{
					throw new Error();
				}
				
				// ignore NS error
				if (e.name == 'NS_ERROR_NOT_AVAILABLE')
				{
					throw new Error();
				}
				
				// ignore FF error caused by cancelling request by leaving current page
				if (xmlhttp.status === 0)
				{
					throw new Error();
				}
				
				// alert error in admin
				if (window.location.pathname.search(/admin\.php$/) != -1)
				{
					alert("ERROR OCCURED:\n" + e);
				}
				
				var logRequest = new ajax_request();

				logRequest.setUrl('admin.php?ajaxlog='+escape(e.message.substring(0, 500))+'&url=' + escape(self.url) + '&location=' + escape(window.location) + '&status=' + escape(xmlhttp.status));
				logRequest.checkXmlResponse = false;
				logRequest.setHandler(function(xml){});
				logRequest.send();
			}
			catch(e)
			{}
			
			// hide preloader
			self.preloaderHide();
		}
	}

	if (this.headers)
	{
		for (var key in this.headers)
		{
			xmlhttp.setRequestHeader(key, this.headers[key]);
		}
	}
	
	if (this.method == 'POST')
	{
		xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		this.content = url;
	}

	xmlhttp.send(this.content);

	return true;
}

ajax_request.prototype.getXmlResponse = function(xmlhttp)
{
	var xmlResponse = xmlhttp.responseXML;
	var exception = new ajax_error("Invalid XML structure:\n" + xmlhttp.responseText.substring(0, 500));

	// IE
	if (!xmlResponse || !xmlResponse.documentElement)
	{
		throw exception;
	}

	// FF
	var rootNode = xmlResponse.documentElement;

	if (rootNode.nodeName == "parsererror")
	{
		throw exception;
	}

	return xmlResponse;
}

ajax_request.prototype.preloaderDisplay = function()
{
	if (this.preloader && this.preloader instanceof ajax_preloader)
	{
		this.preloader.display();
	}
}

ajax_request.prototype.preloaderHide = function()
{
	if (this.preloader && this.preloader instanceof ajax_preloader)
	{
		this.preloader.hide();
	}
}

ajax_request.prototype.traceStart = function()
{
	if (this.trace)
	{
		this.trace.start(this);
	}
}

ajax_request.prototype.traceFinish = function()
{
	if (this.trace)
	{
		this.trace.finish();
	}
}


/************************************************************************************************************/
/* ajax_call																								*/
/************************************************************************************************************/

function ajax_call()
{
	this.handler;
	this.trace = false;
	this.preloader;
}

var call = new ajax_call();

ajax_call.prototype.setTrace = function(bool)
{
	this.trace = bool;
}

ajax_call.prototype.setPreloader = function(preloader)
{
	this.preloader = preloader;
}

ajax_call.prototype.getPreloader = function()
{
	if (!this.preloader)
	{
		this.preloader = new admin_preloader();
	}

	return this.preloader;
}

ajax_call.prototype.execute = function(url, handler, method)
{
	this.handler = handler;
	var request = new ajax_request();

	url += '&ajax=1';

	request.setUrl(url);
	request.setHandler(this.handle, this);
	
	if (method)
	{
		request.setMethod(method);
	}
	
	if (this.trace)
	{
		request.setTrace(new ajax_trace());
	}
	
	request.setPreloader(this.getPreloader());
	
	request.send();
}

ajax_call.prototype.handle = function(xmlhttp, self)
{
	var xml = xmlhttp.responseXML;
	var success = xml.getElementsByTagName("success")[0].firstChild.nodeValue;

	if (success == 1)
	{
		self.handler(xmlhttp);
	}
	else
	{
		var message = 'Error';
		var errors = xml.getElementsByTagName("error");
		
		// add errors
		if (errors.length)
		{
			message = '';
			
			for (var i = 0; i < errors.length; i++)
			{
				var error = errors[i];
				
				// redirect to login page if user is not logged
				if (error.getAttribute('type') == 'notlogged')
				{
					window.location = "admin.php";
					return;
				}
				
				if (error.firstChild)
				{
					message += '\n- '+error.firstChild.nodeValue;
				}
			}
		}
		
		alert(message);
	}
	
	self.getPreloader().setParent(null);
}