/**
 * This file contains some global functions used for different kind of purposes in the application.
 * 
 * @version 21-01-2009
 * @author <a href="mailto:r.tennapel@griponservice.nl?SUBJECT=globalkit.js">R. ten Napel, ing.</a>
 **/

/**
 * A static class with all the global functions.
 **/
GlobalKit = new function() {
	/**
	 * Retrieve the browser.
	 * 
	 * @return				The current browser.
	 **/
	this.browser = function() {
		return navigator.appVersion;
	};
	
	/**
	 * Retrieve the document body width.
	 * 
	 * @return				The current body width.
	 **/
	this.screenWidth = function() {
		return document.body.clientWidth;
	};
	
	/**
	 * Retrieve the document body height.
	 * 
	 * @return				The current body height.
	 **/
	this.screenHeight = function() {
		return document.body.clientHeight;
	};
	
	/**
	 * Check if an object is an array.
	 * 
	 * @param obj				The object to check.
	 * 
	 * @return					If the given object is an array.
	 **/
	this.isArray = function(obj) {
		return (obj != "undefined" && typeof obj.constructor != "undefined" && obj.constructor == Array);
	};
	
	/**
	 * Converts a decimal value to hexadecimal.
	 * 
	 * @param value				The decimal value to convert.
	 * 
	 * @return					The converted value.
	 **/
	this.d2h = function(value) {
		return parseInt(value).toString(16);
	};
	
	/**
	 * Converts a hexadecimal value to decimal.
	 * 
	 * @param value				The hexadecimal value to convert.
	 * 
	 * @return					The converted value.
	 **/
	this.h2d = function(value) {
		return parseInt(value, 16);
	};
	
	/**
	 * Converts an rgb string which defines the rgb value of a background color to a hexadecimal value.
	 * 
	 * @param rgb				The RGB string (p.h. "rgb(23, 32, 12)").
	 * 
	 * @return					The hex-value (p.h. "#ff3344").
	 **/
	this.rgb2h = function(rgb) {
		rgb = rgb.replace(/rgb\(|\)/g, "").split(",");
		
		// Retrieve the RGB integer values and convert to hex:
		rgb[0] = parseInt(rgb[0], 10).toString(16).toLowerCase();
		rgb[1] = parseInt(rgb[1], 10).toString(16).toLowerCase();
		rgb[2] = parseInt(rgb[2], 10).toString(16).toLowerCase();
		
		// Add 0 if the hex value is 1 in length:
		rgb[0] = (rgb[0].length == 1) ? "0" + rgb[0] : rgb[0];
		rgb[1] = (rgb[1].length == 1) ? "0" + rgb[1] : rgb[1];
		rgb[2] = (rgb[2].length == 1) ? "0" + rgb[2] : rgb[2];
		
		return "#" + rgb.join("");
	};
	
	/**
	 * Retrieve a textual element tree of a given element with a maximum element depth stated by maxDepth.
	 * 
	 * @param element			The element to search for nodes / childs.
	 * @param maxDepth			The maximum recursive depth to search for nodes / childs.
	 * 
	 * @return					A textual representation of this element's node / child tree.
	 **/
	this.getElementTree = function(element, maxDepth) {
		text = "";
		
		// If the maximum depth is set to 0 exit the function:
		if (element == null || maxDepth == 0) {
			return text;
		}
		
		// Retrieve all childs of the element and sort by key:
		var childs = new Array();
		for (var child in element) {
			// Ignore the debug child:
			if (key != "getElementTree" && key != "debug") {
				childs[childs.length] = child;
			}
		}
		childs.sort();
		
		// Write the table header:
		text += "<table style='background-color: #cccccc; border: 1px solid #000000;'>";
		
		// Iterate through all element childs:
		for (var i = 0; i < childs.length; i++) {
			try {
				// Retrieve the child key and value:
				var key = new String(childs[i]);
				var value = new String(element[key]);
				
				// Ignore HTML tags and linebreaks:
				value = value.replaceAll('<script>','');
				value = value.replaceAll('</script>','');
				value = value.replaceAll('</script>','');
				value = value.replaceAll('<','&lt;').replaceAll('>','&gt;').replaceAll('\n','\n<br>');
				
				// Write the child:
				text += "<tr><td style='background-color: #eeeeee; vertical-align: top; border: 1px solid #000000; border-right: 1px solid #eeeeee; text-align: right;'>" + key + "</td><td style='background-color: #ffffff; vertical-align: top; border: 1px solid #000000; border-left: 1px solid #eeeeee;' valign='top' nowrap>";
				
				// If the child is an object go into it (recursively) else write the child value:
				if (typeof(element[key]) == "object") {
					text += getElementTree(element[key], maxDepth - 1);
				} else {
					text += value;
				}
				
				text += "</td></tr>";
			} catch(error) {
				text += "<tr><td style='background-color: #eeeeee; vertical-align: top; border: 1px solid #000000; border-right: 1px solid #eeeeee; text-align: right;'>ERROR</td><td style='background-color: #ffffff; vertical-align: top; border: 1px solid #000000; border-left: 1px solid #eeeeee;' valign='top' nowrap>";
				text += error.descripiton;
				text += "</td></tr>";
			}
		}
		
		// Write the table footer:
		text += "</table>";
		
		return text;
	};
	
	/**
	 * Retrieve all input values, defined by tag name, of an element in one string (especially used with forms).
	 * 
	 * @param element		The element.
	 * @param tagName		The tag name to search for.
	 * 
	 * @return				The string.
	 **/
	this.getVars = function(element, tagName) {
		var getstr = "";
		
		// Define default tag name:
		if (tagName == null) {
			tagName = "INPUT";
			
			// Retrieve all values rgb all input types:
			getstr = GlobalKit.getVars(element, "SELECT");
			getstr += GlobalKit.getVars(element, "TEXTAREA");
		}
		
		// Retrieve all input elements:
		inputs = element.getElementsByTagName(tagName);
		
		// Iterate through all the input elements:
		for (var i = 0; i < inputs.length; i++){
			//getstr += inputs[i].type + "\n";
			if (inputs[i].type == "checkbox") {
				if (inputs[i].checked) {
					getstr += (inputs[i].name + "=" + inputs[i].value + "&");
				}
			} else if (inputs[i].type == "hidden") {
				getstr += (inputs[i].name + "=" + inputs[i].value + "&");
			} else if (inputs[i].type == "password") {
				getstr += (inputs[i].name + "=" + inputs[i].value + "&");
			} else if (inputs[i].type == "radio") {
				if (inputs[i].checked) {
					getstr += (inputs[i].name + "=" + inputs[i].value + "&");
				}
			} else if (inputs[i].type == "select-one") {
				getstr += (inputs[i].name + "=" + inputs[i].value + "&");
			} else if (inputs[i].type == "submit") {
				getstr += ("submit=" + inputs[i].value + "&");
			} else if (inputs[i].type == "text") {
				getstr += (inputs[i].name + "=" + inputs[i].value + "&");
			} else if (inputs[i].type == "textarea") {
				getstr += (inputs[i].name + "=" + inputs[i].value.replaceAll("\n", "%0A").replaceAll("&", "%26") + "&");
			}
		}
		
		return getstr;
	};
	
	/** This variable represents all dynamically loaded files. **/
	this.loadedFiles = "";
	
	/**
	 * Load a Javascript file dynamically.
	 * 
	 * @param				The filename.
	 **/
	this._loadJS = function(filename) {
		// If file was already loaded exit:
		if (GlobalKit.loadedFiles.indexOf("[" + filename + "]") != -1) {
			return;
		}
		
		// Load the javaScript through Ajax:
		new Ajax(null, filename, null, null, function(response) { eval(response); }).request();
		
		// Store the filename:
		GlobalKit.loadedFiles += "[" + filename + "]";
	};
	this.loadJS = function(filename) {
		// If file was already loaded exit:
		if (GlobalKit.loadedFiles.indexOf("[" + filename + "]") != -1) {
			return;
		}
		
		// Create a new script element:
		var fileref = document.createElement("script");
		
		// Define the script type:
		fileref.setAttribute("type", "text/javascript");
		fileref.setAttribute("src", filename);
		
		// Add to header:
		if (typeof fileref != "undefined") {
			document.getElementsByTagName("head")[0].appendChild(fileref);
			
			GlobalKit.loadedFiles += "[" + filename + "]";
		}
	};
	
	/**
	 * Load a CSS file dynamically.
	 * 
	 * @param				The filename.
	 **/
	this.loadCSS = function(filename) {
		// If file was already loaded exit:
		if (GlobalKit.loadedFiles.indexOf("[" + filename + "]") != -1) {
			return;
		}
		
		// Create a new script element:
		var fileref = document.createElement("link");
		
		// Define the script type:
		fileref.setAttribute("rel", "stylesheet");
		fileref.setAttribute("type", "text/css");
		fileref.setAttribute("href", filename);
		
		// Add to header:
		if (typeof fileref != "undefined") {
			document.getElementsByTagName("head")[0].appendChild(fileref);
			
			GlobalKit.loadedFiles += "[" + filename + "]";
		}
	};
	
	/**
	 * Add a CSS rule to the current document style (p.h. css("html { background-color: red; }")).
	 * 
	 * @param style			The style to add to the document main style.
	 **/
	this.css = function(style) {
		// Retrieve head:
		var head = document.getElementsByTagName("HEAD")[0];
		
		// Retrieve style definitions in head:
		var elements = head.getElementsByTagName("STYLE");
		
		// Retrieve main style if exists or create a new one:
		var element;
		if (elements.length == 0) {
			element = document.createElement("STYLE");
			element = head.appendChild(element);
		} else {
			element = elements[0];
		}
		
		// Add the style if not already there:
		if (element.styleSheet) {
			if (!element.styleSheet.cssText.contains(style)) {
				element.styleSheet.cssText += style;
			}
		} else if (!element.innerHTML.contains(style)) {
			element.innerHTML += style;
		}
	};
};

