/**
 * Site Init
 */

		var browser;
		var http;
		var requestProcess;
		var notifier;

var init = function()
{
	browser = new Browser();
	http = new RequestObject();
	requestProcess = new RequestProcessor();
	notifier = new Notifier();
	//initialise the map manager if its defined
	if(window.MapManager)	MapManager.initMaps();
}

/**
 * DOM functions
 */
var createElement = function(type, classname)
{
	var tmp = document.createElement(type);
	tmp.className = classname;
	return tmp;
}
var createTextElement = function(type, classname, text)
{
	var tmp = createElement(type, classname);
	tmp.innerHTML = text;
	return tmp;
}
var getElement = function(id)
{
	return document.getElementById(id);
}
var removeAllChildren = function(dom)
{
	if(dom)
	{
	  while(dom.hasChildNodes())
	  {
	    dom.removeChild(dom.firstChild);
	  }
	}
}

/**
 * XMLHTTP Request object
 *  - returns a XMLHTTP request object
 * @component AJAX
 */
function RequestObject()
{
	if(browser.isIE)
		return new ActiveXObject("Microsoft.XMLHTTP");
	else
		return new XMLHttpRequest();
}
/**
 * HTTP Request processor
 * - processes requests
 * @component AJAX
 */
function RequestProcessor()
{
	this.queue = new Array();
	this.position = 0;
	this.busy = false;
	this.async = true;
	// the async parameter is depreciated, please specify the parameter in the request object
	this.add = function(request,async)
	{
		this.queue[this.queue.length] = request;
		this.process();
		return this.queue.length-1;
	}
	this.abort = function(ticket)
	{
		if(this.position == ticket)
		{
			http.abort();
		}
		this.queue[ticket].abort = true;
	}
	this.process = function()
	{
		if(this.busy||http.readyState!=0&&http.readyState!=4)
		{
			if(this.queue[this.position+1])
			{
				setTimeout(function(){requestProcess.process();},50);
			}
			return;
		}
		this.busy = true;
		if(!this.queue[this.position])
		{
			this.position--;
		}
		var current = this.queue[this.position];
		this.position++;
		if(current.abort)
		{
			this.done();
			return;
		}
		
		http.open(current.method, current.address, current.async);
		if(current.method == 'POST')
		{
			http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded; charset=utf-8');
			http.setRequestHeader('Content-length', current.data.length);
		}
		
		//NOTE: for an SYNCHRONOUS request, this shouldnt really be called, though IE and Firebug makes Firefox call it.
		http.onreadystatechange = current.onStateChange;

		http.send(current.data);
		
		//if a SYNCHRONOUS request, then we dont need to use busy, as execution will be halted on http.send() until a response is received.
		if(this.async == false)
		{
			//enable this line if you want to use callbacks with SYNCHRONOUS requests..
			//current.onStateChange();
			//this.busy = false;
		}
		
	}
	this.done = function()
	{
		this.busy = false;
		if(this.position < this.queue.length)
		{
			setTimeout(function(){requestProcess.process();},50);
		}
	}
}
/**
 * Request object
 * - holds all information for a request
 * @component AJAX
 */

function Request(method, address, data, onStateChange, onFail)
{
	this.async = true;
	this.method = method;
	this.address = address;
	this.data = data;
	
	//this may not be called in synchronous requests...
	this.onStateChange = function()
	{
		if(http.readyState == 4)
		{
			try
			{
				if(http.status != 200)
				{
					throw http.status;
				}
			}
			catch(e)
			{
				switch(e)
				{
					case 404:
					{
						notifier.notify('error','404 Not found, please try again');
						break;
					}
					case 500:
					{
						notifier.notify('error','500 Internal error, please try again');
					}
					default:
					{
						notifier.notify('error','Communication error, please try again');
					}
				}
				onFail();
				requestProcess.done();
				return;
			}
			try
			{
				var response = eval('('+http.responseText+')');
			}
			catch(e)
			{
				notifier.notify('error','Unable to interpret server response');
				onFail();
				requestProcess.done();
				return;
			}
			//try
			//{
				switch(response['status'])
				{
					case 'ok':
					{
						onStateChange(response['data']);
						break;
					}
					case 'info':
					{
						notifier.notify('info', response['info']);
						onStateChange(response['data']);
						break;
					}
					case 'warning':
					{
						notifier.notify('warning', response['warning']);
						onStateChange(response['data']);
						break;
					}
					case 'error':
					{
						notifier.notify('error', response['error']);
						onFail(response['error']);
						break;
					}
					case 'kick':
					{
						createCookie('error', response['error'], 0);
						//registerClick('/login');
						window.location = 'index.php?logout=1';
						break;
					}
					default:
					{
						notifier.notify('error', 'Garbage? '+http.responseText);
						break;
					}
				}
			//}
			//catch(e)
			//{
				//notifier.notify('error','Request.onStateChange():: '+toJSONString(e));
			//}
			requestProcess.done();
		}
	}
	this.abort = false;
}

