/********************************************************
** 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 5:
				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:
				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() {
//alert(typeof(XMLSerializer));//this.theResponse.childNodes[0].innerHTML);//.childNodes[0].tagName);
	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
//
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.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) {
//window.open(sURL);
	this.Cancel();

	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) {
			this.NCSAJAXXMLHttpRequest = xmlDoc;
			
			if(bAsync) {
				xmlDoc.onreadystatechange = function() {
					try {
						if(xmlDoc.readyState==4 && xmlDoc.status==200) {
							if(initFunc != null) {
								//When the response MIME type is "text/xml", "application/xml" or "*/*+xml",
								//it should be parsed into xmlDoc.responseXML.  Otherwise, the response
								//will be in xmlDoc.responseText.
								var sContentType = xmlDoc.getResponseHeader("Content-Type");
								if (sContentType.indexOf("image") >= 0)
									initFunc(null, initData);
								else if (xmlDoc.responseXML && (xmlDoc.responseXML.xml != ""))
									initFunc(new NCSAJAXDOM(xmlDoc.responseXML), initData);
								else
									initFunc(new NCSAJAXDOM(xmlDoc.responseText), initData);
							}
						}
					} catch(ex) {
						// Firefox triggers an exception if NCSAJAX.prototype.Cancel is called while a request is pending.
					}
				};
			}
			//alert(xmlDoc.onreadystatechange);
			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);
			} catch(ex) { };
			xmlDoc.send(sBody);
			if(!bAsync && xmlDoc.readyState==4 && xmlDoc.status==200) {
				
				if(initFunc != null) {
					//When the response MIME type is "text/xml", "application/xml" or "*/*+xml",
					//it should be parsed into xmlDoc.responseXML.  Otherwise, the response
					//will be in xmlDoc.responseText.
					var sContentType = xmlDoc.getResponseHeader("Content-Type");
					if (sContentType.indexOf("image") >= 0)
						initFunc(null, initData);
					else if (xmlDoc.responseXML && (xmlDoc.responseXML.xml != ""))
						initFunc(new NCSAJAXDOM(xmlDoc.responseXML), initData);
					else
						initFunc(new NCSAJAXDOM(xmlDoc.responseText), initData);
				}
			} 
		}
	} catch(ex) {
		// When the resource cannot be located (Error number -2146697211) return that the post failed
		// and leave the alert to be processed higher up.
		if(ex.number != -2146697211)
		{
			alert("Post failed: " + ex.message);
		}
		return(false);
	}
	return(true);
}

NCSAJAX.prototype.Cancel = function() {
	if(this.NCSAJAXXMLHttpRequest != null) {
		switch(this.NCSAJAXXMLHttpRequest.readyState) {
			case 1://Loading
			case 2://Loaded
			case 3://Interactive	
				this.NCSAJAXXMLHttpRequest.abort();
				break;
			default://0 (Uninitialized) or 4 (Complete)
				break;
		}
		this.NCSAJAXXMLHttpRequest = null;
	}
}
