//****************************************************************************************
//
//	global.js
//
//	Object for use globally.
//
//	Depends On:
//				
//
//	Copyright: 	David Horne, Tuross Technologies Australia P/L, 2009.
//				dkhorne@bigpond.net.au
//
//****************************************************************************************

//****************************************************************************************
//	Parse the URL into Paramter Name/Value pairs 
//****************************************************************************************
	var parameters = function() {

		var loc = {};
	
		loc.url = document.location.toString();
		loc.file = loc.url.substr(0, (loc.url.indexOf("?") > 0 ? loc.url.indexOf("?") : loc.url.length));
		loc.paths = document.location.pathname.split("/").slice(1).reverse().slice(1);
		loc.hash = document.location.hash.substr(1);
		loc.host = window.location.protocol + "//" + window.location.host;

		var iStart = (loc.url.indexOf("?") > 0 ? loc.url.indexOf("?") + 1 : loc.url.length);
		var iEnd = (loc.url.indexOf("#") > 0 ? loc.url.indexOf("#") : loc.url.length);
		var parameters = (iStart < iEnd ? loc.url.substr(iStart, (iEnd - iStart)).split("&") : []);
		var tmp;
		for (var i = 0; i < parameters.length; i++) {
			tmp = parameters[i].split("=");
			if (loc[tmp[0]]) {
				if (loc[tmp[0]].constructor != Array) loc[tmp[0]] = [loc[tmp[0]]];
				loc[tmp[0]].push(tmp[1]);
			} else {
				loc[tmp[0]] = tmp[1];
			}
		}
		
		loc["get"] =	function(name, defaultVal) {
							if (this[name] != null)
								return unescape(this[name]);
							else
								return (defaultVal != null ? defaultVal : null);
						};
						
		loc["path"] =	function(i) {
							return this.paths[((i == null) || (i < 0 )? i == 0 : (i >= this.paths.length ? this.paths.length - 1 : i))];
						};

		return loc;

	}();

//****************************************************************************************
// Cookie Support
//****************************************************************************************

	var cookie = function() {
	
		return {
			'set':						function(Document, Name, Value, Expires) {
											var ExpiryDate = "";
											if (Expires != null) ExpiryDate = "expires=" + Date.parse(Expires).toGMTString() + ";";
											Document.cookie = Name + "=" + escape(Value) + ";" + ExpiryDate;
										},
										
			'get':						function(Document, Name, Default) {
											var re = new RegExp(Name + "=([^;]+)");
											var Value = re.exec(Document.cookie);
											return (Value != null) ? unescape(Value[1]) : Default;
										},

			'delete':					function(Document, Name) {
											cookie.set(Document, Name, null);
										}
		}
	}();


