/*
* Configuration XML reader.   
* version 2.1
* Requires helpers.js
*/




function Config(dataIslandId) {
	
	/*
	 * When an event calls an object method, "this" will point to object
	 * that called the event, not the object that owns the method.  This
	 * is bad.  So, have an internal variable, "me" that points to the
	 * object that called the method.  This is based on an idea from
	 * http://w3future.com/html/stories/callbacks.xml
	 */


	var me=this;
	
	var fileName;
	var req;
	var id = dataIslandId;
	
	// this is a private variable for security reasons.
	var values = new Array();

	var xml = null; // This will contain the DOM tree of the config XML block.

	function content(tag) {
		if (tag && tag.firstChild && tag.firstChild.nodeValue) {
			//config.debugLog(tag.firstChild.nodeValue);
			return tag.firstChild.nodeValue;
		}
	}
	
	function getArrayValues(tag) {
		var childNodes = DOMHelpers.getAllChildElements(tag);
		var returnValue = new Array();
		
		for (var i=0; i<childNodes.length; i++) {
			var childNode = childNodes[i]
			returnValue[childNode.nodeName] = XMLHelpers.nodeToObject(childNode)	
		}
		
		return returnValue;
	}
	
	function cloneObject(obj) {
	    for (i in obj) {
	        this[i] = what[obj];
	    }
	}
	
	me.getValue = function (s, defaultValue) {
		if (values) {
			var theValue = values[s];
			if (theValue != null) {
				return theValue
			} else {
				return defaultValue
			}
			
		} else if (defaultValue) {
			return defaultValue;
		} else {
			return null;
		}
	}
	
	
	
	me.getNormalizedValue = function (s, defaultValue) {
		var crRe = new RegExp("\n", "g");
		var r = me.getValue(s, defaultValue);
		
		if (typeof(r) == 'string') {
			return r.replace(crRe, '');
		} else {
			return r;
		}
	}
	
	me.getScriptedValue = function(s, macros, defaultValue){
		
		var r = me.getNormalizedValue(s, defaultValue);
		
		switch (typeof(r)) {
			case "string":
				return resolveMacrosInString(r, macros);
				break;
			case "object": // assume array
				var arr = me.getValue(s, defaultValue);
				var cloneArr = new Array();
				for (var i in arr) {
					var obj = arr[i];
					var cloneObj = new Object();
					for (var property in obj) {
						if (typeof(obj[property]) == 'string') {
							cloneObj[property] = resolveMacrosInString(obj[property], macros);
						}
					}
					cloneArr[i] = cloneObj;
					
				}
				return cloneArr;
				break;
			default:
				return null;
		}
	}
	
	function resolveMacrosInString(string, macros){
		
		for (i in macros) {
			var value = macros[i]
			
			if (!value) {
				value ="";
			}
			var reString = '@' + i + '([^a-zA-Z])?'; //StringHelpers.sprintf("@%s([^a-zA-Z])?", i)
			var re = new RegExp(reString, 'g');
			var replaceString = value+'$1'; //StringHelpers.sprintf("%s$1", value)
			
			string = string.replace(re, replaceString)
		}
		
		return string;
	}
	
	
	/* 
	 * Try the newMacro first, then try the old one.  This is so that we can 
	 * use new style object oriented config macros while not breaking scripts
	 * that rely on the old ones.
	 */
	me.getScriptedValueByPriority = function (newMacro, oldMacro, macros, defaultValue) {
		var newMacroValue = me.getScriptedValue(newMacro, macros, defaultValue);
		
		if (newMacroValue) {
			return newMacroValue;
		} else {
			return me.getScriptedValue(oldMacro, macros, defaultValue);
		}
	}
	
	me.getIntegerValue = function(s, defaultValue) {
		return parseInt(me.getValue(s, defaultValue));
	}
	
	me.debugLog = function (s) {
		try {
			Logger.info(s);
		} catch (e) {
			window.status = "Error.";
		}
		
	}
	
	
	// This is private for security reasons.
	function setValue (name, valueToSet) {
		values[name] = valueToSet;
	}

	me.init = function() {
	
	  if (EventHelpers.hasPageLoadHappened(arguments)) return;
	  
	  //alert('entered initConfig');
	  var configComment = document.getElementById(id);
	  
	  if (!configComment) {
	  	return;
	  }
	  
	  
	  var data = configComment.innerHTML;
	  
	  if (data.indexOf('xml=') == 0) {
	  	fileName = data.split('=')[1];
		req = XMLHelpers.getXMLHttpRequest(fileName, getOuterConfigRequestHandler, 'GET', '', false)
		getOuterConfigRequestHandler();
	  } else {
	  
		  if (!configComment) {
		  	alert('no config island.  Exiting.');
		  	return;
		  }
		  
		 
		  xml = XMLHelpers.parseXMLDataIsland(configComment);
		  
		  parseConfigXML(xml)
	   }
	}
	
	
	function parseConfigXML(configDoc) {
		  if (configDoc) {
		  	var configTag = configDoc.getElementsByTagName('config')[0];
	
		  	if (!configTag) {
		  		alert('no config tag in XML');
		  		return;
		  	}
	
		  	//var tags = configTag.getElementsByTagName('*');
			var tags = configTag.childNodes;
			
			index(tags, "");
	
		  	
		  } else {
		  	//alert('config id is not present');
		  }
		//alert('exited initConfig');
	}
	
	
	function getOuterConfigRequestHandler() {
		
		if (!req) {
			return;
		}
		
		if (req.readyState == ReadyState.COMPLETED) {
            // only if "OK"
            if (req.status == HttpCode.OK || req.status == HttpCode.LOCAL_OK) {
				xml = req.responseXML
				//alert(req.responseText)
				parseConfigXML(xml);
				req = null;
			} else if (req.status == HttpCode.NOT_FOUND) {
				alert(StringHelpers.sprintf("config: %s not found", fileName));
			} else {
				alert('config: an unknown error has occured');
			}
		}
	}
	
	function index(tags, prefix) {
		if (!tags) {
	  		//alert('no config macros');
	  		return;
	  	}

	  	for (var i=0; i < tags.length; i++) {
	  	  var theTag = tags[i];
		  
	  	  /* if the tag is a tag node */
		  if (theTag.nodeType == DOMNode.ELEMENT_NODE ) {
	  		
	  		var tagName = theTag.nodeName;

				var childNodes = DOMHelpers.getAllChildElements(theTag);
		  		
				var datatype = DOMHelpers.getAttributeValue(theTag, 'datatype');
				
				if (datatype == 'array') {
					setValue(
						StringHelpers.sprintf("%s%s", prefix, tagName), 
						getArrayValues(theTag));
					
				} else 	if (childNodes.length == 0) {
					//alert(StringHelpers.sprintf("%s%s", prefix, tagName))
					setValue(
						StringHelpers.sprintf("%s%s", prefix, tagName), 
						content(theTag));
				} else {
						index(childNodes, StringHelpers.sprintf(
							"%s%s.", prefix, tagName));
				}
		  }
	  	}
	}
	
	
	
}




var config = new Config('config');

EventHelpers.addPageLoadEvent("config.init");
