/********************************************************
** NCSAJAX.js
**
** Copyright 2005 Earth Resource Mapping Ltd.
** This document contains unpublished source code of
** Earth Resource Mapping Pty Ltd. This notice does
** not indicate any intention to publish the source
** code contained herein.
**
** CREATED:  01 Sep 2005
** AUTHOR:   Simon Cope
** PURPOSE:  AJAX and DOM JS objects.
**
** EDITS:    [xx] ddMmmyy NAME COMMENTS
*******************************************************/

Array.prototype.remove = function(i) {
	var res = null;
	if(typeof(i) == "number") {
		if(i < this.length) {
		    if(typeof(this.splice) == "function") {
		        res = this.splice(i, 1);
		    } else if(i == 0) {
				this.reverse();
				res = this.pop();
				this.reverse();
			} else if(i == this.length - 1) {
				res = this.pop();
			} else {
				var aLeft = (i > 0) ? this.slice(0, i) : new Array();
				var aRight = (i < this.length - 1) ? this.slice(i + 1, this.length) : new Array();
				res = this.slice(i, 1)[0];
				while(this.length) {
					this.pop();
				}
				aLeft = aLeft.concat(aRight);
				aLeft.reverse();
				while(aLeft.length) {
					this.push(aLeft.pop());
				}
			}
		}
	} else {
		var j;
		for(j = this.length-1; j >= 0; j--) {
			if(this[j] == i) {
				res = this.remove(j);
				//break;
			}
		}
	}
	return(res);
}

Array.prototype.endIterate = function() {
	this.bEndIterate = true;
}

Array.prototype.iterate = function() {
	var rVal = true;
	var a = arguments;
	var func = a[0];
	this.bEndIterate = false;
	var i;
	var len = this.length;
	switch(a.length) {
		case 0:
				for(i = 0; i < len && !this.bEndIterate; i++) {
					rVal |= func(this, this[i]);
				}
			break;
		case 1:
				for(i = 0; i < len && !this.bEndIterate; i++) {
					rVal |= func(this, this[i], a[1]);
				}
			break;
		case 2:
				for(i = 0; i < len && !this.bEndIterate; i++) {
					rVal |= func(this, this[i], a[1], a[2]);
				}
			break;
		case 3:
				for(i = 0; i < len && !this.bEndIterate; i++) {
					rVal |= func(this, this[i], a[1], a[2], a[3]);
				}
			break;
		case 4:
				for(i = 0; i < len && !this.bEndIterate; i++) {
					rVal |= func(this, this[i], a[1], a[2], a[3], a[4]);
				}
			break;
		case 4:
				for(i = 0; i < len && !this.bEndIterate; i++) {
					rVal |= func(this, this[i], a[1], a[2], a[3], a[4], a[5]);
				}
			break;
		default:
				debugger; //alert("ERROR: can't iterate with " + a.length + " arguments");
				rVal = false;
			break;
	}
	return(rVal);
}