//****************************************************************************************
//	DOM used to access and manipulate the DOM
//****************************************************************************************

	var DOM = function() {
	
		var DOM_elementDetails_refresh = 	function(element) {
												if (this.element == null) {
													if (element != null) {
														if (typeof(element) == "string")
															this.element = DOM.getElementById(element);
														else
															this.element = element;
													} else {
														return;
													}
												}
		
												this.window = (this.element.ownerDocument.parentWindow ? this.element.ownerDocument.parentWindow : this.element.ownerDocument.defaultView);
												this.screen = this.window.screen;
										
												if (typeof(this.window.innerWidth) == 'number') {
													this.width = this.window.innerWidth;
													this.height = this.window.innerHeight;
												} else if (this.window.document.documentElement && typeof(this.window.document.documentElement.offsetWidth) == 'number') {
													this.width = this.window.document.documentElement.offsetWidth;  
													this.height = this.window.document.documentElement.offsetHeight;  
												} else if (this.window.document.body && typeof(this.window.document.body.offsetWidth) == 'number') {
													this.width = this.window.document.body.offsetWidth;  
													this.height = this.window.document.body.offsetHeight;    
												}
																	
										
												this.pos = { top: 0, left: 0, bottom: 0, right: 0, height: this.element.offsetHeight, width: this.element.offsetWidth }
												var tmpElement = this.element;
												while (tmpElement != null) {
													this.pos.top += tmpElement.offsetTop;
													this.pos.left += tmpElement.offsetLeft;
													tmpElement = (tmpElement.offsetParent != null ? tmpElement.offsetParent : null);
												}
										
												this.pos.bottom = this.pos.top + this.pos.height;
												this.pos.right = this.pos.left + this.pos.width;
											};

		var DOM_elementDetails_set = 		function(name) {
												if (arguments.length > 1) {
													switch (name.toLowerCase()) {
														case "height":
															var height = 0;
															if (arguments[1].pos != null) {
																for (var i = 1; i < arguments.length; i++)
																	height += arguments[i].pos.height;
																height = this.height - height;
															} else {
																height = arguments[1];
															}
															this.element.style.height = height + "px";
															break;
														
														case "width":
															var width = 0;
															if (arguments[1].pos != null) {
																for (var i = 1; i < arguments.length; i++)
																	width += arguments[i].pos.width;
																width = this.width - width;
															} else {
																width = arguments[1];
															}
															this.element.style.width = width + "px";
															break;
														
														default:
															eval("this.ElementObj." + name + " = " + arguments[1]);
															break;
													}
													this.refresh();
												}
											};
	
		return {
		
			element:						null,
			
			//	get Elements by Name or ID
			getElementById: 				function(id, windowRef) { 
												if (!windowRef) windowRef = window; 
				
												if (document.getElementById) {
													return windowRef.document.getElementById(id); 
												} else if (document.all) {
													var elements = windowRef.document.all[id];
													if (elements == null)
														return null;
														
													elements = (((elements.length != null) && (elements.length > 0)) ? elements[0] : elements);
		
													return ((elements.id != id) ? elements : null);
												} else {
													return null;
												}
											},
									
			getElementsByName:				function (name, windowRef) {
												if (!windowRef) windowRef = window; 
												
												if (document.getElementById) {
													return windowRef.document.getElementsByName(name); 
												} else if (document.all) {
													var elements = windowRef.document.all[name];
													var elementArray = new Array();
													if (elements == null)
														return null;
														
													elements = (((elements.length != null) && (elements.length > 0)) ? elements : [elements]);
												
													for (var i = 0; i < elements.length; i++) {
														if ((elements[i].name == name) || (elements[i].id == name))
															elementArray.push(elements[i]);
													}
												
													return elementArray;
												} else {
													return null;
												}
											},
	
			//	set the inner HTML
			setInnerHTML:	 				function (elementid, str, windowRef) { 
												var elements = this.getElementsByName(elementid, windowRef);
												if ((elements == null) || (elements.length == 0))
													elements = this.getElementById(elementid, windowRef);
													
												if (elements != null) {
													if (elements.length > 0) {
														for (var i = 0; i < elements.length; i++) {
															if (typeof(elements[i].innerHTML) != 'undefined')
																elements[i].innerHTML = str; 
														}
													} else {
														if (typeof(elements.innerHTML) != 'undefined')
															elements.innerHTML = str; 
													}
													return true;
												} else {
													return false;
												}
											},
											
			//	Sets the visibility of an element
			visible:						function(elementID, visible) {
												this.setStyle(elementID, "display", (visible ? "block" : "none"));
											},

			//	Sets the style of the element given by elementID
			setStyle:						function(elementID, style, value) {
												element = this.getElementById(elementID);
												if ((element != null) && (element.style[style] != null))
													element.style[style] = value;
											},
	
			//	Sets the value of the element given by elementID
			setValue:						function(elementID, value) {
												element = this.getElementById(elementID);
												if (element != null)
													element.value = value;
											},
	
			//	Sets the option list of an element given by elementID
			setOptions:						function(elementID, items) {
												element = this.getElementById(elementID);
												if (element != null) {
												
												}
													element.value = value;
											},
	
			//	Sets the focus on the element given by elementID
			setFocus:						function(elementID) {
												element = this.getElementById(elementID);
												if (element != null)
													element.focus();
											},
	
			//	find a window by Name
			findWindow: 					function(frameName, windowRef) {
												var returnFrame;
												if (windowRef == null) 
													windowRef = top;
											
												if (windowRef.name == frameName) 
													return(windowRef);
											
												if (windowRef.frames != null) {
													for (var i = 0; i < windowRef.frames.length; i++) {
														returnFrame = this.findWindow(frameName, windowRef.frames[i]);
														if (returnFrame != null) 
															return(returnFrame);
													}
												}
												return(null);
											},
	
			//	Returns an obj containing positional information about a target object
			elementDetails: 				function(element) { 
												var result = new Object();
												result.element = null;
												result.window = {};
												result.screen = {};
												result.pos = {};
												result.width = 0;
												result.height = 0;
												
												result.refresh = DOM_elementDetails_refresh;
												result.set = DOM_elementDetails_set;
												
												result.refresh(element);
												
												return result;
											}
		}
	}();
