/*	.IR (Image Replacement for .NET) is based on

    sIFR (Scalable Inman Flash Replacement) Version 2.0b2
	Copyright 2004 Mike Davidson, Shaun Inman, Tomas Jogin and Mark Wubben

	This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
	
	The code has been modified by Milan Negovan (http://www.aspnetresources.com) to 
	facilitate image replacement in .NET.
*/

/*	Konqueror does not treat empty classNames as strings, so we need a workaround */
function appendToClassName(node, sAppend){
	var sClassName = node.className;
	if(sClassName == null){
		sClassName = sAppend;
	} else {
		sClassName = sClassName.normalize() + (sClassName == "" ? "" : " ") + sAppend;
	};
	node.className = sClassName;
};

function prepareDotIR(){
	var node = document.documentElement;
	if(node){
		if(node.className == null || node.className.match(/\bdotIR\-decoy\b/) == null){
			appendToClassName(node, "dotIR-decoy");
		};
	};
};

String.prototype.normalize = function(){
	return this.replace(/\s+/gi, " ");
};

/* IE 5.0 does not support the push method, so here goes */
if(Array.prototype.push == null){
	Array.prototype.push = function(item){
		this[this.length] = item;
		return this.length;
	};
};

/*	Implement function.apply for browsers which don't support it natively
	Courtesy of Aaron Boodman - http://youngpup.net */
if (!Function.prototype.apply){
	Function.prototype.apply = function(oScope, args) {
		var sarg = [];
		var rtrn, call;

		if (!oScope) oScope = window;
		if (!args) args = [];

		for (var i = 0; i < args.length; i++) {
			sarg[i] = "args["+i+"]";
		};

		call = "oScope.__applyTemp__(" + sarg.join(",") + ");";

		oScope.__applyTemp__ = this;
		rtrn = eval(call);
		oScope.__applyTemp__ = null;
		return rtrn;
	};
};

/*	The following code parses CSS selectors.
	This script however is not the right place to explain it,
	please visit the documentation for more information. */
var parseSelector = function(){
	var reParseSelector = /^([^#.>`]*)(#|\.|\>|\`)(.+)$/;
	function parseSelector(sSelector, oParentNode){
		var listSelectors = sSelector.split(/\s*\,\s*/);
		var listReturn = [];
		for(var i = 0; i < listSelectors.length; i++){
			listReturn = listReturn.concat(doParse(listSelectors[i], oParentNode));
		};
		
		return listReturn;
	};
	
	function doParse(sSelector, oParentNode, sMode){
		sSelector = sSelector.replace(" ", "`");
		var selector = sSelector.match(reParseSelector);
		var node, listNodes, listSubNodes, subselector, i, limit;
		var listReturn = [];
		
		if(selector == null){ selector = [sSelector, sSelector] };
		if(selector[1] == ""){ selector[1] = "*" };
		if(sMode == null){ sMode = "`" };
		if(oParentNode == null){
			oParentNode = document;
		};

		switch(selector[2]){
			case "#":
				subselector = selector[3].match(reParseSelector);
				if(subselector == null){ subselector = [null, selector[3]] };
				node = 	document.getElementById(subselector[1]);
				if(node == null || (selector[1] != "*" && !matchNodeNames(node, selector[1]))){
					return listReturn;
				};
				if(subselector.length == 2){
					listReturn.push(node);
					return listReturn;	
				};
				return doParse(subselector[3], node, subselector[2]);
			case ".":
				if(sMode != ">"){
					listNodes = getElementsByTagName(oParentNode, selector[1]);
				} else {
					listNodes = oParentNode.childNodes;
				};
				
				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];
					if(node.nodeType != 1){
						continue;	
					};
					subselector = selector[3].match(reParseSelector);
					if(subselector != null){
						if(node.className == null || node.className.match("(\\s|^)" + subselector[1] + "(\\s|$)") == null){
							continue;
						};
						listSubNodes = doParse(subselector[3], node, subselector[2]);
						listReturn = listReturn.concat(listSubNodes);	
					} else if(node.className != null && node.className.match("(\\s|^)" + selector[3] + "(\\s|$)") != null){
						listReturn.push(node);
					};
				};
				return listReturn;
			case ">":
				if(sMode != ">"){
					listNodes = getElementsByTagName(oParentNode, selector[1]);
				} else {
					listNodes = oParentNode.childNodes;
				};
								
				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];
					
					if(node.nodeType != 1){
						continue;	
					};
					
					if(!matchNodeNames(node, selector[1])){
						continue;
					};
					listSubNodes = doParse(selector[3], node, ">");
					listReturn = listReturn.concat(listSubNodes);	
				};
				return listReturn;
			case "`":
				listNodes = getElementsByTagName(oParentNode, selector[1]);
				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];
					listSubNodes = doParse(selector[3], node, "`");
					listReturn = listReturn.concat(listSubNodes);	
				};
				return listReturn;
			default:
				if(sMode != ">"){
					listNodes = getElementsByTagName(oParentNode, selector[1]);
				} else {
					listNodes = oParentNode.childNodes;
				};

				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];
					if(node.nodeType != 1){
						continue;	
					};
					if(!matchNodeNames(node, selector[1])){
						continue;
					};
					listReturn.push(node);
				};
				return listReturn;
		};
	};
	
	function getElementsByTagName(oParentNode, sTagName){
		/*	IE5.x does not support document.getElementsByTagName("*")
			therefore we're falling back to element.all */
		if(sTagName == "*" && oParentNode.all != null){
			return oParentNode.all;
		};
		return oParentNode.getElementsByTagName(sTagName);
	};
	
	function matchNodeNames(node, sMatch){
		if(sMatch == "*"){
			return true;
		};
		return node.nodeName.toLowerCase().replace("html:", "") == sMatch.toLowerCase();
	};
	
	return parseSelector;
}();