var Notifier = function()
{
	// dom element
	this.dom_root = createElement('div', 'notifier');
	// array
	this.messages = new Array()
	// array
	this.height = new Array();
	// array
	this.increment = new Array();
	
	this.draw = function()
	{
		return this.dom_root;
	}
	
	this.notify = function(type, msg)
	{
    for(i in this.messages)
    {
      this.acknowledge(i);
    }
		var i = this.messages.length;
		this.messages[i] = createElement('div', type);
		this.messages[i].innerHTML = msg;
		var tmp = this;
		this.messages[i].onclick = function()
		{
			tmp.acknowledge(i);
		}
		//var close = createElement('div','close');
		//close.innerHTML = 'Click to hide';
		//this.messages[i].appendChild(close);
		this.dom_root.appendChild(this.messages[i]);
		setTimeout('notifier.acknowledge('+i+')', 5000);

		//window.location = '#'; // disbakled because otherwise it redirects!
	}
	
	this.acknowledge = function(i)
	{
		this.height[i] = this.messages[i].clientHeight-10;
		this.increment[i] = 1;
		this.hide(i);
	}
	
	this.hide = function(i)
	{
		if(false && this.height[i]>0)
		{
			this.height[i]-=this.increment[i];
			if(this.increment[i]<5)
			{
				if(this.height[i]<6)
				{
					this.increment[i]--;
				}
				else
				{
					this.increment[i]++;
				}
			}
			this.messages[i].style.height = this.height[i] + 'px';
		}
		else
		{
			if(this.messages[i].parentNode == this.dom_root)
			{
				this.dom_root.removeChild(this.messages[i]);
				
			}
		}
	}
}
/**
 * Order summary widget
 */
var showOrderSummaryRollover = function(dom_element)
{
	//console.log('SHOW');
	for(var nodeKey in dom_element.childNodes)
	{
		if(dom_element.childNodes[nodeKey].className == 'summary')
		{
			var cn = dom_element.className; //remove 'expanded' from classname
			dom_element.className = cn.replace(" notexpanded", " expanded"); //remove 'expanded' from classname
			var dimensions = getDimensions(dom_element);
			
			//Determine the current rendered width of the enclosing element, and explicitly set it's width to that size.
			//This prevents the element changing size when the summary is displayed.
			//Different browsers determine size of elements with borders differently. 
			//Some include it in the rendered size, some dont. The same goes for CSS width.
			var browser = new Browser();
			if(browser.isIE)
			{
				//dom_element.style.width = (dimensions['width'])+'px';
			}
			else
			{
				//dom_element.style.width = (dimensions['width']-5)+'px';
			}
			dom_element.childNodes[nodeKey].style.display='block';
		}
	}
}
var hideOrderSummaryRollover = function(dom_element)
{
	//console.log('HIDE');
	for(var nodeKey in dom_element.childNodes)
	{
		if(dom_element.childNodes[nodeKey].className == 'summary')
		{
			var cn = dom_element.className; //remove 'expanded' from classname
			dom_element.className = cn.replace(" expanded", " notexpanded"); //remove 'expanded' from classname
			//reset height back to auto, so can still be resized by browser..
			//dom_element.style.width = 'auto';
			dom_element.childNodes[nodeKey].style.display='none';
		}
	}
}

/**
 * Get the rendered height and width dimensions of any element.
 * param Dom Element
 */
var getDimensions = function(el)
{
	var dimensions = new Object();
	dimensions['height'] = el.offsetHeight;
	dimensions['width'] = el.offsetWidth;
	return dimensions;
}

function Browser()
{
	var ua, s, i;
	this.isIE    = false;
	this.isNS    = false;
	this.isSafari = false;
	this.version = null;
	ua = navigator.userAgent;
	
	// Need to do this before the other browsers, because Safari's navigator.userAgent contains MSIE and Gecko. Also note that the version number for
	// Safari will be an Apple internal version number, and not the version number the user sees.
	// Warning! This has not yet been tested in Safari! (The information above is taken from http://www.quirksmode.org/js/detect.html)
	s = 'Safari';
	if((i = ua.indexOf(s)) >= 0)
	{
		this.isSafari = true;
		this.version = parseFloat(ua.substr(i + s.length));
		return;
	}
	
	s = "MSIE";
	if ((i = ua.indexOf(s)) >= 0) {
		this.isIE = true;
		this.version = parseFloat(ua.substr(i + s.length));
		return;
	}
	s = "Netscape6/";
	if ((i = ua.indexOf(s)) >= 0) {
		this.isNS = true;
		this.version = parseFloat(ua.substr(i + s.length));
		return;
	}
	s = "Gecko"; // Treat any other "Gecko" browser as NS 6.1.
	if ((i = ua.indexOf(s)) >= 0) {
		this.isNS = true;
		this.version = 6.1;
		return;
	}
}