//	End DOM
//****************************************************************************************

//****************************************************************************************
//	Global Browser Sniffer
//****************************************************************************************
	var TheBrowsers = {	'msie ' : {'Code':'MSIE', 'Name':'MS Internet Explorer'},
						'firefox/' : {'Code':'firefox', 'Name':'FireFox'},
						'thunderbird/' : {'Code':'firefox', 'Name':'FireFox'},
						'konqueror/' : {'Code':'konqueror', 'Name':'Konqueror'},
						'netscape/' : {'Code':'netscape', 'Name':'Netscape'},
						'netscape6/' : {'Code':'netscape', 'Name':'Netscape'},
						'ns8/' : {'Code':'netscape', 'Name':'Netscape'},
						'opera/' : {'Code':'opera', 'Name':'Opera'},
						'opera ' : {'Code':'opera', 'Name':'Opera'},
						'safari/' : {'Code':'safari', 'Name':'Safari'},
						'mozilla/' : {'Code':'mozilla', 'Name':'Mozilla'},
						'mozilla ' : {'Code':'mozilla', 'Name':'Mozilla'},
						'unknown' : {'Code':'unknown', 'Name':'Unknown'}
					  };
					  
	var TheOSs = {	'linux' : 'Linux',
					'x11' : 'Unix',
					'mac' : 'Mac',
					'win' : 'Windows',
					'unknown' : 'Unknown OS'
				 };


	var browser = {
		agent: 		navigator.userAgent,
		code: 		"",
		name: 		"",
		version: 	"",
		major: 		"",
		minor: 		"",
		OS: 		"",

		load:		function() {
						var theAgent = this.agent.toLowerCase();
						for (var theBrowser in TheBrowsers)
							if (theAgent.indexOf(theBrowser) >= 0) break;
				
						var iStart = theAgent.indexOf(theBrowser) + theBrowser.length;
						var iEnd = (theAgent.indexOf(" ", iStart) > 0 ? theAgent.indexOf(" ", iStart) : theAgent.length);
				
						this.code = TheBrowsers[theBrowser].Code;
						this.name = TheBrowsers[theBrowser].Name;
						this.version = theAgent.substring(iStart, iEnd);
						this.major = parseInt((this.version.split(".")[0] ? this.version.split(".")[0] : 0));
						this.minor = parseInt((this.version.split(".")[1] ? this.version.split(".")[1] : 0));
					
						if (this.OS == "") {
							for (var theOS in TheOSs)
								if (theAgent.indexOf(theOS) >= 0) break;
							this.OS = TheOSs[theOS];
						}
					}
	}
	browser.load();

//	End Browser
//****************************************************************************************