/*this._getElementsByClassName = function(className, tagName, rootElement, all) {
	// Search in all tags if tag name is not defined:
	if (tagName === null) {
		tagName = "*";
	}
	
	// Search in all elements if root element is not defined:
	if (rootElement === null) {
		rootElement = document;
	}
	
	// All given class names must be available when set to true, else one of the given class names must be available:
	if (all === null) {
		all = true;
	}
	
	// Retrieve all elements to search for the given class name(s):
	var found = (tagName == "*" && rootElement.all) ? rootElement.all : rootElement.getElementsByTagName(tagName);
	var elements = new Array();
	var classNameRegExp = new Array();
	
	var classNames = new Array();
	if (!isArray(className)) {
		classNames.push(className);
	} else {
		classNames.merge(className);
	}
	
	for (var i = 0; i < classNames.length; i++) {
		classNameRegExp.push(new RegExp("(^|\\s)" + classNames[i].replace(/\-/g, "\\-") + "(\\s|$)"));
	}
	
	var element;
	var matchesAll = false;
	for (var i = 0; i < found.length && matchesAll; i++) {
		element = found[i];
		matchesAll = true;
		
		for (var j = 0; j < classNameRegExp.length && matchesAll; j++) {
			if (!classNameRegExp[j].test(element.className)) {
				if (all) {
					matchesAll = false;
				}
			}
		}
		
		if (matchesAll) {
			elements.push(element);
		}
	}
	
	// Make all elements chainable:
	for (i = 0; i < elements.length; i++) {
		// Make chainable:
		if (elements[i] != null) {
			elements[i] = makeChainable(elements[i]);
		}
	}
	
	return elements;
}*/

