// BEGIN WEBND COPYRIGHT
// (c) 2000-2008 WebND Technologies PTY LTD (http://webnd.com.au/)
// Released under the GNU Affero GPL v3.  Seeing doc/COPYING for details.
// END WEBND COPYRIGHT

requestManager = {
	requests: [],
	pollInterval: 200,
	timeoutId: null,
	registerRequest: function (request) {
		this.requests.push(request);
		this.setupTimeoutIfNecessary();
	},
	setupTimeout: function () {
		this.timeoutId = window.setTimeout("requestManager.timeoutTick()", this.pollInterval);
	},
	setupTimeoutIfNecessary: function () {
		if (this.timeoutId == null) {
			this.setupTimeout();
		}
	},
	timeoutTick: function () {
		var i, len, newreq;
		len = this.requests.length;
		newreq = new Array();
		for (i = 0; i < len; i++) {
			if (this.requests[i].requestsCompleted()) {
				this.requests[i].processResults();
				this.requests[i] = null;
			} else {
				newreq.push(this.requests[i]);
			}
		}
		this.requests = newreq;
		if (this.requests.length > 0) {
			this.setupTimeout();
		} else {
			this.timeoutId = null;
		}
	}
};

SubstitutionRequest.prototype = {
	requestsCompleted: function () {
		if (this.templateRequest.readyState == 4 &&
		    this.subsRequest.readyState == 4) {
			return true;
		}
	},
	processResults: function () {
		var subs = this.subsRequest.responseXML;
		var template = this.templateRequest.responseXML.getElementsByTagName("template")[0];
		var destNode = document.getElementById(this.destination);
		var replacement = document.createDocumentFragment();

		this.applyTemplateNodeToNodeWithSubs(template, replacement, subs);
		destNode.appendChild(replacement);
		try {
		    YAHOO.au.com.webnd.ShowUserDetails.waitForTemplates = false;
		} catch (e) {
		    
		}
	},
	applyTemplateNodeToNodeWithSubs: function (template, replacement, subs) {
		var i, len, newNode;
		len = template.childNodes.length;
		for (i = 0; i < len; i++) {
			var srcNode;
			srcNode = template.childNodes[i];
			switch (srcNode.nodeType) {
			case Node.ELEMENT_NODE:
				newNode = this.newElementFromTemplate(srcNode, subs);
				if (newNode) {
					replacement.appendChild(newNode);
				}
				break;
			case Node.TEXT_NODE:
			case Node.CDATA_SECTION_NODE:
				replacement.appendChild(this.cloneNodeBecauseIEIsASteamingPileOfShit(srcNode));
				break;
			case Node.PROCESSING_INSTRUCTION_NODE:
			case Node.COMMENT_NODE:
			case Node.NOTATION_NODE:
				// do nothing
				break;
			default:
				alert("Unexpected node type " + srcNode.nodeType);
				break;
			};
		}
	},
	newElementFromTemplate: function (srcNode, subs) {
		var newNode;
		if (srcNode.nodeName == 'onlinetag') {
			var subName = srcNode.getAttribute("name");
			newNode = this.applyOnlineTag(subName, subs);
		} else if (srcNode.nodeName == 'onlineif') {
			newNode = this.applyOnlineIf(srcNode, subs)
		} else {
			newNode = document.createElement(srcNode.nodeName);
			this.applyTemplateNodeToNodeWithSubs(srcNode, newNode, subs);
			this.copyAttributesFromTemplateNodeToNodeWithSubs(srcNode, newNode, subs)
		}
		return newNode;
	},
	copyAttributesFromTemplateNodeToNodeWithSubs: function (srcNode, dstNode, subs) {
		var i, len;
		len = srcNode.attributes.length;
		for (i = 0; i < len; i++) {
			var attr = srcNode.attributes[i];
			var value = attr.value;
			var subStart = value.indexOf("#{");
			while (subStart != -1) {
				var subEnd = value.indexOf("}", subStart);
				var subName = value.substring(subStart + 2, subEnd);
				var replacement = this.applyOnlineTag(subName, subs);
				if (replacement) {
					replacement = this.collapseElementToText(replacement);
					value = value.substring(0, subStart) + replacement, value.substring(subEnd + 1);
					subStart = value.indexOf("#{");
				} else {
					subStart = -1;
				}
			}
			dstNode.setAttribute(attr.name, value);
			if (this.isRunningInIE) {
				// IE is a manky pile of shit
				if (attr.name == 'style') {
					dstNode.style.setAttribute('cssText', value, 0);
				}
			}
		}
	},
	applyOnlineTag: function (subName, subs) {
		var sub = this.getElementByAttribute(subs, 'id', subName);
		if (!sub) {
			return null;
		}

		var newFrag = document.createDocumentFragment();
		var i, len;
		len = sub.childNodes.length;
		for (i = 0; i < len; i++) {
			newFrag.appendChild(this.cloneNodeBecauseIEIsASteamingPileOfShit(sub.childNodes[i]));
		}
		return newFrag;
	},
	applyOnlineIf: function (srcNode, subs) {
		var subName = srcNode.getAttribute("name");
		var sub = this.getElementByAttribute(subs, 'id', subName);
		var trueVersion = document.createDocumentFragment();
		var falseVersion = document.createDocumentFragment();
		var currentVersion = trueVersion;
		var i, len, value;
		len = srcNode.childNodes.length;
		for (i = 0; i < len; i++) {
			var childNode = srcNode.childNodes[i];
			if (srcNode.childNodes[i].nodeName == 'onlineelse') {
				currentVersion = falseVersion;
			} else {
				switch (childNode.nodeType) {
				case Node.TEXT_NODE:
				case Node.CDATA_SECTION_NODE:
					currentVersion.appendChild(this.cloneNodeBecauseIEIsASteamingPileOfShit(childNode));
					break;
				case Node.ELEMENT_NODE:
					var newNode = this.newElementFromTemplate(childNode, subs);
					if (newNode) {
						currentVersion.appendChild(newNode);
					}
					break;
				case Node.PROCESSING_INSTRUCTION_NODE:
				case Node.COMMENT_NODE:
				case Node.NOTATION_NODE:
					// Do nothing
					break;
				default:
					alert("Unexpected node type " + srcNode.nodeType);
					break;
				}
			}
		}
		if (sub) {
			value = this.collapseElementToText(sub);
		}
		if (value == '0' ||
		    value == '' ||
		    value == undefined ||
		    value == null) {
			return falseVersion;
		}
		return trueVersion;
	},
	getElementByAttribute: function (node, attrName, attrValue) {
		var i, len;
		len = node.childNodes.length;
		for (i = 0; i < len; i++) {
			var child;
			var attr;
			if (node.childNodes[i].nodeType == Node.ELEMENT_NODE) {
				attr = node.childNodes[i].getAttributeNode(attrName);
			}
			if (attr && attr.value == attrValue) {
				return node.childNodes[i];
			}
			child = this.getElementByAttribute(node.childNodes[i], attrName, attrValue);
			if (child) {
				return child;
			}
		}
		return null;
	},
	collapseElementToText: function (node) {
		if (node.nodeType == Node.TEXT_NODE) {
			return this.unescapeCharacterEntities(node.nodeValue);
		}
		if (node.nodeType == Node.CDATA_SECTION_NODE) {
			return this.unescapeCharacterEntities(node.nodeValue);
		}

		var i, len, text;
		len = node.childNodes.length;
		text = '';
		for (i = 0; i < len; i++) {
			text = text + this.collapseElementToText(node.childNodes[i]);
		}
		return text;
	},
	unescapeCharacterEntities: function (string) {
		var data = new String(string);
		data = data.replace(/\&\#(\d+)\;/g, function(match, cap1) { return String.fromCharCode(cap1); });
		return data;
	},
	cloneNodeBecauseIEIsASteamingPileOfShit: function (node) {
		var newNode;
		switch (node.nodeType) {
		case Node.ATTRIBUTE_NODE:
			newNode = document.createAttribute(node.nodeName);
			newNode.value = node.nodeValue;
			break;
		case Node.TEXT_NODE:
			newNode = document.createTextNode(this.unescapeCharacterEntities(node.nodeValue));
			break;
		case Node.CDATA_SECTION_NODE:
			newNode = document.createTextNode(this.unescapeCharacterEntities(node.nodeValue));
			break;
		case Node.ELEMENT_NODE:
			newNode = document.createElement(node.nodeName);
			this.copyAttributesBecauseIEIsASteamingPileOfShit(node, newNode);
			if (node.hasChildNodes()) {
				var childNode;
				for (childNode = node.firstChild; childNode; childNode = childNode.nextSibling) {
					newNode.appendChild(this.cloneNodeBecauseIEIsASteamingPileOfShit(childNode));
				}
			}
			break;
		default:
			alert("tried to clone a wierd node");
			break;
		}
		return newNode;
	},
	copyAttributesBecauseIEIsASteamingPileOfShit: function (srcNode, dstNode) {
		var i, len;
		len = srcNode.attributes.length;
		for (i = 0; i < len; i++) {
			var attr = srcNode.attributes[i];
			dstNode.setAttribute(attr.name, attr.value);
			if (this.isRunningInIE) {
				// IE is a manky pile of shit
				if (attr.name == 'style') {
					dstNode.style.setAttribute('cssText', attr.value, 0);
				}
			}
		}
	}
};

xmlHttpRequestFactory = {
	isRunningInIE: false,
	isRunningInIE7: false,
	ieControlNames: [ 'MSXML2.XMLHTTP.5.0',
			  'MSXML2.XMLHTTP.4.0',
			  'MSXML2.XMLHTTP.3.0',
			  'MSXML2.XMLHTTP',
			  'Microsoft.XMLHTTP' ],
	getConnection: function () {
		var conn;

                try {
			conn = new XMLHttpRequest();
			if (Node == null) {
				this.fakeShitForIE();
				this.isRunningInIE7 = true;
			}
			return conn;
		} catch(e) {
			var i, len;
			len = this.ieControlNames.length;
                        for (i = 0; i < len; i++) {
                                try {
                                        conn = new ActiveXObject(this.ieControlNames[i]);
                                        if (conn) {
						this.fakeShitForIE();
                                                return conn;
                                        }
                                } catch(e) {
					// Do nothing, we'll try the next one
				}
                        }
                }
		// No XMLHttpRequest and no IE control - bugger
		return null;
	},
	fakeShitForIE: function () {
		// IE doesn't put constants in the Node class. fuckers.
		Node = {
			ELEMENT_NODE                   : 1,
			ATTRIBUTE_NODE                 : 2,
			TEXT_NODE                      : 3,
			CDATA_SECTION_NODE             : 4,
			ENTITY_REFERENCE_NODE          : 5,
			ENTITY_NODE                    : 6,
			PROCESSING_INSTRUCTION_NODE    : 7,
			COMMENT_NODE                   : 8,
			DOCUMENT_NODE                  : 9,
			DOCUMENT_TYPE_NODE             : 10,
			DOCUMENT_FRAGMENT_NODE         : 11,
			NOTATION_NODE                  : 12
		};
		this.isRunningInIE = true;
	}
};

function
SubstitutionRequest(destination, template_url, subs_url) {
	try {
	  YAHOO.au.com.webnd.ShowUserDetails.waitForTemplates = true;
	} catch (e) {
	}
	this.destination = destination;
	this.template_url = template_url;
	this.subs_url = subs_url;
	this.templateReady = 0;
	this.subsReady = 0;
	this.isRunningInIE = false;
	this.isRunningInIE7 = false;

	this.templateRequest = xmlHttpRequestFactory.getConnection();
	this.subsRequest = xmlHttpRequestFactory.getConnection();

	if (! this.templateRequest ||
	    ! this.subsRequest) {
		alert("No AJAX support in this browser, sorry");
		return;
	}

	this.templateRequest.open("GET", template_url, true);
	this.subsRequest.open("GET", subs_url, true);

	this.templateRequest.send(null);
	this.subsRequest.send(null);

	if (xmlHttpRequestFactory.isRunningInIE) {
		this.isRunningInIE = true;
	}
	if (xmlHttpRequestFactory.isRunningInIE7) {
		this.isRunningInIE7 = true;
	}
	requestManager.registerRequest(this);
}


function
populate_template(destination, template_url, subs_url) {
	return new SubstitutionRequest(destination, template_url, subs_url);
}