//****************************************************************************************
//	Global object that provides multiple functions
//****************************************************************************************

	var global = function() {
	
			//	parses a date string to date
		var parseDate = 			function(source) {
										var strMonths = new Array("january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december");
										var MonthDays = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
								
										var iYear, iMonth, iDay, iHour, iMin, iSec, imSec;
								
										var iPos = 0;
										
										if (global.isEmpty(source)) return "";
										
										//remove the day name
										var reDays = /mon\w*|tue\w*|wed\w*|thu\w*|fri\w*|sat\w*|sun\w*/g;
								       	source = source.toString().toLowerCase().replace(reDays, "");
							
										//match the date parts and determine format
										var reDateParts = /[\/\-:.t ]*([^t\W]*)[\/\-:.t ]*([^t\W]*)[\/\-:.t ]*([^t\W]*)[\/\-:.t ]*([^t\W]*)[\/\-:.t ]*([^t\W]*)[\/\-:.t ]*([^t\W]*)/;
										var DateArray = source.match(reDateParts);
										var YMD = (DateArray[1] > 31) && (DateArray[3] <= 31)
										var IsAM = (source.toString().indexOf("am") >= 0);
										var IsPM = (source.toString().indexOf("pm") >= 0);
								
										if (DateArray.length >= 4) {
											iYear = parseFloat(YMD ? DateArray[1] : DateArray[3]);
								
											if (isNaN(parseFloat(DateArray[2]))) {
												if (iMonth == null)
													for (var j = 0; j < strMonths.length; j++)
														if (strMonths[j].indexOf(DateArray[2]) >= 0) iMonth = j;
											} else {
												iMonth = parseFloat(DateArray[2]) - 1;
											}
								
											iDay = parseFloat(YMD ? DateArray[3] : DateArray[1]);
											iHour = (DateArray[4] != "" ? parseFloat(DateArray[4]) : 0);
											iMin = (DateArray[5] != "" ? parseFloat(DateArray[5]) : 0);
											iSec = (DateArray[6] != "" ? parseFloat(DateArray[6]) : 0);
										}
										
								// Do Some checks
										if ((iMonth >= 12) && (iDay <= 12)) {
											var tmp = iMonth;
											iMonth = iDay - 1;
											iDay = tmp + 1;
										}
										
										iHour += (IsPM ? 12 : 0) + (IsPM && (iHour == 12) ? -12 : 0) + (IsAM && (iHour == 12) ? -12 : 0);
								
										var TheDate = new Date(iYear, iMonth, iDay, (iHour != null ? iHour : 0), (iMin != null ? iMin : 0), (iSec != null ? iSec : 0), (imSec != null ? imSec : 0));
										if (isNaN(TheDate)) {
											TheDate = new Date(strDate);
											if (isNaN(TheDate)) {
												alert("Invalid date: " + strDate + "\nValid formats include dd mmm yyyy hh:mm:ss or dd/mm/yy.")
			return "";
	}
										}
										return TheDate;
									};

		var formatDate =			function(source, format) {
										if (global.isEmpty(source)) return "";

										if (global.typeOf(source) != "date")
											source = new Date(source);
		
										var ShowAMPM = ((format.match(/AMPM/gi) != null) || (format.match(/AP/gi) != null));
										var IsPM = (source.getHours() >= 12)
							
										var Months = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
										var iYear = source.getFullYear();
										var iMonth = source.getMonth();
										var iDay = source.getDate();
										var iHour = source.getHours();
										if (ShowAMPM && (iHour > 12)) iHour -= 12;
										if (ShowAMPM && (iHour <= 0)) iHour = 12;
										var iMin = source.getMinutes();
										var iSec = source.getSeconds();
										var imSec = source.getMilliseconds();
										
										format = format.replace(/mmm/g, Months[iMonth]);
										format = format.replace(/mm/g, (iMonth > 9 ? "" : "0") + (iMonth + 1));
										format = format.replace(/yyyy/g, iYear);
										format = format.replace(/yy/g, iYear.toString().substr(iYear.toString().length - 2));
										format = format.replace(/dd/g, (iDay > 9 ? "" : "0") + iDay);
										format = format.replace(/HH/g, (iHour > 9 ? "" : "0") + iHour);
										format = format.replace(/MM/g, (iMin > 9 ? "" : "0") + iMin);
										format = format.replace(/SSS/g, (imSec > 99 ? "" : "0") + (imSec > 9 ? "" : "0") + imSec);
										format = format.replace(/SS/g, (iSec > 9 ? "" : "0") + iSec);
										format = format.replace(/AMPM/gi, (IsPM ? "pm" : "am"));
										format = format.replace(/ap/gi, (IsPM ? "pm" : "am"));
										
										return format;
									}
									
		return {

//****************************************************************************************
//	String prototypes
//****************************************************************************************
			//	trims the white space from the left and right
			trim: 				function(source, left, right) {
									var iStart = 0;
									if ((left == null) || left)
										while ((iStart < this.length) && (this.charAt(iStart) == " ")) iStart++; 
			
									var iEnd = this.length - 1;
									if ((right == null) || right)
										while ((iEnd >= 0) && (this.charAt(iEnd) == " ")) iEnd--; 
				
									return source.substr(iStart, (iEnd - iStart + 1));
								},
					
			//	Returns the parsed value of a string
			parse:				function(source, type) {
									try {
										switch (type.toLowerCase()) {
											case "integer":
												return parseInt(source);
												break;
												
											case "number":
											case "float":
												return parseFloat(source);
												break;
									
											case "percent":
												return parseFloat(String(source).replace(/[%,]/g, ""));
												break;
									
											case "money":
												return parseFloat(String(source).replace(/[\$,]/g, ""));
												break;
									
											case "time":
											case "date":
											case "datetime":
												return parseDate(source);
												break;
									
											case "boolean":
												return ((source.toLowerCase() == "on") || (source.toLowerCase() == "true") || (source.toLowerCase() == "1"));
												break;
									
											default:
												return source.toString();
												break;
										}
									}
									catch (e) {
										return null;
									}
									return null;
								},
	
			//	Formats a value based on Type
			format:				function(source, type, option) {
									try {
										switch (type.toLowerCase()) {
											case "integer":
												return Number(source).toFixed(0);
												break;
												
											case "number":
											case "float":
												option = (option != null ? option : 2);
												return Number(source).toFixed(option);
												break;
												
											case "percent":
												option = (option != null ? option : 2);
												return Number(source/100).toFixed(option) + "%";
												break;
									
											case "money":
												var currency = Number(source).toFixed(2);
												var i = (currency.indexOf(".") - 3);
												while (i > 0) {
													currency = currency.slice(0, i) + "," + currency.slice(i);
													i = (currency.indexOf(",") - 3);
												}
												return "$" + currency;
												break;
									
											case "date": 
												return formatDate(source, (option != null ? option : "dd-mmm-yyyy"));
												break;
									
											case "time": 
												return formatDate(source, (option != null ? option : "HH:MM:SS"));
												break;
									
											case "datetime": 
												return formatDate(source, (option != null ? option : "dd-mmm-yyyy HH:MM"));
												break;
									
											case "boolean":
												return Boolean(source).toString();
												break;
		
											case "image":
												return source.replace(/\\/g, "/");
												break;

											default:
												return (source != null ? source.toString() : "");
												break;
										}
									}
									catch (e) {
										return null;
									}
									return null;
								}, 
								
								indirect:			function(source) {
														return	function() {
															if (arguments.length > 0)
																return eval("source." + arguments[1]);
															else
														return "";
													};
								},
	
			//	merges the strings in the arguments using conjunction.
			mergeString:		function(conjunction) {
									var returnString = "";
									if (arguments.length > 1) {
										for (var i = 1; i < arguments.length; i++)
											returnString += (!this.isEmpty(returnString) ? Conjunction : "") + (!this.isEmpty(arguments[i]) ? arguments[i] : "");
									}
									return returnString;
								},
	
			//	returns true if source is a valid type
			isValid: 			function(source, type) {
									return (this.parse(source, type) != null);
								},
	
			//	returns true if source is null or empty		
			isEmpty: 			function(source) {
									return ((source == null) || (source == ""));
								},
								
	//****************************************************************************************
	//	Object prototypes
	//****************************************************************************************
			//	merges the objects in the arguments together.
			mergeObject:		function() {
									var returnObject = null;
									if ((arguments.length > 0) && (global.typeOf(arguments[0]) == "object")) {
										returnObject = arguments[0];
										for (var i = 1; i < arguments.length; i++) {
											if (global.typeOf(arguments[i]) == "object") {
												for (var item in arguments[i])
													returnObject[item] = arguments[i][item];
											}
										}
									}
									return returnObject;
								},
								
			cloneObject:		function(source, noData) {
									noData = (noData ? noData : false);
						 			var newObj = new source.constructor;
									for (var item in source) {
										if ((typeof(source[Item]) == "object") && (source[Item] != null)) {
											switch (source[Item].constructor) {
												case Date:
													newObj[item] = (noData ? new Date() : source[Item]);
													break;
													
												default:
													newObj[Item] = this.cloneObject(source[item], noData);
													break;
											}
										} else {
											newObj[item] = (noData ? null : source[item]);
										}
									}
									return newObj;
								},
								
			typeOf:				function(source) {
									if (source == null) return "null";
									else if (source.constructor == Date) return "date";
									else if (source.constructor == Array) return "array";
									else if (source.constructor == Object) return "object";
									else if (source.constructor == Number) return "number";
									else if (source.constructor == String) return "string";
									else if (source.constructor == null) return typeof(source);
									else return typeof(source);
								},

	//****************************************************************************************
	//	Date prototypes
	//****************************************************************************************
			dateAdd:			function(date, delta, type) {
									var seconds = date.getSeconds();
									var minutes = date.getMinutes();
									var hours = date.getHours();
									var days = date.getDate();
									var months = date.getMonth();
									var years = date.getFullYear();

									switch (type) {
										case "Y":
											years += delta;
											break;
											
										case "M":
											months += delta
											break;
											
										case "D":
											days += delta
											break;
											
										case "m":
											minutes += delta
											break;
											
										case "s":
											seconds += delta
											break;
									}
									
									return new Date(years, months, days, hours, minutes, seconds);
								}
		};

	}();
							