//
// Static method to build a string - faster than s=s1+s2+s3...
//
String.build = function() {
	var len = arguments.length;
	var s = new Array(len);
	for(i = 0; i < len; i++) {
		s[i] = arguments[i];
	}
	return(s.join(""));
}
//
// CLASS NCSAJAXDOMElement
//
// NCSAJAXDOMElement class used by NCSAJAXDOM class to assist parsing XML server responses.
//
// These classes use the DOM XML parser if available, else cheap and dirty string manipulation
//
function NCSAJAXDOMElement(sElement, theElement) {
	this.theElement = theElement;
	this.tagName = sElement;
	this.nodeType = theElement.nodeType;
	this.ownerDocument = theElement.ownerDocument;
	this.bDOM = (typeof(this.theElement) != "string");
	if(this.bDOM) {
		NCSAJAXDOMElement.prototype.getElement = function(sElement) {
				var aEls = this.theElement.getElementsByTagName(sElement);
				if(aEls != null && aEls.length > 0)	{
					return(new NCSAJAXDOMElement(sElement, aEls[0]));
				}
				return(null);
			};
		NCSAJAXDOMElement.prototype.getElements = function() {
				var aEls = new Array();
				var i;
				var node = this.theElement.firstChild;
				while(node) {
					if(node.nodeType == 1) {
						aEls.push(new NCSAJAXDOMElement(node.tagName, node));
					}
					node = node.nextSibling;
				}
				if(aEls.length > 0) {
					return(aEls);
				}
				return(null);
			};
		NCSAJAXDOMElement.prototype.getText = function() {
				if(typeof(this.innerHTML) != "undefined") {
					return(this.innerHTML);
				} else {
   					var nodes = this.theElement.childNodes;
   					var len = nodes.length;
   					if(len == 1 && nodes[0].nodeType == 3) {
						return(nodes[0].data);
					} else {
						var s = "";
						for(var i=0; i < len; i++){
							var node = nodes[i];
							if(node.nodeType == 3){
								s += node.data;
							}
						}
						return(s);
					}
				}
				return(null);
			};
		NCSAJAXDOMElement.prototype.getElementText = function(sElement) {
				var el = this.getElement(sElement);
				if(el != null) {
					return(el.getText());
				}
				return(null);
			};
		NCSAJAXDOMElement.prototype.getAttribute = function(sAttribute) {
			return(this.theElement.getAttribute(sAttribute));
		}
	} else {
		NCSAJAXDOMElement.prototype.getElement = function(sElement) {
			var aEls = this.theElement.split(sElement + ">");
			if(aEls != null && aEls.length > 0)	{
				return(new NCSAJAXDOMElement(sElement, aEls[0]));
			}
			return(null);
		}

		NCSAJAXDOMElement.prototype.getElementText = function(sElement) {
			var el = this.getElement(sElement);
			if(el != null) {
				return(el.getText());
			}
			return(null);
		}

		NCSAJAXDOMElement.prototype.getText = function() {
			return(this.theElement.split("</")[0]);
		}

		NCSAJAXDOMElement.prototype.getAttribute = function(sAttribute) {
			if(this.theElement.split(sAttribute + "=\"").length > 1) {
				return(this.theElement.split(sAttribute + "=\"")[1].split("\"")[0]);
			} else if(this.theElement.split(sAttribute + "=").length > 1) {
				if(this.theElement.split(sAttribute + "=")[1].split(" ").length > 1) {
					return(this.theElement.split(sAttribute + "=")[1].split(" ")[0]);
				} else {
					return(this.theElement.split(sAttribute + "=")[1].split(">")[0]);
				}
			} else {
				return(null);
			}
		}

	}
}


//
// CLASS NCSAJAXDOM
//
// NCSAJAXDOM class to assist parsing XML server responses.
//
function NCSAJAXDOM(theResponse) {
	var res = theResponse;
	this.theResponse = res;
	this.bDOM = (typeof(this.theResponse) != "string");

	if(this.bDOM) {
		var dom = this;
		this.getElementsByTagName = function(sElement) {
				var aEls = null;
				aEls = this.theResponse.getElementsByTagName(sElement);
				if(aEls != null && aEls.length > 0) {
					var aVEls = new Array();
					var i;
					var len = aEls.length;
					for(i = 0; i < len; i++) {
						aVEls.push(new NCSAJAXDOMElement(sElement, aEls[i]));
					}
					return(aVEls);
				}
				return(null);
			}
	} else {
		this.getElementsByTagName = function(sElement) {
				var aEls = aEls = this.theResponse.split("<" + sElement);
				if(aEls != null && aEls.length) {
					var aVEls = new Array();
					aEls.remove(0);
					aEls.iterate(function(a, r) {
								var l = r.indexOf("/>");
								//if(l >= 0) l += ("/>").length;
								var l2 = r.indexOf("</" + sElement + ">");
								//if(l2 >= 0) l2 += ("</" + sElement + ">").length;
								if(l == -1) {
									l = l2;
								} else if(l2 >= 0) {
									l = Math.min(l, l2);
								}
								if(l == -1) {
									l = r.length;
								}
								//alert(r.substring(0, l));
								aVEls.push(new NCSAJAXDOMElement(sElement, r.substring(0, l)));
							});
					return(aVEls);
				}
				return(null);
			};
	}
}
/*
NCSAJAXDOM.prototype.getElementsByTagName = function(sElement) {
	var aEls = null;
	if(!this.bDOM) {
		aEls = this.theResponse.split("<" + sElement);
	} else {
		aEls = this.theResponse.getElementsByTagName(sElement);
	}
	if(aEls != null) {
		var aVEls = new Array();
		var i;
		for(i = 0; i < aEls.length; i++) {
			aVEls[aVEls.length] = new NCSAJAXDOMElement(sElement, aEls[i]);
		}
		return(aVEls);
	}
	return(null);
}*/

NCSAJAXDOM.prototype.getElementFromTagName = function(sElement) {
	var aEls = this.getElementsByTagName(sElement);
	if(aEls != null && aEls.length) {
		return(aEls[0]);
	}
	return(null);
}

NCSAJAXDOM.prototype.getElementText = function(sElement) {
	var el = this.getElementFromTagName(sElement);
	if(el != null) {
		return(el.getText());
	}
	return(null);
}