/**
 * Retrieve all elements with the given class name.
 * 
 * @param className			The class name.
 * 
 * @return					An array of elements.
 **/
document.getElementsByClassName = function(className) {
	// Create the elements arrays:
	var elements = new Array();
	
	// If no class name is given:
	if (className == null) {
		return elements;
	}
	
	// Retrieve all elements:
	var totalElements = document.all ? document.all : document.getElementsByTagName("*");
	
	// Define all regular expressions to find the class names:
	var classNameRegExp = new RegExp("(^|\\s)" + className.replace(/\-/g, "\\-") + "(\\s|$)");
	
	// Scan every element for the correct class name:
	for (var i = 0; i < totalElements.length; i++) {
		if (classNameRegExp.test(totalElements[i].className)) {
			elements.push(totalElements[i]);
		}
	}
	
	return elements;
};

/** 
 * Create a DOMParser for IE (like the one used in FireFox).
 **/
if (typeof(DOMParser) == "undefined") {
	DOMParser = function() {};
	
	DOMParser.prototype.parsergbString = function(str, contentType) {
		if (typeof(ActiveXObject) != "undefined") {
			var xmldata = new ActiveXObject("MSXML.DomDocument");
			
			xmldata.async = false;
			xmldata.loadXML(str);
			
			return xmldata;
		} else if (typeof(XMLHttpRequest) != "undefined") {
			var xmldata = new XMLHttpRequest;
			
			if (!contentType) {
				contentType = "application/xml";
			}
			
			xmldata.open("GET", "data:" + contentType + ";charset=utf-8," + encodeURIComponent(str), false);
			
			if (xmldata.overrideMimeType) {
				xmldata.overrideMimeType(contentType);
			}
			
			xmldata.send(null);
			
			return xmldata.responseXML;
		}
	};
}