//	End Global
//****************************************************************************************
	
//****************************************************************************************
//	Options object that creates an array from a string of options
//****************************************************************************************
	function Options(options) {

		this.Options = new Object();					//	Contains the array of parsed options
		this.Blocked = new Object();					//	Contains Keys that have been blocked
	
		//	parses a string into Options
		this.Parse =			function(Options, Clear) {
									if (Clear)
										this.Options = new Object();
										
									var Match;
									var regOption = /(\w*)\s*=\s*(['"]?)(.*?)\2/g;

									if (this != "") {
										var strElements = Options.replace(/\\'/g, "~");
									
										while ((Match = regOption.exec(strElements)) != null) {
											if (Match.length >= 4)
												this.Options[Match[1].toLowerCase()] = {'Key': Match[1], 'Value': Match[3].replace(/~/g, "'")};
										}
									}
								}

		//	returns true if Name is set
		this.IsSet =			function(Key) {
									return ((this.Options[Key.toLowerCase()] != null) && !this.Blocked[Key.toLowerCase()]);
								}
								
		//	sets the Key option to Value						
		this.Set =				function(Key, Value) {
									this.Options[Key.toLowerCase()] = {'Key': Key, 'Value': Value};
									this.Block(Key, false);
								}

		//	sets the Key to Value if not already set								
		this.SetIfNull =		function(Key, Value) {
									if (!this.IsSet(Key))
										this.Set(Key, Value);
								}
		
		//	block or unblocks a Key
		this.Block =			function(Key, Block) {
									this.Block[Key.toLowerCase()] = Block;
								}

		//	remove the Key altogether									
		this.Remove =			function(Key) {
									delete this.Options[Key.toLowerCase()];
									delete this.Block[Key.toLowerCase()];
								}
								
		//	returns the Value for Key if set otherwise default
		this.Get =				function(Key, Default, Format) {
									var Value = "";
									if (this.IsSet(Key))
										return global.parse(this.Options[Key.toLowerCase()].Value, (Format != null ? Format : "string"));
									else
										return global.parse(Default, (Format != null ? Format : "string"));
								}
					
		//	returns the Options as HTML attributes. NOTE that valid HTML options are those in lower case format.
		this.Attributes =		function(HTMLOnly) {
									HTMLOnly = (HTMLOnly != null ? HTMLOnly : true);
									var reUpperCase = /[A-Z]/;
									var Attributes = new Object();
									for (Key in this.Options) {
										if ((this.Options.hasOwnProperty(Key)) && this.IsSet(Key) && (!HTMLOnly || !reUpperCase.test(Key)))
											strHTML += (strHTML != "" ? " " : "") + this.Options[Key].Key + "='" + this.Options[Key].Value + "'";
									}
									return strHTML;
								}


		if (options != null)
			this.Parse(options, true);
	}
//	End Options
//****************************************************************************************
	
//****************************************************************************************
//	HTML object for rendering HTML
//****************************************************************************************

	var HTML = function() {
	
		var HTMLDefinition = 
			{ 
				generic:	{	Tag: "<div id='[ID]' [ATTRIBUTES]>[VALUE]</div>",
								Attributes: [ 	"class", "style", "title", "accesskey", "tabindex", 
												"onchange", "onsubmit", "onreset", "onselect", "onblur", "onfocus", 
												"onkeydown", "onkeypress", "onkeyup", 
												"onclick", "ondblclick", "onmousedown", "onmousemove", "onmouseout", "onmouseover", "onmouseup"],
								Value: "",
								Data: "innerHTML"
							},
							
				image: 		{	Tag: "<img id='[ID]' src='[VALUE]' [ATTRIBUTES] />",
								Attributes: ["alt"],
								Value: "src",
								Data: "src"
							},
							
				text: 		{	Tag: "<input id='[ID]' type='text' value='[VALUE]' [ATTRIBUTES] />", 
								Attributes: [],
								Value: "value",
								Data: "value"
							},
							
				password: 	{	Tag: "<input id='[ID]' type='password' value='[VALUE]' [ATTRIBUTES] />", 
								Attributes: [],
								Value: "value",
								Data: "value"
							},
							
				hidden: 	{	Tag: "<input id='[ID]' type='hidden' value='[VALUE]' [ATTRIBUTES] />", 
								Attributes: [],
								Value: "value",
								Data: "value"
							},
							
				textarea: 	{	Tag: "<textarea id='[ID]' [ATTRIBUTES]>[VALUE]</textarea>",
					 			Attributes: ["rows"],
								Value: "text",
								Data: "innerHTML"
							},
							
				list: 		{	Tag: "<select id='[ID]' [ATTRIBUTES]>[VALUE]</select>",
								Attributes: ["size", "multiple"],
								Value: "options",
								Data: "value"
							},
							
				link: 		{	Tag: "<a id='[ID]' [ATTRIBUTES]>[VALUE]</a>",
								Attributes: ["href", "target"],
								Value: "text",
								Data: "innerHTML"
							},

				checkbox: 	{	Tag: "<input id='[ID]' type='checkbox' [VALUE] [ATTRIBUTES] />",
							 	Attributes: [],
								Value: "selected",
								Data: "selected"
							},
							
				button: 	{	Tag: "<button id='[ID]' [ATTRIBUTES]>[VALUE]</button>",
					 			Attributes: ["onclick"],
								Value: "text",
								Data: "innerHTML"
							},

				file: 		{	Tag: "<div style='text-align: center'><button id='[ID]' [ATTRIBUTES]>[VALUE]</button></div><div id='[ID].Display' class='display-file-result'></div>",
				 				Attributes: [],
								Value: "text",
								Data: "value"
							},

				span: 		{	Tag: "<span id='[ID]' [ATTRIBUTES]>[VALUE]</span>",
								Attributes: [],
								Value: "text",
								Data: "innerHTML"
							}
			};
			
		var Fields = 
			{
				image: 		{edit: "image",		view: "image"},
				hidden: 	{edit: "hidden",	view: "hidden"},
				text: 		{edit: "text",		view: "span"},
				password:	{edit: "password",	view: "none"},
				textarea: 	{edit: "textarea",	view: "span"},
				date: 		{edit: "text",		view: "span"},
				datetime:	{edit: "text",		view: "span"},
				time: 		{edit: "text",		view: "span"},
				number:		{edit: "text",		view: "span"},
				float: 		{edit: "text",		view: "span"},
				integer:	{edit: "text",		view: "span"},
				list: 		{edit: "list",		view: "span"},
				link: 		{edit: "link",		view: "link"},
				boolean: 	{edit: "checkbox",	view: "span"},
				button: 	{edit: "button",	view: "button"},
				file: 		{edit: "file",		view: "file"}
			}

		return {
	
			Render: 			function(name, type, edit, options) {
									type = type.toLowerCase();
									
									switch (type.toLowerCase()) {
										case "email":
											options["href"] = "email:" + options["href"];
											type = "link";
											break;
									}
									
									var fieldType = (Fields[type] != null ? (edit ? Fields[type].edit : Fields[type].view) : "none");
									if ((fieldType == "none")) 
										return "";

									var htmlType = HTMLDefinition[(edit ? Fields[type].edit : Fields[type].view)];
									var result = htmlType.Tag;

									if (typeof(options) == "string")
										options = new Options(options);
									
									if (htmlType != null) {
										var attributes = 'name="' + name + '"';

										if ((options != null) && (options instanceof Options)) {
											var allAttributes = eval("({'" + HTMLDefinition.generic.Attributes.concat(htmlType.Attributes).join("': true, '") + "':true})");
											for (var Key in allAttributes) {
												if (allAttributes.hasOwnProperty(Key) && (allAttributes[Key.toLowerCase()] != null) && options.IsSet(Key))
													attributes += ' ' + Key.toLowerCase() + '="' + options.Get(Key) + '"';
											}

											if (options.IsSet(htmlType.Value))
												result = result.replace("[VALUE]", options.Get(htmlType.Value));
										}
										
										result = result.replace("[ATTRIBUTES]", attributes);
									}
									return result;
								},
			
			Extract:			function(element, type, edit) {
									type = type.toLowerCase();
									var htmlType = HTMLDefinition[(edit ? Fields[type].edit : Fields[type].view)];
									return element[htmlType.Data]
								},
								
			reField: 			/\[([^\]]*?)\]/gim

		}
	}()
	
//	End HTML
//****************************************************************************************
	
//****************************************************************************************
//	HTML object for rendering HTML
//****************************************************************************************
	var message = function() {

		return {
	
			debugWindow:		null,
			debugOn:			false,
			messages:			[],
			
			setDebug:			function(on) {
									this.debugOn = on;
									
									if (this.debugOn) {
										if ((this.debugWindow == null) || this.debugWindow.closed)
											this.debugWindow = window.open("", "debug");
									} else {
										if ((this.debugWindow != null) && !this.debugWindow.closed) {
											this.debugWindow.close();
											this.debugWindow = null;
										}
									}
								},

			raise:				function(system, type, message, debugMessage, throwError) {
								
									this.messages.push({ 'system': system, 'type': type, 'message': message, 'debugMessage': debugMessage, 'throwError': throwError })
								
									if (this.debugOn && (debugMessage != null)) {
										if ((this.debugWindow == null) || this.debugWindow.closed)
											this.debugWindow = window.open("", "debug");

										this.debugWindow.document.write("<b>" + type + "</b><br><br>System: " + system + "<br><br>Message: " + message.replace(/\r/gim, "").replace(/\n/gim, "<br>") + "<br><br>" + debugMessage.replace(/\r/gim, "").replace(/\n/gim, "<br>"));
									}
								
									if (throwError)
										throw system + " " + type + "\n" + message;
									else
										alert(system + " " + type + "\n" + message);
								},

			clear:				function() {
									if (this.debugOn) {
										if ((this.debugWindow != null) && !this.debugWindow.closed) {
											this.debugWindow.close();
											this.debugWindow = null;
										}
									}
									
									this.messages = new Array();
								}
		}
	}();
	
//	End Message
//****************************************************************************************
	