/*	Executes an anonymous function which returns the function dotIR (defined inside the function).
	You can replace elements using dotIR.replaceElement()
	All other variables and methods you see are private. If you want to understand how this works you should
	learn more about the variable-scope in JavaScript. */
var dotIR = function(){

	if(!document.createElement || !document.getElementById){ return function(){return false} };

	/* Opera and Mozilla require a namespace when creating elements in an XML page */
	var sNameSpaceURI = "http://www.w3.org/1999/xhtml";
	var UA = function(){ 
		var sUA = navigator.userAgent.toLowerCase();
		var oReturn =  {
			bIsKHTML: sUA.indexOf('safari') > -1 || sUA.indexOf('konqueror') > -1 || sUA.indexOf('omniweb') > -1,
			bIsOpera : sUA.indexOf('opera') > -1,
			bIsGecko : navigator.product != null && navigator.product.toLowerCase() == 'gecko',
			bIsXML : document.contentType != null && document.contentType.indexOf('xml') > -1
		};
		oReturn.bIsIE = sUA.indexOf('msie') > -1 && ! oReturn.bIsOpera && !oReturn.bIsKHTML && !oReturn.bIsGecko;
		return oReturn;
	}();

	var bIsInitialized = false;
	var stackReplaceElementArguments = [];
	
	function fetchContent(oNode, oNewNode){
		var sContent = "";
		var oSearch = oNode.firstChild;
		var oRemove, oRemovedNode, oTarget;

		while(oSearch){
			if(oSearch.nodeType == 3){
				sContent += oSearch.nodeValue;
			} else if(oSearch.nodeType == 1){
				if(oSearch.nodeName.toLowerCase() == "a"){
					if(oSearch.getAttribute("target")){
						oTarget = oSearch.getAttribute("target");
					} else {
						oTarget = "";
					};
					sContent += '<a href="' + oSearch.getAttribute("href") + '" target="' + oTarget + '">';
				};				
				if(oSearch.hasChildNodes){
					sContent += fetchContent(oSearch);
				};
				if(oSearch.nodeName.toLowerCase() == "a"){
					sContent += "</a>";
				};
			};
			oRemove = oSearch;
			oSearch = oSearch.nextSibling;
			if(oNewNode != null){
				oRemovedNode = oRemove.parentNode.removeChild(oRemove);
				oNewNode.appendChild(oRemovedNode);	
			};
		};
		return sContent;
	};
	
	function createElement(sTagName){
		if(document.createElementNS){
			return document.createElementNS(sNameSpaceURI, sTagName);	
		} else {
			return document.createElement(sTagName);
		};
	};

	function forceRedraw() {
		/*	Corrects a margin-bottom sum bug in Mozilla
			In case you're wondering why I didn't use document.body,
			it's because that throws an error if used in an XML page. */
		var nodeBody = document.getElementsByTagName("body")[0];
		nodeBody.style.height = "1px";
		nodeBody.style.height = "auto";
	};
	
	function urlEncode (sText)
	{
		sText = sText.replace(/%\d{0}/g, '%25');	
		sText = sText.replace(/\+/g, '%2B');		
		sText = sText.replace(/&amp;/g, '%26');
		sText = sText.replace(/&\w{0}#{0}/g, '%26');
		sText = sText.replace(/\"/g, '%22');
		sText = sText.replace(/\#/g, '%23');

        return sText;
	}
	
	function replaceElement(dotIRHandlerPath, sSelector, sForeColor, sBackgroundColor, sWidth, 
	    sAlign, sFontSize, sFont, bDisableCache, bTransparent, bToUpper, sRenderingHint,
	    bBold, bItalic, bUnderline, iLetterSpacing){
		if(!mayReplace()){
			return stackReplaceElementArguments.push(arguments);	
		};
		
		var node, nodeAlternate, sText, sVars;
		var listNodes = parseSelector (sSelector, document);
				
		if(listNodes.length == 0){ return false };
	
		for(var i = 0; i < listNodes.length; i++){
			node = listNodes[i];
			
			/* Prevents elements from being replaced multiple times. */
			if(node.className.match(/\bdotIR\-replaced\b/) != null){ continue; };

			nodeAlternate = createElement("span");
			nodeAlternate.className = "dotIR-alternate";

			sText = urlEncode (fetchContent(node, nodeAlternate));

			node.className += " dotIR-replaced";
			sVars = "t=" + sText;
		    sVars += "&w=" + sWidth;
		    sVars += "&fc=" + urlEncode (sForeColor);
		    sVars += "&bc=" + urlEncode (sBackgroundColor);
		    sVars += "&fs=" + sFontSize;
		    sVars += "&fn=" + urlEncode (sFont);
            sVars += "&rh=" + urlEncode (sRenderingHint);
            sVars += "&ls=" + iLetterSpacing;
            
            if(bDisableCache == true)
                sVars += "&noCache=true";
                
            if(bTransparent == true)
                sVars += "&tr=true";
             
            if(bToUpper == true)
                sVars += "&upper=true";
                
			 if (sAlign != null)
			    sVars += "&align=" + sAlign;
			    
			if(bBold == true)
                sVars += "&bold=true";
			
			if(bItalic == true)
                sVars += "&italic=true";
                
            if(bUnderline == true)
                sVars += "&unl=true";
                
            imgNode = document.createElement ("img");
            imgNode.setAttribute ("src", dotIRHandlerPath + "?" + sVars);
            imgNode.setAttribute ("alt", sText);

            node.appendChild (imgNode);
            node.appendChild (nodeAlternate);
			
			/*	Workaround to force KHTML-browsers to repaint the document. 
				Additionally, IE for both Mac and PC need this.
				See: http://neo.dzygn.com/archive/2004/09/forcing-safari-to-repaint */

			/*if(UA.bIsKHTML || UA.bIsIE){
				node.innerHTML += "";
			};*/
		};
		forceRedraw();	
	};
	
	function mayReplace(e){
		if(((UA.bIsXML && UA.bIsGecko || UA.bIsKHTML) && e == null && bIsInitialized == false) || document.getElementsByTagName("body").length == 0){
			return false;
		};
		return true;
	};
	
	function dotIR(e){
		if((!dotIR.bAutoInit && (window.event || e) != null) || !mayReplace(e)){
			return;	
		};
		bIsInitialized = true;
		
		for(var i = 0; i < stackReplaceElementArguments.length; i++){
			replaceElement.apply(null, stackReplaceElementArguments[i]);
		};
		stackReplaceElementArguments = [];

	};

	dotIR.replaceElement = replaceElement;
	dotIR.UA = UA;
	dotIR.bAutoInit = true;
	
	if(window.attachEvent){
		window.attachEvent("onload", dotIR);
	} else {
		if(document.addEventListener){
			document.addEventListener("load", dotIR, false);	
		};
		if(window.addEventListener){
			window.addEventListener("load", dotIR, false);	
		};
	};
	
	return dotIR;
}();