NCSAJAXDOM.prototype.serialize = function() {
	if(!this.bDOM) {
		return(this.theResponse);
	} else if(this.theResponse.xml) {
		return(this.theResponse.xml);
	} else if(this.getElementFromTagName("BODY")) {
		return(this.getElementFromTagName("BODY").getText());
	} else if(this.theResponse.childNodes && this.theResponse.childNodes.length > 0 && this.theResponse.childNodes[0].innerHTML) {
		return(this.theResponse.childNodes[0].innerHTML);
	} else {
		try {
			// create serializer object
			var xmlSerializer = new XMLSerializer();
			// serialize
			var markup = xmlSerializer.serializeToString(this.theResponse);
			return(markup);
		} catch(e) {
			//debugger; //alert("Unknown response from server, type \"" + typeof(this.theResponse) + "\"");
		}
	}
}

//
// NCSAJAX_Timer class
//
var _NCSAJAX_Timers = new Array();
var _NCSAJAX_Timers_NextID = 0;

function NCSGetTimeStampMs() {
    var d = new Date();
    return(d.getTime());
}

function _NCSAJAX_TimerCB(nID) {
	var i;
	var len = _NCSAJAX_Timers.length;
	for(i = 0; i < len; i++) {
		var t = _NCSAJAX_Timers[i];

		if(t.nID == nID) {
			if(t.bOneShot) {
		        t.timerID = -1;
		    }
		    t.nLastTimeout = NCSGetTimeStampMs();
			t.func(t.data);
			break;
		}
	}
}

NCSAJAX_Timer = function(nTimeout, func, data, bOneShot) {
	this.nID = _NCSAJAX_Timers_NextID++;
	this.func = func;
	this.data = data;
	this.bOneShot = bOneShot;
	this.nTimeout = nTimeout;
	this.nLastTimeout = NCSGetTimeStampMs();
	this.timerID = -1;
	_NCSAJAX_Timers.push(this);
/*
	if(bOneShot) {
		this.timerID = window.setTimeout("_NCSAJAX_TimerCB(" + this.nID + ");", nTimeout);
	} else {
		this.timerID = window.setInterval("_NCSAJAX_TimerCB(" + this.nID + ");", nTimeout);
	}*/
}

NCSAJAX_Timer.prototype.setFunc = function(func) {
    this.func = func;
}

NCSAJAX_Timer.prototype.setData = function(data) {
    this.data = data;
}

// Cancel current timeout
NCSAJAX_Timer.prototype.cancel = function() {
    if(this.timerID != -1) {
	    window.clearTimeout(this.timerID);
	    this.timerID = -1;
	}
}

// Cancel current timeout and delete timer
NCSAJAX_Timer.prototype.stop = function() {
    this.cancel();
	_NCSAJAX_Timers.remove(this);
}

// Start timer if not currently started.
NCSAJAX_Timer.prototype.start = function() {
    if(this.timerID == -1) {
        if(this.bOneShot) {
	        this.timerID = window.setTimeout("_NCSAJAX_TimerCB(" + this.nID + ");", this.nTimeout);
        } else {
            this.timerID = window.setInterval("_NCSAJAX_TimerCB(" + this.nID + ");", this.nTimeout);
        }
    } else {
        var tsNow = NCSGetTimeStampMs();
        if(tsNow - this.nLastTimeout > this.nTimeout) {
            if(this.bOneShot) {
                window.clearTimeout(this.timerID);
		        this.timerID = -1;
		    }
		    this.nLastTimeout = tsNow;
			this.func(this.data);
        }
    }
}

// Restart (cancel/start) timer
NCSAJAX_Timer.prototype.restart = function() {
    this.cancel();
    this.start();
}

//
// NCSAJAX - Asynchronous Javascript and XML object
//
// Uses HTTPRequest if available, otherwise a hidden IFRAME
//
var _NCSAJAXs = new Array();

function _NCSAJAX_Find(nID) {
	var i;
	for(i = 0; i < _NCSAJAXs.length; i++) {
		if(_NCSAJAXs[i].nID == nID) {
			return(_NCSAJAXs[i]);
			break;
		}
	}
	return(null);
}

function NCSAJAX() {
	_NCSAJAXs[_NCSAJAXs.length] = this;
	this.nID = _NCSAJAXs.length;

	this.NCSAJAXXMLHttpRequest = null;
	this.NCSAJAXXMLIFrame = null;
	this.initFunc = null;
	this.initData = null;
	this.bAsync = true;
}

// Post something to sURL
NCSAJAX.prototype.Post = function(sURL, sBody, sAction) {
	return(this.PostEx(sURL, sBody, sAction, null, null, true));
}

