/*****************************************************************************************************
By. Mark Fogle
url: http://www.softwareceo.com
Date: 3-18-08
******************************************************************************************************/

/*****************************************************************************************************
function: 	getrandomitem
parameters: url - address of the xml file to load 
			destinationID - ID of the container to put the result in  
			document.write apparently doesn't work well in some browsers, so 
			accessing the DOM directly is more reliable
			[optional]templateName - if multiple templates, which one?
			[optional]filter - filter items based on this criteria. "tag=value" format

purpose:  	return a random item from an xml file, formatted according to a template in the xml file
comments: 	Loading works differently in IE and Firefox and Safari, so loading has to be handled differently
	  		load an xml file and parse it once loaded.
		  	pass destinationID as a string... 

			An improvement might be to add a <frequency></frequency> so you could randomly change the
			item of the hour/day/month etc.
******************************************************************************************************/
var xmldoc;
var destID;
var tName;
var fltr;

function getRandomItem(url, destinationID, templateName, filter) { 
    destID = destinationID;

    if (templateName == undefined) {
	tName = "default";
    }
    else {
	tName = templateName;
    }
	
    if (filter == undefined ) {
	fltr = "none";
    }
    else {
	fltr = filter;
    }
	
    xmldoc = false;

    // branch for native XMLHttpRequest object
    if(window.XMLHttpRequest && !(window.ActiveXObject)) {
    	try {
	    xmldoc = new XMLHttpRequest();
	    if(xmldoc) {
		xmldoc.onreadystatechange = parseXML;
		xmldoc.open("GET", url, true);
		xmldoc.send(null);
	    }
        } 
        catch(e) {
	    xmldoc = false;
        }
    } 

    // branch for IE/Windows ActiveX version
    else if(window.ActiveXObject) {
       	try {
            xmldoc = new ActiveXObject("Microsoft.XMLHTTP");
      	} 
        catch(e) {
     	    try {
                xmldoc = new ActiveXObject("Msxml2.XMLHTTP");
            } 
            catch(e) {
          	xmldoc = false;
            }
        }
	if(xmldoc) {
	    xmldoc.onreadystatechange = parseXML;
	    xmldoc.open("GET", url, true);
	    xmldoc.send();
	}
    }
}

function parseXML() {
    if (xmldoc.readyState == 4) {	// if xmldoc shows "loaded"
        if (xmldoc.status == 200) {         // if "OK"
	    var xmldata = xmldoc.responseXML.getElementsByTagName("data")[0]; //get the data element
	    var delimiter=GetNodeData(xmldata,"delimiter");			 //get the delimiter to be used for substitutions

	    //get the desired item template
	    var templates = xmldata.getElementsByTagName("template"); 
	    var tmpl = GetNodeData(templates[0],"structure");		//if only one, pick it. Otherwise, this is an initial value

	    if (templates.length > 1) {
		for (var i = 1; i < templates.length; i++) {
		    if (GetNodeData(templates[i],"name") == tName) {
			tmpl = GetNodeData(templates[i],"structure")
		    }
		}
	    }
	
	    //perform file-level tag substitutions (case insensitive) for each child tag
	    for (var i = 0; i < xmldata.childNodes.length; i++) {		
	        if (xmldata.childNodes[i].tagName != undefined) {
		    var nd = GetNodeData(xmldata, xmldata.childNodes[i].tagName);
		    if (nd == undefined) {nd=""};
		    tmpl = tmpl.replace(new RegExp(delimiter + xmldata.childNodes[i].tagName + delimiter,"gi"), nd);
	        }
	    }

	    //create an array of indices that match the filter (all if no filter)
	    var items = xmldata.getElementsByTagName("item");			    	//get all the individual items from the data element
	    var fitems = [];
	    for (var i = 0; i < items.length; i++) {
		if (fltr == "none") {
		    fitems[fitems.length] = i;						//include all if no filter
		}
		else {
		    var arrFilter = fltr.split("=");			    		//filter originally entered in "tag=value" format
		    if (GetNodeData(items[i],arrFilter[0]) == arrFilter[1]){
		        fitems[fitems.length] = i;
		    }
		}
	    }

	    var rand = items[fitems[randomNumber(0, fitems.length-1)]];			//select a random one.  Indexes start at 0 to #items-1.  Length=#items
	    for (var i = 0; i < rand.childNodes.length; i++) {				//perform item-level substitutions (case insensitive) for each child tag
		if (rand.childNodes[i].tagName != undefined) {
		    var nd = GetNodeData(rand, rand.childNodes[i].tagName);
		    if (nd == undefined) {nd=""};
		    tmpl = tmpl.replace(new RegExp(delimiter + rand.childNodes[i].tagName + delimiter,"gi"), nd);
		}
	    }
	
	    document.getElementById(destID).innerHTML = tmpl;				//set the innerHTML of the destination container
        } // status=OK 
        else {
            alert("There was a problem retrieving the XML data:\n" + xmldoc.statusText);
        }
    } // readyState=Loaded
}

function GetNodeData(curNode, tagname) {
    var elements = curNode.getElementsByTagName(tagname)[0];
    if (elements != null) {								//Does specified tag exist? Trying to access childNodes will generate an error if not.
	var mNodes = elements.childNodes; 						//Firefox and IE find this in different nodes, particularly for CDATA sections
	
	for (var n = 0; n < mNodes.length; n++) {
	    switch (mNodes[n].nodeType) {
		//in Firefox, if data is encapsulated with CDATA, and there are line breaks before the data (for formatting/nesting), Firefox 
		//returns the blank lines separately as text nodes. The first line would be a text node, and the actual data is on another node.
		case 3:	txt = removeinvisible(mNodes[n].nodeValue); 
			if (txt!=""){
			    return txt;//return only if not empty
			};
			break; //TEXT_NODE
		case 4: return mNodes[n].nodeValue; break; //CDATA_SECTION_NODE
		default: return mNodes[n].nodeValue; break; //OTHER NODES
	    }
	}
    }
}

function removeinvisible(txt) {
    var t = "";
    for (i=0; i < txt.length; i++) {
	switch (txt.charCodeAt(i)) {
	    case 9:  break;
	    case 10: break;
	    case 13: break;
	    default: t += txt.charAt(i); break;
	}
    }
    return t;
}

function randomNumber(fromNum, toNum) {
    return fromNum + Math.floor((toNum - fromNum + 1)*(Math.random()%1))
}