NCSAJAX.prototype.GetXML = function(sURL, sBody, sAction) {
	if(this.PostEx(sURL, sBody, sAction, function(dom, theAJAX) { theAJAX.m_GetXMLHookDOM = dom; return(1);	}, this, false)) {
		return(this.m_GetXMLHookDOM);
	}
	return(null);
}

NCSAJAX.prototype.Get = function(sURL, sBody, sAction) {
	var dom = this.GetXML(sURL, sBody, sAction);
	if(dom) {
		return(dom.serialize());
	}
	return(null);
}

NCSAJAX.prototype.PostEx = function(sURL, sBody, sAction, initFunc, initData, bAsync) {
	this.Cancel();
	var theLayer = this;
	try {
		var xmlDoc = null;
		if(typeof window.ActiveXObject != 'undefined' ) {
			xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
		} else if(typeof(XMLHttpRequest) != "undefined") {
			xmlDoc = new XMLHttpRequest();
		}
		if(xmlDoc != null) {
			if(bAsync) {
				xmlDoc.onreadystatechange = function() {
					if(xmlDoc.readyState == 4) {
						if(initFunc != null) {
							initFunc((xmlDoc.status == 200) ? new NCSAJAXDOM(xmlDoc.responseXML) : null, initData);
						}
					}
				};
			}
			xmlDoc.open(sAction, sURL, bAsync);
			try {
				// Firefox does not correctly set the referer HTTP header, so we must do it manually
				xmlDoc.setRequestHeader('Referer', document.location.href);
			} catch(ex) { };
			xmlDoc.send(sBody);
			if(!bAsync && xmlDoc.readyState == 4) {
				if(initFunc != null) {
					initFunc((xmlDoc.status == 200) ? new NCSAJAXDOM(xmlDoc.responseXML) : null, initData);
				}
			} else if(bAsync) {
				this.NCSAJAXXMLHttpRequest = xmlDoc;
			}
		}
	} catch(ex) {
		return(false);
	}
	return(true);
}

NCSAJAX.prototype.Cancel = function() {
	if(this.NCSAJAXXMLHttpRequest != null) {
		this.NCSAJAXXMLHttpRequest.abort();
		this.NCSAJAXXMLHttpRequest = null;
	}
}

function _NCSAJAX_AsyncLoad(theAJAX) {
		// Pass both the ID and NAME of the iframe which you want the innerHTML of.
	function getIFrameDoc(iFrame) {
		var saf = navigator.userAgent.match(/Safari/i);
		var opr = navigator.userAgent.match(/Opera/i);
		var obj=null;

		if(iFrame) {
			if(iFrame.contentDocument && !saf) {
				// NS6 &amp; Gecko
				if(typeof(iFrame.contentDocument.defaultView) != "undefined" && iFrame.contentDocument.defaultView != null) {
					obj=iFrame.contentDocument.defaultView.document;
				}
			} else if(iFrame.contentWindow) {
				// IE 5.5 &amp; 6.x
				obj=iFrame.contentWindow.document;
			} else if(saf) {
				// This may also support Konqueror, I haven't tested it yet.
				// Safari
				obj=iFrame.document;
			} else if(document.all && !opr) {
				// IE 5.5 on the MAC
				obj=document.frames[iFrame.name].document;
			} else if(opr) {
				// Opera
				obj=iFrame.contentDocument;
			}
		}
		return(obj);
	}
	if(theAJAX != null) {
		var tsBegin = NCSGetTimeStampMs();

		while(true) {
			var IFrameDoc = getIFrameDoc(theAJAX.NCSAJAXXMLIFrame);
			if(!IFrameDoc) {
				//NOP
			} else if(typeof(IFrameDoc.readyState) != "undefined" && IFrameDoc.readyState != "complete") {
				//NOP
			} else {
				var xmlDoc = null;
				if(typeof(IFrameDoc.XMLDocument) != "undefined") {
					xmlDoc = new NCSAJAXDOM(IFrameDoc.XMLDocument);
				} else {
					xmlDoc = new NCSAJAXDOM(IFrameDoc);
				}
				var nRet = true;
				if(theAJAX.initFunc != null) {
					nRet = theAJAX.initFunc(xmlDoc, theAJAX.initData);
				}
				if(nRet > 0) {
					// Done, all OK
					break;
				}
			}
			var tsNow = NCSGetTimeStampMs();
			if(this.bAsync || (tsNow - tsBegin > 5000)) {
				this.timer = new NCSAJAX_Timer(250, _NCSAJAX_AsyncLoad, theAJAX, true);
				this.timer.start();
				return;
			}
		}
	}
}
