/**
 * Anobis Network JavaScript Library
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 12:25:12 (built: 20060906130921)
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *	- v1.0.1 - 2005-06-27 - 06:32:14 by Laroche Fabrice
 *		The obj.attachWindowEvent and the obj.detachWindowEvent
 *		methods were added to the object method.
 *
 *	- v1.0.2 - 2005-07-04 - 11:55:35 by Laroche Fabrice
 *		The obj.interval method was added to the object method.
 *
 *	- v1.0.3 - 2005-07-21 - 08:45:23 by Laroche Fabrice
 *		Removed the attach, detach window and document events, now
 *		they are part of the global functions.
 *
 *	- v1.0.4 - 2009-06-06 - 15:16:58 by Laroche Fabrice
 *		Added support for the new Chrome browser
 *
 * Comments:
 */

/**
 * Anobis Network System Namespaces
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 11:44:45
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

if (!window.ANet) {
	var ANet = function(a, b) {
		return ANet.dispatch(a, b)
	};

	ANet.toString = function() {
		return "ANet JS Controls 2.0";
	};
};

if (!ANet.System)	  		{ ANet.System				= {}};
if (!ANet.HTML)	  			{ ANet.HTML					= {}};
if (!ANet.Templates)		{ ANet.Templates 		= {}};
if (!ANet.Controllers)	{ ANet.Controllers	= {}};
if (!ANet.Controls) 		{ ANet.Controls			= {}};
if (!ANet.Formats)			{ ANet.Formats 			= {}};
if (!ANet.HTTP)					{ ANet.HTTP	 				= {}};
if (!ANet.CSV)					{ ANet.CSV	 				= {}};
if (!ANet.XML)					{ ANet.XML		 			= {}};

if (!ANet.Popup)				{ ANet.Popup	 			= {}};
/**
 * Anobis Network Common Browser Extensions
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-11-18 - 12:46:23
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 *
 */

(function() {
	ANet.all = { id: 0 };
	ANet.docs = [document];

	/**
	 * Takes each element in an array and pass it to
	 * an handler. This function gets used to attach
	 * and detach all the control's mouse events
	 *
	 * @param array (Array) Array with elements
	 * @param handler (Function) Handler to handle the element
	 */

	ANet.forEach = function(array, handler) {
		var i, custom = {};

		for (i in array) {
			if (!custom[i]) {
				handler(i, array[i])
			}
		}
	};

	/**
	 * Returns a document element
	 *
	 * @param id (String) Element ID
	 * @return element (Object)
	 */

	ANet.element = function(id) {
		var i, e, docs = ANet.docs;

		for (i = 0; i < docs.length; i++) {
			e = docs[i].getElementById(id);
			if (e) { return e }
		}
	};

	/**
	 * Returns an object
	 *
	 * @param id (String) Object id
	 */

	ANet.object = function(id) {
		var parts = id.split("-");
		var tag = parts[0];
		var obj = ANet.all[tag];
		var target = obj;

		for (var i = 1; i < parts.length; i++) {
			if (obj["_" + parts[i] + "Content"]) {
				for (var j = i;	j < parts.length;	j++) {
					target = target.getContent(parts[j])
				}

				break;
			} else if (parts[i + 1] && parts[i + 1].match(/^(\d+)$/)) {
				if (parts[i + 2] && parts[i + 2].match(/^(\d+)$/)) {
					if (parts[i + 3] && parts[i + 3].match(/^(\d+)$/)) {
						obj = obj.getTemplate(parts[i], parts[i + 1], parts[i + 2], parts[i + 3]);
						i += 3
					} else {
						obj = obj.getTemplate(parts[i], parts[i + 1], parts[i + 2]);
						i += 2
					}
				} else {
					obj = obj.getTemplate(parts[i], parts[i + 1]);
					i += 1
				}
			} else {
				obj = obj.getTemplate(parts[i])
			}

			target = obj;
		}

		return target;
	};

	var events = { "DOMFocusIn": "focus" };

	/**
	 * Executes the events set to the object
	 */

	ANet.dispatch = function(element, event) {
		var type = "_on" + (events[event.type] || event.type) + "Event";
		var target = ANet.object(element.id);
		var obj = target;

		while (obj._parent) { obj = obj._parent }
		target[type].call(obj, event);
	};

	ANet.paint = function(element) {
		var obj = ANet.object(element.id);

		while (obj._parent) { obj = obj._parent }

		if (obj && obj.raiseEvent && !obj.$paint) {
			obj.$paint = true;
			obj.raiseEvent("onPaint");
		}

		window.setTimeout(function() {
			element.style.removeExpression("visibility");
			element.style.display = "none";

			if (obj && obj.$paint) {
				obj.$paint = false;
			}
		}, 0);

		return "hidden";
	};

	ANet.camelCase = function() {
		var i, s = arguments[0];

		for (i = 1; i < arguments.length; i++) {
			s += arguments[i].substr(0, 1).toUpperCase() + arguments[i].substr(1);
		}

		return s;
	};

	ANet.textPattern = /(\"|&|<|>)/gm;
	ANet.textTable   = {"\"":"&quot;", "&":"&amp;", "<":"&lt;", ">":"&gt;"};
	ANet.textReplace = function(c) { return ANet.textTable[c] || "" };

	ANet.htmlPattern = /(&quot;|&amp;|&lt;|&gt|<[^<>]*>)/gm;
	ANet.htmlTable   = {"&quot;":"\"", "&amp;":"&", "&lt;":"<", "&gt;":">"};
	ANet.htmlReplace = function(e) { return ANet.htmlTable[e] || "" };

	ANet.valueToText = function(v) { return v ? String(v).replace(ANet.textPattern, ANet.textReplace): "" };
	ANet.textToValue = function(t) { return t ? String(t).replace(ANet.htmlPattern, ANet.htmlReplace): "" };
})();
/**
 * Anobis Network Browser Detection
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-11-18 - 12:55:54
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 *
 */

(function() {
	/**
	 * Identify the client's system
	 */

	ANet.browser = "";

	if (window.opera) { ANet.browser = "opera" }
	else if (window.__defineGetter__) { ANet.browser = "gecko" }
	else if (navigator.userAgent.match("MSIE")) { ANet.browser = "ie" }
	else if (navigator.userAgent.match("KHTML")) { ANet.browser = "khtml" }
	else if (navigator.userAgent.match("Safari")) { ANet.browser = "safari" }
	else if (navigator.userAgent.match("Konqueror")) { ANet.browser = "khtml" }
		
	if (navigator.userAgent.match("Chrome")) { ANet.browser = "chrome" }

	if (ANet.browser) { ANet[ANet.browser] = true }

	ANet.os = "";

	if (!navigator.userAgent.match("Windows")) { ANet.unix = true }
	if (navigator.userAgent.match("Mac OS")) { ANet.os = "mac" }
	if (navigator.userAgent.match("Linux")) { ANet.os = "linux" }

	ANet.strict = (document.compatMode && document.compatMode.match("CSS")) || ANet.browser == "safari";

	var htmlc = "";

	if (ANet.strict)	{ htmlc += " anet-strict" }
	if (ANet.browser)	{ htmlc += " anet-" + ANet.browser }
	if (ANet.unix)		{ htmlc += " anet-unix" }
	if (ANet.os)			{ htmlc += " anet-" + ANet.os }

	document.getElementsByTagName("html")[0].className += htmlc;

	if (ANet.strict) {
		ANet.dx = 8;
		ANet.dy = 4;
	}	else {
		ANet.dx = 0;
		ANet.dy = 0;
	}
})();
/**
 * Anobis Network IE Extensions
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-21 - 07:59:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 *
 */

(function() {
	if (ANet.ie) {
		/**
		 * Sets an event handler to the window, document or element
		 *
		 * NOTE: Try not to use the wrapper method as this one increase
		 * the memory usage on ever reload of the page.
		 *
		 * @param	element (Object)
		 * @param	name (String) Event name
		 * @param handler (Function) Event handler
		 */

		ANet.attachEvent = function(element, name, handler) {
			return element.attachEvent(name, handler);
		};

		/**
		 * Removes an event handler from the window, document or element
		 *
		 * @param	element (Object)
		 * @param	name (String) Event name
		 * @param handler (Function) Event handler
		 */

		ANet.detachEvent = function(element, name, handler) {
			return element.detachEvent(name, handler)
		};

		/**
		 * Returns the object that fired the event
		 *
		 * @param event (Event)
		 * @return element (Object)
		 */

		ANet.srcElement = function(event) {
			return event.srcElement
		};

		/**
		 * Returns the object from which activation or the mouse
		 * pointer is exiting during the event
		 *
		 * @param event (Event)
		 * @return element (Object)
		 */

		ANet.fromElement = function(event) {
			return event.fromElement
		};

		/**
		 * Returns the reference to the object toward which the user
		 * is moving the mouse pointer
		 *
		 * @param event (Event)
		 * @return element (Object)
		 */

		ANet.toElement = function(event) {
			return event.toElement
		};

		ANet.setReturnValue = function(event, value) {
			var undef;

			if (event != undef) { event.returnValue = value }
		};

		ANet.setCapture = function(element) {
			return element.setCapture()
		};

		ANet.releaseCapture = function(element) {
			return element.releaseCapture()
		};

		ANet.addRule = function(stylesheet, selector, rule, index) {
			var i = index || -1;
			return stylesheet.addRule(selector, rule, i)
		};

		ANet.removeRule = function(stylesheet, index) {
			var i = index || stylesheet.rules.length - 1;
			stylesheet.removeRule(i);
		};

		ANet.getRules = function(stylesheet) {
			return stylesheet.rules
		};

		ANet.setOuterHTML = function(element, html) {
			element.outerHTML = html;
		};

		ANet.createXMLHttpRequest = function() {
			return new ActiveXObject("MSXML2.XMLHTTP");
		};

		ANet.getLeft = function(element) {
			return element.getBoundingClientRect().left;
		};

		ANet.getTop = function(element) {
			return element.getBoundingClientRect().top;
		};

		ANet.getPageHeight = function(document) {
			var y = 0;

			if (typeof document.height != 'undefined') {
				y = document.height;
			} else if (document.compatMode && document.compatMode != 'BackCompat') {
				y = document.documentElement.scrollHeight;
			} else if (document.body && typeof document.body.scrollHeight != 'undefined') {
				y = document.body.scrollHeight;
			}

			return y;
		};

		ANet.getCursorPos = function(event) {
			return {
				x: event.x,
				y: event.y
			}
		};

		ANet.setScrollTop = function(element, y) {
			element.scrollTop = y;
		};

		ANet.setScrollLeft = function(element, x) {
			element.scrollLeft = x;
		};

		ANet.scrollLeft = function(element) {
			return element.scrollLeft;
		};

		ANet.scrollTop = function(element) {
			return element.scrollTop;
		};

		ANet.getRectangle = function(element) {
			var x = y = 0;

			x = ANet.getLeft(element);
			y = ANet.getTop(element);

			return {
				top: y,
				right: x + element.offsetWidth,
				bottom: y + element.offsetHeight,
				left: x
			}
		};
	}
})();
/**
 * Anobis Network Gecko Extensions
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-21 - 07:59:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 *
 */

(function() {
	if (ANet.gecko) {
		var capture;

		ANet.attachEvent = function(target, name, handler) {
			if (capture) {
				handler[name] = function(event) { return handler.call(target, event) };
				window.addEventListener(name.replace(/^on/, ""), handler[name], true);
			} else {
				target.addEventListener(name.replace(/^on/, ""), handler, false);
			}
		};

		ANet.detachEvent = function(target, name, handler) {
			if (capture) {
				window.removeEventListener(name.replace(/^on/, ""), handler[name], true);
				handler[name] = null;
			} else {
				target.removeEventListener(name.replace(/^on/, ""), handler, false);
			}
		};

		ANet.srcElement = function(event) {
			try {
				return (event.target && event.target.nodeType == 3) ? event.target.parentNode: event.target
			} catch(e) {
				return event.target;
			}
		};

		ANet.fromElement = function(event) {
			try {
				if (event.type == "mouseover") {
					return (event.relatedTarget && event.relatedTarget.nodeType == 3) ? event.relatedTarget.parentNode: event.relatedTarget
				} else {
					return null;
				}
			} catch(e) {
				return event.relatedTarget;
			}
		};

		ANet.toElement = function(event) {
			try {
				if (event.type == "mouseout") {
					return (event.relatedTarget && event.relatedTarget.nodeType == 3) ? event.relatedTarget.parentNode: event.relatedTarget
				} else {
					return null;
				}
			} catch(e) {
				return event.relatedTarget;
			}
		};

		ANet.setReturnValue = function(event, value) {
			var undef;

			if (event != undef) { event.preventDefault() }
		};

		ANet.setCapture = function(element) {
			capture = element;
		};

		ANet.releaseCapture = function(element) {
			capture = null;
		};

		ANet.addRule = function(stylesheet, selector, rule, index) {
			var i = index || stylesheet.cssRules.length;

			stylesheet.insertRule(selector + " { " + rule + " }", i);
			stylesheet.cssRules[i].style.cssText = rule
		};

		ANet.removeRule = function(stylesheet, index) {
			var i = index || stylesheet.cssRules.length - 1;
			stylesheet.deleteRule(i);
		};

		ANet.getRules = function(stylesheet) {
			return stylesheet.cssRules
		};

		ANet.setOuterHTML = function(element, html) {
		   var range = element.ownerDocument.createRange();
		   range.setStartBefore(element);

		   var fragment = range.createContextualFragment(html);
		   element.parentNode.replaceChild(fragment, element);
		};

		ANet.createXMLHttpRequest = function() {
			return new XMLHttpRequest;
		};

		ANet.getLeft = function(element) {
			var doc = document.getBoxObjectFor(document.body);
			return document.getBoxObjectFor(element).screenX - doc.screenX + doc.x;
		};

		ANet.getTop = function(element) {
			var doc = document.getBoxObjectFor(document.body);
			return document.getBoxObjectFor(element).screenY - doc.screenY + doc.y;
		};

		ANet.getPageHeight = function(document) {
			var y = 0;

			if (typeof document.height != 'undefined') {
				y = document.height;
			} else if (document.compatMode && document.compatMode != 'BackCompat') {
				y = document.documentElement.scrollHeight;
			} else if (document.body && typeof document.body.scrollHeight != 'undefined') {
				y = document.body.scrollHeight;
			}

			return y;
		};

		ANet.getCursorPos = function(event) {
			return {
				x: event.pageX,
				y: event.pageY
			}
		};

		ANet.setScrollTop = function(element, y) {
			element.scrollTop = y;
		};

		ANet.setScrollLeft = function(element, x) {
			element.scrollLeft = x;
		};

		ANet.scrollTop = function(element) {
			return element.pageYOffset;
		};

		ANet.scrollLeft = function(element) {
			return element.pageXOffset;
		};

		ANet.getRectangle = function(element) {
			var x = y = 0;

			x = ANet.getLeft(element);
			y = ANet.getTop(element);

			return {
				top: y,
				right: x + element.offsetWidth,
				bottom: y + element.offsetHeight,
				left: x
			}
		};
	}
})();

/**
 * Anobis Network Chrome Extensions
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2009-06-06 - 15:18:54
 * Copyright (C) 2009, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 *
 */

(function() {
	if (ANet.chrome) {
		var capture;

		ANet.attachEvent = function(target, name, handler) {
			if (capture) {
				handler[name] = function(event) { return handler.call(target, event) };
				window.addEventListener(name.replace(/^on/, ""), handler[name], true);
			} else {
				target.addEventListener(name.replace(/^on/, ""), handler, false);
			}
		};

		ANet.detachEvent = function(target, name, handler) {
			if (capture) {
				window.removeEventListener(name.replace(/^on/, ""), handler[name], true);
				handler[name] = null;
			} else {
				target.removeEventListener(name.replace(/^on/, ""), handler, false);
			}
		};

		ANet.srcElement = function(event) {
			try {
				return (event.target && event.target.nodeType == 3) ? event.target.parentNode: event.target
			} catch(e) {
				return event.target;
			}
		};

		ANet.fromElement = function(event) {
			try {
				if (event.type == "mouseover") {
					return (event.relatedTarget && event.relatedTarget.nodeType == 3) ? event.relatedTarget.parentNode: event.relatedTarget
				} else {
					return null;
				}
			} catch(e) {
				return event.relatedTarget;
			}
		};

		ANet.toElement = function(event) {
			try {
				if (event.type == "mouseout") {
					return (event.relatedTarget && event.relatedTarget.nodeType == 3) ? event.relatedTarget.parentNode: event.relatedTarget
				} else {
					return null;
				}
			} catch(e) {
				return event.relatedTarget;
			}
		};

		ANet.setReturnValue = function(event, value) {
			var undef;

			if (event != undef) { event.preventDefault() }
		};

		ANet.setCapture = function(element) {
			capture = element;
		};

		ANet.releaseCapture = function(element) {
			capture = null;
		};

		ANet.addRule = function(stylesheet, selector, rule, index) {
			var i = index || stylesheet.cssRules.length;

			stylesheet.insertRule(selector + " { " + rule + " }", i);
			stylesheet.cssRules[i].style.cssText = rule
		};

		ANet.removeRule = function(stylesheet, index) {
			var i = index || stylesheet.cssRules.length - 1;
			stylesheet.deleteRule(i);
		};

		ANet.getRules = function(stylesheet) {
			return stylesheet.cssRules
		};

		ANet.setOuterHTML = function(element, html) {
		   var range = element.ownerDocument.createRange();
		   range.setStartBefore(element);

		   var fragment = range.createContextualFragment(html);
		   element.parentNode.replaceChild(fragment, element);
		};

		ANet.createXMLHttpRequest = function() {
			return new XMLHttpRequest;
		};

		ANet.getLeft = function(element) {
			return element.getBoundingClientRect().left;
		};

		ANet.getTop = function(element) {
			return element.getBoundingClientRect().top;
		};

		ANet.getPageHeight = function(document) {
			var y = 0;

			if (typeof document.height != 'undefined') {
				y = document.height;
			} else if (document.compatMode && document.compatMode != 'BackCompat') {
				y = document.documentElement.scrollHeight;
			} else if (document.body && typeof document.body.scrollHeight != 'undefined') {
				y = document.body.scrollHeight;
			}

			return y;
		};

		ANet.getCursorPos = function(event) {
			return {
				x: event.pageX,
				y: event.pageY
			}
		};

		ANet.setScrollTop = function(element, y) {
			element.scrollTop = y;
		};

		ANet.setScrollLeft = function(element, x) {
			element.scrollLeft = x;
		};

		ANet.scrollTop = function(element) {
			return element.pageYOffset;
		};

		ANet.scrollLeft = function(element) {
			return element.pageXOffset;
		};

		ANet.getRectangle = function(element) {
			var x = y = 0;

			x = ANet.getLeft(element);
			y = ANet.getTop(element);

			return {
				top: y,
				right: x + element.offsetWidth,
				bottom: y + element.offsetHeight,
				left: x
			}
		};
	}
})();
/**
 * Anobis Network Opera Extensions
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-11-18 - 13:16:34
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 *
 */

(function() {
	if (ANet.safari) {
		var capture;

		ANet.attachEvent = function(target, name, handler) {
			if (capture) {
				handler[name] = function(event) { return handler.call(target, event) };
				window.addEventListener(name.replace(/^on/, ""), handler[name], true);
			} else {
				target.addEventListener(name.replace(/^on/, ""), handler, false);
			}
		};

		ANet.detachEvent = function(target, name, handler) {
			if (capture) {
				window.removeEventListener(name.replace(/^on/, ""), handler[name], true);
				handler[name] = null;
			} else {
				target.removeEventListener(name.replace(/^on/, ""), handler, false);
			}
		};

		ANet.srcElement = function(event) {
			try {
				return (event.target && event.target.nodeType == 3) ? event.target.parentNode: event.target
			} catch(e) {
				return event.target;
			}
		};

		ANet.fromElement = function(event) {
			try {
				if (event.type == "mouseover") {
					return (event.relatedTarget && event.relatedTarget.nodeType == 3) ? event.relatedTarget.parentNode: event.relatedTarget
				} else {
					return null;
				}
			} catch(e) {
				return event.relatedTarget;
			}
		};

		ANet.toElement = function(event) {
			try {
				if (event.type == "mouseout") {
					return (event.relatedTarget && event.relatedTarget.nodeType == 3) ? event.relatedTarget.parentNode: event.relatedTarget
				} else {
					return null;
				}
			} catch(e) {
				return event.relatedTarget;
			}
		};

		ANet.setReturnValue = function(event, value) {
			var undef;

			if (event != undef) { event.preventDefault() }
		};

		ANet.setCapture = function(element) {
			capture = element;
		};

		ANet.releaseCapture = function(element) {
			capture = null;
		};

		ANet.addRule = function(stylesheet, selector, rule, index) {
			var i = index || stylesheet.cssRules.length;

			stylesheet.insertRule(selector + " { " + rule + " }", i);
			stylesheet.cssRules[i].style.cssText = rule
		};

		ANet.removeRule = function(stylesheet, index) {
			var i = index || stylesheet.cssRules.length - 1;
			stylesheet.deleteRule(i);
		};

		ANet.getRules = function(stylesheet) {
			return stylesheet.cssRules
		};

		ANet.setOuterHTML = function(element, html) {
			element.outerHTML = html;
		};

		ANet.createXMLHttpRequest = function() {
			return new XMLHttpRequest;
		};

		ANet.getLeft = function(element) {
			return getRectangle(element).left;
		};

		ANet.getTop = function(element) {
			return getRectangle(element).top;
		};

		ANet.getPageHeight = function(document) {
			var y = 0;

			if (typeof document.height != 'undefined') {
				y = document.height;
			} else if (document.compatMode && document.compatMode != 'BackCompat') {
				y = document.documentElement.scrollHeight;
			} else if (document.body && typeof document.body.scrollHeight != 'undefined') {
				y = document.body.scrollHeight;
			}

			return y;
		};

		ANet.getCursorPos = function(event) {
			return {
				x: event.pageX,
				y: event.pageY
			}
		};

		ANet.setScrollTop = function(element, y) {
			element.scrollTop = y;
		};

		ANet.setScrollLeft = function(element, x) {
			element.scrollLeft = x;
		};

		ANet.scrollTop = function(element) {
			return element.pageYOffset;
		};

		ANet.scrollLeft = function(element) {
			return element.pageXOffset;
		};

		function getRectangle(e) {
			var t = e, x = 0, y = 0;

			function getPos(el) {
				if (!el) { return {x: 0, y: 0}; }

				if (el == document.body.parentNode) {
					return {x: 0, y: 0};
				}

				if (el == document.body) {
					return {x: el.offsetLeft, y: el.offsetTop};
				}

				var p = el.offsetParent;
				var pp = getPos(p);

				return {
					x: el.offsetLeft + pp.x,
					y: el.offsetTop + pp.y
				};
			}

			var pp = getPos(e);

			return {
				left: pp.x,
				right: pp.x + e.offsetWidth,
				top: pp.y,
				bottom: pp.y + e.offsetHeight
			};
		}
	}
})();
/**
 * Anobis Network Opera Extensions
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-11-18 - 13:16:34
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 *
 */

(function() {
	if (ANet.opera) {
		ANet.attachEvent = function(target, name, handler) {
			return target.addEventListener(name.replace(/^on/, ""), handler, false)
		};

		ANet.detachEvent = function(target, name, handler) {
			return target.removeEventListener(name.replace(/^on/, ""), handler, false)
		};

		ANet.srcElement = function(event) {
			try {
				return (event.target && event.target.nodeType == 3) ? event.target.parentNode: event.target
			} catch(e) {
				return event.target;
			}
		};

		ANet.fromElement = function(event) {
			try {
				if (event.type == "mouseover") {
					return (event.relatedTarget && event.relatedTarget.nodeType == 3) ? event.relatedTarget.parentNode: event.relatedTarget
				} else {
					return null;
				}
			} catch(e) {
				return event.relatedTarget;
			}
		};

		ANet.toElement = function(event) {
			try {
				if (event.type == "mouseout") {
					return (event.relatedTarget && event.relatedTarget.nodeType == 3) ? event.relatedTarget.parentNode: event.relatedTarget
				} else {
					return null;
				}
			} catch(e) {
				return event.relatedTarget;
			}
		};

		ANet.setReturnValue = function(event, value) {
			var undef;

			if (event != undef) { event.preventDefault() }
		};

		ANet.setCapture = function(element) {
			return
		};

		ANet.releaseCapture = function(element) {
			return
		};

		ANet.addRule = function(stylesheet, selector, rule, index) {
			var i = index || stylesheet.cssRules.length;

			stylesheet.insertRule(selector + " { " + rule + " }", i);
			stylesheet.cssRules[i].style.cssText = rule
		};

		ANet.removeRule = function(stylesheet, index) {
			var i = index || stylesheet.cssRules.length - 1;
			stylesheet.deleteRule(i);
		};

		ANet.getRules = function(stylesheet) {
			return stylesheet.cssRules
		};

		ANet.setOuterHTML = function(element, html) {
			element.outerHTML = html;
		};

		ANet.createXMLHttpRequest = function() {
			return new XMLHttpRequest;
		};

		ANet.getLeft = function(element) {
			return getRectangle(element).left;
		};

		ANet.getTop = function(element) {
			return getRectangle(element).top;
		};

		ANet.getPageHeight = function(document) {
			var y = 0;

			if (typeof document.height != 'undefined') {
				y = document.height;
			} else if (document.compatMode && document.compatMode != 'BackCompat') {
				y = document.documentElement.scrollHeight;
			} else if (document.body && typeof document.body.scrollHeight != 'undefined') {
				y = document.body.scrollHeight;
			}

			return y;
		};

		ANet.scrollTop = function(element) {
			return element.pageYOffset;
		};

		ANet.scrollLeft = function(element) {
			return element.pageXOffset;
		};

		function getRectangle(e) {
			var t = e, x = 0, y = 0;

			function getPos(el) {
				if (!el) { return {x: 0, y: 0}; }

				if (el == document.body.parentNode) {
					return {x: 0, y: 0};
				}

				if (el == document.body) {
					return {x: el.offsetLeft, y: el.offsetTop};
				}

				var p = el.offsetParent;
				var pp = getPos(p);

				return {
					x: el.offsetLeft + pp.x,
					y: el.offsetTop + pp.y
				};
			}

			var pp = getPos(e);

			return {
				left: pp.x,
				right: pp.x + parseInt(getComputedStyle(e, null).width),
				top: pp.y,
				bottom: pp.y + parseInt(getComputedStyle(e, null).height)
			};
		}
	}
})();
/**
 * Anobis Network JS Object Class
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 12:25:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *	- v1.0.1 - 2005-06-27 - 06:32:14 by Laroche Fabrice
 *		The obj.attachWindowEvent and the obj.detachWindowEvent
 *		methods were added to the object method.
 *
 *	- v1.0.2 - 2005-07-04 - 11:55:35 by Laroche Fabrice
 *		The obj.interval method was added to the object method.
 *
 *	- v1.0.3 - 2005-07-21 - 08:45:23 by Laroche Fabrice
 *		Removed the attach, detach window and document events, now
 *		they are part of the global functions.
 *
 * Comments:
 */

ANet.System.Object = function() {};

/**
 * var ANet is an object, the root of the hierarchy. ANet.System is
 * also an object (System is a property of ANet) ANet.System.Object
 * is a function (Object is a method of System). To be precise, it is
 * not just a function, it is a constructor function, which is used to
 * create objects of type ANet.System.Object (like this: var obj = new
 * ANet.System.Object;).
 */

ANet.System.Object.subclass = function() {
	/**
	 * We are creating a method 'subclass' of the ANet.System.Object.
	 * Again, ANet.System.Object is a constructor function, which
	 * represents a class, not an object instance. It is OK to create a
	 * method or a property of a function because functions themselves
	 * behave like objects.
	 */

	var create = function(cls) {
		cls.created = true;

		if (cls.superclass && !cls.superclass.created) {
			create(cls.superclass);
		}

		cls.create();
	};

	var constructor = function() {
		if (constructor.defer) { return }
		if (!constructor.created) { create(constructor) }

		if (this.init) { this.init(arguments) }
	};

	/**
	 * Our 'subclass' method should return a constructor function, which
	 * we create here. Because the constructor is created automatically,
	 * the actual object initialization code should be somewhere else,
	 * i.e. in a special 'init' method. So each object constructor just
	 * calls 'init' method of a newly created object. Here 'this' keyword
	 * refers to the newly created object, when subclass constructor runs.
	 */

	for (var i in this) { constructor[i] = this[i] }

	/**
	 * This code copies all properties and methods from the base class
	 * constructor to the derived class constructor. Note, it is NOT object
	 * properties, it is constructor function properties. Keyword 'this'
	 * refers to the base class constructor, i.e. ANet.System.Object
	 * function.
	 */

	this.defer = true;

	constructor.prototype = new this();

	this.defer = false;

	/**
	 * The 'prototype' property of the constructor of the derived class
	 * should point to the base class object instance. Here we create a new
	 * instance of the base class by calling the base class constructor
	 * function with the keyword 'new'. Again, 'this' refers to the base
	 * class constructor, i.e. ANet.System.Object function.
	 */

	constructor.prototype.constructor = constructor;
	constructor.superclass = this;

	/**
	 * We also create special 'superclass' property, which provides quick
	 * access to the base class constructor from within the derived class.
	 * It is very useful when you want to overload a method in the derived
	 * class but still be able to call the base class implementation of the
	 * same method.
	 */

	constructor.created = false;
	return constructor;
};

ANet.System.Object.handle = function(error) {
	throw(error);
};

ANet.System.Object.create = function() {
	var obj = this.prototype;

	/**
	 * Creates an object clone.
	 *
	 * The clone function creates a fast copy of the object. Instead of
	 * physically copying each property and method of the source object -
	 * it creates a clone as a ‘subclass’ of the source object, i.e.
	 * properties and methods  are inherited from the source object into
	 * the clone.
	 *
	 * Note that the clone continues to be dependent on the source
	 * object. Changes in the source object property or method will
	 * affect all the clones unless this property is already overwritten
	 * in the clone object itself.
	 *
	 * @return A new object.
	 */

	obj.clone = function() {
		if (this._clone.prototype !== this) {
			this._clone = function() { this.init() };
			this._clone.prototype = this;
		}

		return new this._clone();
	};

	obj._clone = function() {};

	/**
	 * Initializes the object.
	 *
	 * This method normaly contains all object initialization code
	 * (instead of the constructor function).	Constructor function is
	 * the same for all objects and only contains object.init() call.
	 */

	obj.init = function() {};

	/**
	 * Handles exceptions in the ANet methods.
	 *
	 * The default error handler just throws the same exception to the
	 * next level. Overload this function to add your own diagnostics
	 * and error logging.
	 *
	 * @param	error (Error) Error object.
	 */

 	obj.handle = function(error) {
		throw(error);
	};

	/**
	 * Calls a method after a specified time interval has elapsed.
	 *
	 * This method has the same effect as window.setTimeout except that
	 * the function will be evaluated not as a global function but
	 * as a method of the current object.
	 *
	 * @param	handler (Function) Method to call.
	 * @param	delay (Number) Time interval in milliseconds.
	 * @return An identifier that can be used with window.clearTimeout
	 *				 to cancel the current method call.
	 */

	obj.setTimeout = function(handler, delay) {
		var self = this;
		var wrapper = function() { handler.call(self) };
		return window.setTimeout(wrapper, delay ? delay: 0);
	};

	/**
	 * Calls a method every time after a specified time interval has elapsed.
	 *
	 * This method has the same effect as window.setInterval except that
	 * the function will be evaluated not as a global function but
	 * as a method of the current object.
	 *
	 * @param	handler (Function) Method to call.
	 * @param	delay (Number) Time interval in milliseconds.
	 * @return An identifier that can be used with window.clearInterval
	 *				 to cancel the current method call.
	 */

	obj.setInterval = function(handler, delay) {
		var self = this;
		var wrapper = function() { handler.call(self) };
		return window.setInterval(wrapper, delay ? delay: 0);
	};

	/**
	 * Converts object to string.
	 *
	 * This method is overloaded in ANetWidgets subclasses.
	 *
	 * @return Text or HTML representation of the object.
	 */

 	obj.toString = function() {
		return "";
	};
};

ANet.System.Object.create();
/**
 * Anobis Network Generic Data Model Class
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 12:19:34
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.System.Model = ANet.System.Object.subclass();
ANet.System.Model.create = function() {
	var obj = this.prototype;

	/**
	 * Creates a new property.
	 *
	 * @param	name (String) Property name.
	 * @param	value	(String) Default property value.
	 */

	obj.defineProperty = function(name, value) {
		var _getProperty = ANet.camelCase("get", name);
		var _setProperty = ANet.camelCase("set", name);
		var _property = "_" + name;

		var getProperty = function() {
			return this[_property];
		};

		this[_setProperty] = function(value) {
			if(typeof value == "function") {
				this[_getProperty] = value;
			} else {
				this[_getProperty] = getProperty;
				this[_property] = value;
			}
		};

		this[_setProperty](value);
	};

	var get = {};
	var set = {};

	/**
	 * Returns property value.
	 *
	 * @param	name (String) Property name.
	 * @return Property value.
	 */

	obj.getProperty = function(name, a, b, c) {
		if (!get[name]) { get[name] = ANet.camelCase("get", name) }
		return this[get[name]](a, b, c);
	};

	/**
	 * Sets property value.
	 *
	 * @param	name (String) Property name.
	 * @param	value	(String) Property value.
	 */

	obj.setProperty = function(name, value, a, b, c) {
		if (!set[name]) { set[name] = ANet.camelCase("set", name) }
		return this[set[name]](value, a, b, c);
	};

	/**
	 * Indicates whether the data is available.
	 */

	obj.isReady = function() {
		return true;
	};
};
/**
 * Anobis Network Generic Data Fromatting Class
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 14:30:34
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.System.Format = ANet.System.Object.subclass();
ANet.System.Format.create = function() {
	var obj = this.prototype;

	/**
	 * Transforms the primitive value into the readable text.
	 *
	 * @param	value	(Any) Primitive value.
	 * @return Readable text.
	 */

	obj.valueToText = function(value) {
		return value;
	};

	/**
	 * Transforms the wire data into the primitive value.
	 *
	 * @param	data (String) Wire data.
	 * @return Primitive value.
	 */

	obj.dataToValue = function(data) {
		return data;
	};

	/**
	 * Transforms the wire data into the readable text.
	 *
	 * @param	data (String) Wire data.
	 * @return Readable text.
	 */

	obj.dataToText = function(data) {
		var value = this.dataToValue(data);
		return this.valueToText(value);
	};

	/**
	 * Specifies the text to be returned in case of error.
	 *
	 * @param	text (String) Error text.
	 */

	obj.setErrorText = function(text) {
		this._textError = text;
	};

	/**
	 * Specifies the value to be returned in case of error.
	 *
	 * @param	value	(Any) Error value.
	 */

	obj.setErrorValue = function(value) {
		this._valueError = value;
	};

	obj.setErrorText("#ERR");
	obj.setErrorValue(NaN);

	obj.textToValue = function(text) {
		return text;
	};

	obj.textToData = function(text) {
		return text;
	};

	obj.valueToData = function(value) {
		return value;
	};

	obj.comparator = function(values, greater, less, equal, error) {
		return function(i, j) {
			try {
				var a = values[i];
				var b = values[j];

				if (a > b) { return greater }
				if (a < b) { return less }

				return equal(i, j);
			} catch(e) {
				return error(i, j, e);
			}
		}
	};
};
/**
 * Anobis Network Generic base class for building and manipulating HTML markup
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 12:47:21
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *	v1.0.1 - 2005-07-07 - 08:46:23 by Laroche Fabrice
 *		- Improved the setTag function by adding a new parameter 'single'
 *			which defines if the tag has a closing tag or not.
 *		- Minor changes to the outerHTML function due to the new setTag
 *			parameter.
 *
 * Comments:
 */

ANet.System.HTML = ANet.System.Object.subclass();
ANet.System.HTML.create = function() {
	/**
	 * Objects, which  have visual representation, are most likely
	 * subclasses of this generic HTML class. It provides a set of
	 * functions to define attributes, inline styles, stylesheet
	 * selectors, DOM events and inner HTML content either as static
	 * properties or calls to the object's methods. Direct or implicit
	 * call to ‘toString’ method returns properly formatted HTML
	 * markup string, which can be used in document.write() call or
	 * assigned to the page innerHTML property.
	 *
	 * The two-way linking between original javascript object and
	 * it's DOM counterpart is maintained through the use of unique ID for
	 * each object. This allows forwarding DOM events back to the
	 * proper javascript master object and, if necessary, updating
	 * the correct piece of HTML on the page.
	 */

	var obj = this.prototype;

	/**
	 * By default each HTML object is a SPAN tag. This function allows
	 * to change the tag string.
	 *
	 * @param	tag (String) The new tag.
	 * @param	single (Boolean) Defines if the tag has a closing tag or not.
	 *
	 * @example	obj.setTag("DIV");
	 * @example	obj.setTag("IMG", true);
	 */

	obj.setTag = function(tag, single) {
		this._tag = tag;
		this._single = (single != null ? single: false);

		/**
		 * Reset the outerHTML cache when the tag gets set or changed
		 */

		this._outerHTML = "";
	};

	/**
	 * Returns HTML tag for the object.
	 *
	 * @return	HTML tag string
	 */

	obj.getTag = function() {
		return this._tag;
	};

	obj._tag = "span";
	obj._single = false;

	/**
	 * Initializes the object and fires the onInit event.
	 */

	var tagPattern = "anet";

	obj.init = function(args) {
		if (this.$owner) { return }
		if (this._parent) { return }

		this._id = tagPattern + ANet.all.id++;
		ANet.all[this._id] = this;
		this.onInit(args);
	};

	/**
	 * 2005-06-26 - 13:25:42 - by Laroche Fabrice
	 *
	 * This event gets fired after the object got
	 * initialized. (e.g. var tag = new ANet.System.HTML)
	 */

	obj.onInit = function() {
	};

	/**
	 * Returns unique ID for the object.
	 *
	 * @return	Unique ID string.
	 */

	obj.getId = function() {
		return this._id;
	};

	obj._id = "";

	/**
	 * Sets ID string for an element.
	 *
	 * @param	id (String) New ID.
	 */

	obj.setId = function(id) {
		this._id = id;
		ANet.all[this._id] = this;
	};

	/**
	 * Returns a reference to the HTML element.
	 *
	 * This function returns null if it is called before writing the
	 * object to the page.
	 *
	 * @return Reference to the HTML element
	 */

	obj.element = function() {
		var i, docs = ANet.docs, id = this.getId(), e;

		for(i = 0; i < docs.length; i++) {
			e = docs[i].getElementById(id);
			if (e) { return e }
		}
	};

	/**
	 * Returns CSS selector.
	 *
	 * @param	name (String) Selector name.
	 * @param	exec (Boolean) If set to false then return the function as is.
	 * @return	Selector value.
	 */

	obj.getClass = function(name) {
		var param = "_" + name + "Class";
		var value = this[param];

		return (typeof(value) == "function") ? value.call(this): value;
	};

	/**
	 * Sets CSS selector.
	 *
	 * The selector string is composed from the three parts - the prefix
	 * ('anet'),	the name and the value, separated by the '-' character.
	 * Normally the object class string consists of several selectors
	 * separated by space.
	 *
	 * Selector values are stored and inherited separately within the
	 * object. This function allows easy access to single selector
	 * value without parsing the whole class string.
	 *
	 * The following example adds 'anet-template-box' stylesheet
	 * selector to the object class.
	 *
	 * @param	name (String) Selector name.
	 * @param	value (String/Function) Selector value.
	 * @example obj.setClass("template", "box");
	 */

	obj.setClass = function(name, value) {
		var element = this.element();

		if (element) {
			var v = (typeof(value) == "function") ? value.call(this): value;

			if (v == null) {
				element.className = element.className.replace(new RegExp("(anet-" + name + "-\\w+ |$)"), "");
			} else {
				element.className = element.className.replace(new RegExp("(anet-" + name + "-\\w+ |$)"), " anet-" + name + "-" + v + " ");
			}
		}

		var param = "_" + name + "Class";

		if (this[param] == null) {
			this._classes += " " + name
		}

		this[param] = value;
		this._outerHTML = "";

		if (this.lock) { this.lock() }
	};

	/**
	 * Updates CSS selectors string for an element.
	 */

	obj.refreshClasses = function() {
		var element = this.element();
		if (!element) { return }

		var s = "", classes = this._classes.split(" ");

		for (var i = 1; i < classes.length; i++) {
			var name = classes[i];
			var value = this["_" + name + "Class"];

			if (typeof(value) == "function") {
				value = value.call(this);
			}

			s += "anet-" + name + "-" + value + " ";
		}

		element.className = s;
	};

	obj._classes = "";

	/**
	 * Returns inline CSS attribute.
	 *
	 * @param	name (String) CSS attribute name.
	 * @return	CSS attribute value.
	 */

	obj.getStyle = function(name) {
		var param = "_" + name + "Style";
		var value = this[param];

		return typeof(value) == "function" ? value.call(this): value;
	};

	/**
	 * Sets inline CSS attribute.
	 *
	 * @param	name (String) CSS attribute name.
	 * @param	value (String/Function) CSS attribute value.
	 */

	obj.setStyle = function(name, value) {
		var element = this.element();
		if (element) { element.style[name] = value }

		var param = "_" + name + "Style";

		if (this[param] == null) {
			this._styles += " " + name
		}

		this[param] = value;
		this._outerHTML = "";

		if (this.lock) { this.lock() }
	};

	obj._styles = "";

	/**
	 * Returns HTML attribute.
	 *
	 * @param	name (String) HTML attribute name.
	 * @return	HTML attribute value.
	 */

	obj.getAttribute = function(name) {
		try {
			var param = "_" + name + "Attribute";
			var value = this[param];

			return typeof(value) == "function" ? value.call(this): value;
		} catch(error) {
			this.handle(error);
		}
	};

	/**
	 * Sets HTML attribute.
	 *
	 * @param	name (String) HTML attribute name.
	 * @param	value (String/Function) HTML attribute value.
	 */

	obj.setAttribute = function(name, value) {
		try {
			var param = "_" + name + "Attribute";

			if (typeof this[param] == "undefined") { this._attributes += " " + name }

			if (specialAttributes[name] && (typeof value == "function")) {
				this[param] = function() { return value.call(this) ? true: null };
			} else {
				this[param] = value;
			}

			this._outerHTML = "";
			if (this.lock) { this.lock() }
		} catch(error) {
			this.handle(error);
		}
	};

	obj._attributes = "";

	var specialAttributes = {
		checked	  : true,
		disabled  : true,
		hidefocus : true,
		readonly  : true};

	/**
	 * Returns HTML event handler.
	 *
	 * @param	name (String) HTML event name.
	 * @return	HTML event handler.
	 */

	obj.getEvent = function(name) {
		try {
			var param = "_" + name + "Event";
			var value = this[param];

			return value;
		} catch(error) {
			this.handle(error);
		}
	};

	/**
	 * Sets HTML event handler.
	 *
	 * @param	name (String) HTML event name.
	 * @param	value (String/Function) HTML event handler.
	 */

	obj.setEvent = function(name, value) {
		try {
			var param = "_" + name + "Event";

			if (this[param] == null) {
				this._events += " " + name
			}

			this[param] = value;
			this._outerHTML = "";

			if (this.lock) { this.lock() }
		}	catch(error) {
			this.handle(error);
		}
	};

	obj._events = "";

	/**
	 * Returns static HTML content.
	 *
	 * @param	name (String) content name.
	 * @return	content object or function.
	 */

	obj.getContent = function(name) {
		try {
			var split = name.match(/^(\w+)\W(.+)$/);

			if (split) {
				var ref = this.getContent(split[1]);
				return ref.getContent(split[2]);
			}	else {
				var param = "_" + name + "Content";
				var value = this[param];

				if ((typeof value == "object") && (value._parent != this)) {
					/**
					 * 2005-07-02 - 22:44:16 - by Laroche Fabrice
					 *
					 * The above IF condition was separated into two IF
					 * conditions; the one above and below this comment. The
					 * reason is that the object should only be cloned in case
					 * the parent differs from 'this' but the ID must be updated
					 * every time we request the content as this object may occure
					 * more than once but with different ID's e.g. tag1.tab:0-caption,
					 * tag1.tab:1-caption. In case we won't update the ID then we
					 * cannot access the right element in the document!
					 */

					value = value.clone();
					value._parent = this;
					this[param] = value;
				}

				if (value && typeof value == "object" && !value.defineModel) {
					value._id = this._id + "-" + name;
				}

				return value;
			}
		}	catch(error) {
			this.handle(error);
		}
	};

	/**
	 * Sets static HTML content.
	 *
	 * @param	name (String) content name.
	 * @param	value (Object/String/Function) static content.
	 */

	obj.setContent = function(name, value) {
		try {
			if (arguments.length == 1) { /* Assigning array or single function */
				this._content = "";

				if (typeof name == "object") {
					for (var i in name)	{
						if (typeof(i) == "string") {
							this.setContent(i, name[i]);
						}
					}
				} else {
					this.setContent("html", name);
				}
			} else {
				var split = name.match(/^(\w+)\W(.+)$/);

				if (split) {
					var ref = this.getContent(split[1]);
					ref.setContent(split[2], value);

					this._innerHTML = "";
					this._outerHTML = "";
				} else {
					var param = "_" + name + "Content";

					if (this[param] == null) { this._content += " " + name }

					if (value && typeof value == "object") {
						value._parent = this;

						if (!value.defineModel) {
							value._id = this._id + "-" + name;
						}
					}

					this[param] = value;
					this._innerHTML = "";
					this._outerHTML = "";
				}
			}

			if (this.lock) { this.lock() }
		} catch(error) {
			this.handle(error);
		}
	};

	obj._content = "";

	/**
	 * Returns 'innerHTML' string for an object.
	 */

	var getParamStr = function(i) { return "{#" + i + "}" };
	var getControlFunc = function(v) { return function() { return v } };

	obj.innerHTML = function() {
		try {
			/**
			 * Just return cached value if available
			 */

			if (this._innerHTML) { return this._innerHTML }

			this._innerParamLength = 0;

			var i, j, name, value, param1, param2, html, item, s = "";
			var content = this._content.split(" ");

			for(i = 1; i < content.length; i++) {
				name = content[i];
				value = this["_" + name + "Content"];

				if (typeof(value) == "function") {
					param = getParamStr(this._innerParamLength++);
					this[param] = value;
					s += param;
				} else if (typeof(value) == "object" && value.defineModel) {
					param = getParamStr(this._innerParamLength++);
					this[param] = getControlFunc(value);
					s += param;
				} else if (typeof(value) == "object") {
					item = value;
					html = item.outerHTML().replace(/\{id\}/g, "{id}-" + name);

					for(j = item._outerParamLength - 1; j >= 0; j--) {
						param1 = getParamStr(j);
						param2 = getParamStr(this._innerParamLength + j);

						if (param1 != param2) { html = html.replace(param1, param2) }
						this[param2] = item[param1];
					}

					this._innerParamLength += item._outerParamLength;
					s += html;
				} else {
					s += value;
				}
			}

			this._innerHTML = s;
			return s;
		} catch(error) {
			this.handle(error);
		}
	};

	/**
	 * Returns 'outerHTML' string for an object.
	 */

	obj.outerHTML = function() {
		try {
			/**
			 * Just return cached value if available
			 */

			if (this._outerHTML) { return this._outerHTML }

			/**
			 * Build innerHTML first
			 */

			var innerHTML = this.innerHTML();

			/**
			 * Reset param count
			 */

			this._outerParamLength = this._innerParamLength;

			/**
			 * Elementless templates
			 */

			if (!this._tag) { return innerHTML }

			var i, tmp, name, value, param;

			var html = "<" + this._tag + " id=\"{id}\"";

			tmp = "";
			var classes = this._classes.split(" ");

			for(i = 1; i < classes.length; i++) {
				name = classes[i];
				value = this["_" + name + "Class"];

				if (typeof(value) == "function") {
					param = getParamStr(this._outerParamLength++);
					this[param] = value;
					value = param;
				}

				tmp += "anet-" + name + "-" + value + " ";
			}

			if (tmp) { html += " class=\"" + tmp + "\"" }

			tmp = "";
			var styles = this._styles.split(" ");

			for(i = 1; i < styles.length; i++) {
				name = styles[i];
				value = this["_" + name + "Style"];

				if (typeof(value) == "function") {
					param = getParamStr(this._outerParamLength++);
					this[param] = value;
					value = param;
				}

				tmp += name + ":" + value + ";";
			}

			if (tmp) { html += " style=\"" + tmp + "\"" }

			tmp = "";
			var attributes = this._attributes.split(" ");

			for(i = 1; i < attributes.length; i++) {
				name = attributes[i];
				value = this["_" + name + "Attribute"];

				if (typeof(value) == "function") {
					param = getParamStr(this._outerParamLength++);
					this[param] = value;
					value = param;
				} else if (specialAttributes[name] && !value) {
					value = null;
				}

				if (value !== null) {
					tmp += " " + name + "=\"" + value + "\"";
				}
			}

			html += tmp;

			tmp = "";
			var events = this._events.split(" ");

			for(i = 1; i < events.length; i++) {
				name = events[i];
				value = this["_" + name + "Event"];

				if (typeof(value) == "function") {
					value = "ANet(this, event)";
				}

				tmp += " " + name + "=\"" + value + "\"";
			}

			html += tmp;

			/**
			 * Is it a closing or non-closing tag
			 */

			if (this._single) {
				html += " />";
			} else {
				html += ">" + innerHTML + "</" + this._tag + ">";
			}

			/**
			 * Save the result in cache and return
			 */

			this._outerHTML = html;
			return html;
		} catch(error) {
			this.handle(error);
		}
	};

	/**
	 * Returns HTML markup string for the object.
	 *
	 * Direct or implicit
	 * call to ‘toString’ method returns properly formatted HTML
	 * markup string, which can be used in document.write() call or
	 * assigned to the page innerHTML property.
	 *
	 * @return	HTML string.
	 */

	obj.toString = function() {
		try {
			this.onLoading();

			var i, s = this._outerHTML;

			if (!s) { s = this.outerHTML() }
			s = s.replace(idPattern, this._id);

			var max = this._outerParamLength;

			if (paramCache.length < max) {
				for (i = paramCache.length; i < max; i++) {
					paramCache[i] = getParamStr(i);
				}
			}

			for(i = 0; i < max; i++) {
				var param = paramCache[i];
				var value = this[param]();

				if (value === null) {
					value = "";
					param = specialParams[i];
					if (!param) { param = getSpecialParamStr(i); }
				}

				s = s.replace(param, value);
			}

			this.setTimeout(this.onLoaded, 1);

			return s;
		} catch(error) {
			this.handle(error);
		}
	};

	/**
	 * 2005-07-02 - 22:58:57 - by Laroche Fabrice
	 *
	 * This event gets fired after the element was
	 * written to the document.
	 */

	obj.onLoading = function() {
	};

	obj.onLoaded = function() {
	};

	var idPattern = /\{id\}/g;
	var paramCache = [];
	var specialParams = [];

	function getSpecialParamStr(i) { return (specialParams[i] = new RegExp("[\\w\\x2D]*=?:?\\x22?\\{#" + i + "\\}[;\\x22]? ?")); }

	/**
	 * Updates HTML on the page and fires the onRefresh event.
	 */

	obj.refresh = function() {
		try {
			this.onRefresh();

			var element = this.element();
			if (element) { ANet.setOuterHTML(element, this.toString()) }
		} catch(error) {
			this.handle(error);
		}
	};

	/**
	 * 2005-06-26 - 13:46:14 - by Laroche Fabrice
	 *
	 * This event gets fired before the element gets
	 * refreshed.
	 */

	obj.onRefresh = function() {
	};

	obj.setSize = function(width, height) {
		if (typeof(width) != "undefined") { this.setStyle("width", typeof(width) == "number" ? width - ANet.dx + "px": width) }
		if (typeof(height) != "undefined") { this.setStyle("height", typeof(height) == "number" ? height - ANet.dy + "px": height) }
	};

	obj.setPosition = function(left, top, width, height) {
		this.setStyle("position", "absolute");
		this.setSize(width, height);

		if (typeof(left) != "undefined") { this.setStyle("left", left + "px") }
		if (typeof(top) != "undefined") { this.setStyle("top", top + "px") }
	};
};
/**
 * Anobis Network Generic HTML Template Class
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 14:03:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.System.Template = ANet.System.HTML.subclass();
ANet.System.Template.create = function() {
	/**
	 * Generic HTML template class. Template is a re-usable HTML
	 * fragment aimed to produce markup as part of a larger
	 * object (control).
	 *
	 * Template can either be a simple element or a complex HTML structure
	 * and may include calls to other templates as part of the output.
	 *
	 * Templates can access properties of the parent control,
	 * so the template output will be different depending on
	 * the control's data. Templates can also accept parameters
	 * allowing to generate lists or tables of data with the
	 * single instance of the template.
	 */

	var obj = this.prototype;

	obj.lock = function() {
		if (!this.$owner) {	return }
		this.$owner[ANet.camelCase("set", this.$name, "template")](this, this.$0, this.$1, this.$2);
	};

	/**
	 * Returns the template object.
	 *
	 * @param	name (String) Template name.
	 * @return Template object.
	 */

	obj.getTemplate = function(name) {
		var i, args = [], get = ANet.camelCase("get", name, "template");
		for(i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i] }
		return this[get].apply(this, args);
	};

	/**
	 * Sets the template.
	 *
	 * @param	name (String) Template name.
	 * @param	template (Object) Template object.
	 */

	obj.setTemplate = function(name, template, index) {
		var set = ANet.camelCase("set", name, "template");
		this[set](template, index);
	};

	/**
	 * Runs the action.
	 *
	 * @param	name (String) Action name.
	 * @param	source (Object) Action source.
	 */

	obj.raiseEvent = function(name, source, a, b, c) {
		if (typeof source == "undefined") {
			source = this;
			a = this.$0;
			b = this.$1;
			c = this.$2;
		}

		var handler = this[name];

		if (typeof(handler) == "function") {
			var r = handler.call(this, source, a, b, c);
			if (r) { return r	}
		}

		if (this.$owner && this.$owner.raiseEvent) {
			return this.$owner.raiseEvent(name, source, a, b, c);
		}
	};

	obj.mapTemplate = function(source, target) {
		var get = ANet.camelCase("get", source, "template");

		if (typeof(target) == "function") {
			this[get] = target
		} else {
			var u, m = ANet.camelCase("get", target, "template");

			this[get] = function(a, b, c) {
				if (a === u) { return this.$owner[m](this.$0, this.$1, this.$2) }
				if (b === u) { return this.$owner[m](a, this.$0, this.$1) }
				if (c === u) { return this.$owner[m](a, b, this.$0) }

				return this.$owner[m](a, b, c)
			}
		}

		this.lock()
	};

	obj.mapModel = function(source, target, target2) {
		var get = ANet.camelCase("get", source, "property");
		var set = ANet.camelCase("set", source, "property");

		if (typeof(target) == "function") {
			this[get] = target;

			if (typeof(target2) == "function") {
				this[set] = target2
			} else {
			 	this[set] = function() {}
			}
		} else {
			var _get = ANet.camelCase("get", target, "property");
			var _set = ANet.camelCase("set", target, "property");
			var u;

			this[get] = function(p, a, b, c) {
				if (a === u) { return this.$owner[_get](p, this.$0, this.$1, this.$2) }
				if (b === u) { return this.$owner[_get](p, a, this.$0, this.$1) }
				if (c === u) { return this.$owner[_get](p, a, b, this.$0) }

				return this.$owner[_get](p, a, b, c)
			};

			this[set] = function(p, v, a, b, c) {
				if (a === u) { return this.$owner[_set](p, v, this.$0, this.$1, this.$2) }
				if (b === u) { return this.$owner[_set](p, v, a, this.$0, this.$1) }
				if (c === u) { return this.$owner[_set](p, v, a, b, this.$0) }

				return this.$owner[_set](p, v, a, b, c)
			}
		}

		this.lock()
	};

	/**
	 * Returns the saved value in a cookie
	 *
	 * @param index (String) Key/Index of the saved value.
	 */

	obj.getCookie = function(index) {
		this._cookies = document.cookie.length ? " " + document.cookie: null;

		if (this._cookies) {
			index = (this.$owner ? this.$owner.getId(): this.getId()) + "-" + index;

			var start = this._cookies.indexOf(" " + index + "=");

			if (start == -1)
				return null;

			var end = this._cookies.indexOf(";", start);

			if (end == -1)
				end = this._cookies.length;

			end -= start;

			var cookie = this._cookies.substr(start, end);
			return unescape(cookie.substr(cookie.indexOf("=") + 1, cookie.length - cookie.indexOf("=") + 1));
		}

		return null;
	};

	/**
	 * Allows to save values in a cookie
	 *
	 * @param value (String) Value to save in the cookie.
	 * @param index (String) Key/Index of the value.
	 */

	obj.setCookie = function(value, index) {
		index = (this.$owner ? this.$owner.getId(): this.getId()) + "-" + index;
		document.cookie = index + "=" + escape(value);
	};

	obj._cookies = null;
};
/**
 * Anobis Network Generic User Interface Control Class
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 14:15:23
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *	- v1.0.1 - 2005-06-28 - 08:02:14 by Laroche Fabrice
 *		Added the feature to get/set cookies.
 *
 * Comments:
 */

ANet.System.Control = ANet.System.HTML.subclass();
ANet.System.Control.create = function() {
	/**
	 * Generic user interface control class. Control is a screen element,
	 * which can have focus and responds to the keyboard or mouse commands.
	 *
	 * Typical control has a set of built-in or external data models
	 * and may also contain additional presentation templates.
	 */

	ANet.System.Template.create.call(this);

	var obj = this.prototype;
	var templates = ANet.System.Template.prototype;

	/**
	 * Set SPAN as default tag and set the system style class
	 */

	obj.setTag("span");
	obj.setClass("system", "control");
	obj.setAttribute("anet", "control");

	/**
	 * By default we disable the content menu and selection
	 */

	obj.setEvent("oncontextmenu", "return false");
	obj.setEvent("onselectstart", "return false");

	obj.clear = function() {
	};

	/**
	 * Returns the data model object. For a built-in model this method
	 * will create a temporary proxy attached to the template.
	 *
	 * @param	name	(String) Name of the data model.
	 * @return			A data model object.
	 */

	obj.getModel = function(name) {
		var getModel = ANet.camelCase("get", name, "model");
		return this[getModel]();
	};

	/**
	 * Sets the external data model.
	 *
	 * @param	name	(String) Name of the data model.
	 * @param	model	(Object) Data model object.
	 */

	obj.setModel = function(name, model) {
		var setModel = ANet.camelCase("set", name, "model");
		return this[setModel](model);
	};

	/**
	 * Creates a new data model.
	 *
	 * @param	name (String) New data model name.
	 * @param properties (Array) Default model properties
	 */

	obj.defineModel = function(name, properties) {
		var ext = "_" + name + "Model";

		var defineProperty = ANet.camelCase("define", name, "property");
		var getProperty = ANet.camelCase("get", name, "property");
		var setProperty = ANet.camelCase("set", name, "property");

		var getModel = ANet.camelCase("get", name, "model");
		var setModel = ANet.camelCase("set", name, "model");
		var clearModel = ANet.camelCase("clear", name);

		var getInt = {};
		var setInt = {};
		var getExt = {};
		var setExt = {};
		var changing = {};
		var changed = {};
		var error = {};

		var undef;

		/**
		 * Define property
		 */

		this[defineProperty] = function(p, v, arrayValue) {
			var _p = "_" + ANet.camelCase(name, p);

			var _p1 = _p + "1";
			var _p2 = _p + "2";
			var _p3 = _p + "3";

			/**
			 * Internal
			 */

			var get = (getInt[p] = ANet.camelCase("get", name, p));
			var set = (setInt[p] = ANet.camelCase("set", name, p));

			/**
			 * External
			 */

			var $get = (getExt[p] = ANet.camelCase("get", p));
			var $set = (setExt[p] = ANet.camelCase("set", p));

			var _changing = (changing[p] = ANet.camelCase("on", name, p, "changing"));
			var _changed = (changed[p] = ANet.camelCase("on", name, p, "changed"));
			var _error = (error[p] = ANet.camelCase("on", name, p, "error"));

			/**
			 * Get property
			 */

			this[get] = function(a, b, c) {
				if (this[ext] && this[ext][$get]) {
					return this[ext][$get](a, b, c)
				}

				var r;

				if (c !== undef && this[_p3] && this[_p3][c] && this[_p3][c][b] && this[_p3][c][b][a] !== undef) {
					r = this[_p3][c][b][a]
				} else if (b !== undef && this[_p2] && this[_p2][b] && this[_p2][b][a] !== undef) {
					r = this[_p2][b][a]
				} else if (a !== undef &&	this[_p1] && this[_p1][a] !== undef) {
					r = this[_p1][a]
				} else {
					r = this[_p];
				}

				return (typeof(r) == "function") ? r.call(this, a, b, c): r;
			};

			function isArray(a) {
				return a && typeof(a) == "object" && !a.constructor.subclass && !arrayValue;
			}

			/**
			 * Set Property
			 */

			var setProp = function (v, a, b, c) {
				var i;

				if (isArray(v)) {
					for(i in v) {
						if (isArray(v[i])) {
							this[_p2] = v;
							delete this[_p3];

							return;
						}

						break;
					}

					if (a !== undef) {
						if (!this[_p2]) { this[_p2] = {} }
						this[_p2][a] = v;
						delete this[_p3];
					} else {
						this[_p1] = v;
						delete this[_p2];
						delete this[_p3];
					}

					return;
				}

				if (c !== undef) {
					if (!this[_p3]) { this[_p3] = {} }
					if (!this[_p3][c]) { this[_p3][c] = {} }
					if (!this[_p3][c][b]) { this[_p3][c][b] = {} }

					this[_p3][c][b][a] = v;
				} else if (b !== undef) {
					if (!this[_p2]) { this[_p2] = {} }
					if (!this[_p2][b]) { this[_p2][b] = {} }

					this[_p2][b][a] = v;
				} else if (a !== undef) {
					if (!this[_p1]) { this[_p1] = {$owner: this} }
					else if (this[_p1].$owner != this) {
						var r = this[_p1]; this[_p1] = {};

						for (i in r) { this[_p1][i] = r[i] }
						this[_p1].$owner = this;
					}

					this[_p1][a] = v;
				} else {
					this[_p] = v;
					delete this[_p1];
					delete this[_p2];
					delete this[_p3];
				}
			};

			this[set] = function(v, a, b, c) {
				if (this[ext] && this[ext][$set]) {
					return this[ext][$set](v, a, b, c)
				}

				var r = this.raiseEvent(_changing, v, a, b, c);

				if (r) {
					this.raiseEvent(_error, r, a, b, c);
					return false;
				}

				setProp.call(this, v, a, b, c);
				this.raiseEvent(_changed, v, a, b, c);
				return true;
			};

			setProp.call(this, v);

			var clearPrevious = this[clearModel];

			this[clearModel] = function() {
				delete this[_p3];
				delete this[_p2];
				delete this[_p1];
				delete this[_p];

				clearPrevious.call(this);
				setProp.call(this, v);
			}
		};

		this[getProperty] = function(p, a, b, c) {
			try {
				if (this[ext] && this[ext][getExt[p]]) { return this[ext][getExt[p]](a, b, c) }
				return this[getInt[p]](a, b, c)
			} catch(error) {
				return this.handle(error)
			}
		};

		this[setProperty] = function(p, v, a, b, c) {
			try {
				if (this[ext] && this[ext][setExt[p]]) { return this[ext][setExt[p]](v, a, b, c) }
				return this[setInt[p]](v, a, b, c);
			} catch(error) {
				return this.handle(error)
			}
		};

		templates[getProperty] = function(p, a, b, c) {
			if (a === undef) { return this.$owner[getProperty](p, this.$0, this.$1, this.$2) }
			if (b === undef) { return this.$owner[getProperty](p, a, this.$0, this.$1) }
			if (c === undef) { return this.$owner[getProperty](p, a, b, this.$0) }

			return this.$owner[getProperty](p, a, b, c);
		};

		templates[setProperty] = function(p, v, a, b, c) {
			if (a === undef) { return this.$owner[setProperty](p, v, this.$0, this.$1, this.$2) }
			if (b === undef) { return this.$owner[setProperty](p, v, a, this.$0, this.$1) }
			if (c === undef) { return this.$owner[setProperty](p, v, a, b, this.$0) }

			return this.$owner[setProperty](p, v, a, b, c);
		};

		this[getModel] = function() {
			return this[ext];
		};

		this[setModel] = function(model) {
			this[ext] = model;
			if (model) { model.$owner = this }
		};

		this[clearModel] = function() {
			if (this[ext] && this[ext].$owner) {
				delete this[ext].$owner;
			}

			delete this[ext];
		};

		var clear = this.clear;

		this.clear = function() {
			clear.call(this);
			this[clearModel]();
		};

		var i, zz = {};

		for (i in properties) {
			if (!zz[i]) {
				this[defineProperty](i, properties[i])
			}
		}
	};

	/**
	 * Creates a link to the new content template (array).
	 *
	 * @param	name	(String) Template name.
	 * @param	template	(Object) Template object.
	 */

	obj.defineTemplate = function(name, template) {
		var ref = "_" + name + "Template";
		var ref1 = ref + "1", ref2 = ref + "2", ref3 = ref + "3";

		var get = ANet.camelCase("get", name, "template");
		var set = ANet.camelCase("set", name, "template");

		var clone = ANet.camelCase("_", name, "template", "clone");

		var name1 = "-" + name;
		var name2 = "-" + name + "-";

		var undef;

		this[get] = function(a, b, c) {
			if (typeof(this[ref]) == "function") {
				return this[ref](a, b, c);
			}

			var r, id, useClone = false;

			if (a === undef) {
				id = this._id + name1;
				r = this[ref];
			} else if (b === undef) {
				id = this._id + name2 + a;

				if (this[ref1] && this[ref1][a]) {
					r = this[ref1][a];
				} else {
					r = this[ref];
					useClone = true;
				}
			} else if (c === undef) {
				id = this._id + name2 + a + "-" + b;

				if (this[ref2] && this[ref2][a] && this[ref2][a][b]) {
					r = this[ref2][a][b];
				} else if (this[ref1] && this[ref1][a]) {
					r = this[ref1][a];
					useClone = true;
				} else {
					r = this[ref];
					useClone = true;
				}
			} else {
				id = this._id + name2 + a + "-" + b + "-" + c;

				if (this[ref3] && this[ref3][a] && this[ref3][a][b] && this[ref3][a][b][c] ) {
					r = this[ref2][a][b][c];
				} else if (this[ref2] && this[ref2][a] && this[ref2][a][b]) {
					r = this[ref2][a][b];
					useClone = true;
				}	else if (this[ref1] && this[ref1][a]) {
					r = this[ref1][a];
					useClone = true;
				} else {
					r = this[ref];
					useClone = true;
				}
			}

			if (useClone || r.$owner != this) {
				if (!r.$clone) {
					r.$clone = r.clone();
					r.$clone.$clone = null;
				}

				r = r.$clone;
			}

			r.$owner = this;
			r.$0 = a;
			r.$1 = b;
			r.$2 = c;
			r._id = id;
			return r;
		};

		templates[get] = function(a, b, c) {
			if (a === undef) { return this.$owner[get](this.$0, this.$1, this.$2) }
			if (b === undef) { return this.$owner[get](a, this.$0, this.$1) }
			if (c === undef) { return this.$owner[get](a, b, this.$0) }

			return this.$owner[get](a, b, c);
		};

		this[set] = function(template, a, b, c) {
			if (a === undef) {
				if (this[ref] == template) {
					return;
				}

				if (this[ref]) {
					this[ref].$clone = "";
				}

				this[ref] = template;

				if (template) {
					template.$clone = "";
					template.$name = name;

					if (template.$owner != this) {
						template.$owner = this;
						this.raiseEvent(ANet.camelCase("on", name, "templateChanged"), template);
					}
				}

				return;
			}

			if (b === undef) {
				if (!this[ref1]) {
					this[ref1] = {};
				}

				if (this[ref1][a] == template) {
					return;
				}

				this[ref1][a] = template;

				template.$clone = "";
				template.$name = name;
				template.$0 = a;

				this[ref].$clone = "";

				if (template.$owner != this) {
					template.$owner = this;
					this.raiseEvent(ANet.camelCase("on", name, "templateChanged"), template, a);
				}

				return;
			}

			if (c === undef) {
				if (!this[ref2]) {
					this[ref2] = {};
				}

				if (!this[ref2][a]) {
					this[ref2][a] = {};
				}

				this[ref2][a][b] = template;

				template.$clone = "";
				template.$name = name;

				this[ref].$clone = "";

				if (this[ref1] && this[ref1][a]) {
					this[ref1][a].$clone = "";
				}

				template.$0 = a;
				template.$1 = b;

				if (template.$owner != this) {
					template.$owner = this;
					this.raiseEvent(ANet.camelCase("on", name, "templateChanged"), template, a, b);
				}

				return;
			}
		};

		this[set](template);
	};

	function controlValue() {
		var text = this.getControlText();
		var format = this.getControlFormat();
		return format ? format.textToValue(text): text;
	}

	/**
	 * Define the control and tab index models
	 */

	obj.defineModel("tab", { index: 1 });
	obj.defineModel("state", { "default": false, selected: false, blured: false, inactive: false, disabled: false });
	obj.defineModel("control", { text: "", image: "", value: controlValue, link: "", target: "", format: "", tooltip: "", shortcut: "", visible: true, display: "inline-block" });

	/**
	 * Set the control onChange events
	 */

	obj.onControlVisibleChanged = function(visible) {
		this.setStyle("visibility", visible ? "visible": "hidden")
	};

	obj.onControlDisplayChanged = function(display) {
		this.setStyle("display", display)
	};

	/**
	 * Sets a new controller
	 *
	 * @param name (String) Controller name
	 * @param controller (Handlers) Controller handlers
	 */

	obj.setController = function(name, controller) {
		var i, n = "_" + name + "Controller";

		this[n] = controller;

		for (i = 0; i < this._controllers.length; i++) {
			if (this._controllers[i] == n) {
				return
			}
		}

		this._controllers = this._controllers.concat();
		this._controllers.push(n)
	};

	obj._controllers = [];

	/**
	 * Raises an event and the controllers of the source object
	 *
	 * @param name (String) Action name
	 * @param source (Object) Action source
	 */

	obj.raiseEvent = function(name, source, a, b, c) {
		var i, r;
		var handler = this[name];

		if (typeof(handler) == "function") {
			r = handler.call(this, source, a, b, c);
			if (r) { return r }
		}

		for (i = 0; i < this._controllers.length;	i++) {
			handler = this[this._controllers[i]] ? this[this._controllers[i]][name]: null;

			if (typeof(handler) == "function") {
				r = handler.call(this, source, a, b, c);
				if (r) { return r }
			} else if (typeof(handler) == "string" && handler != name) {
				r = this.raiseEvent(handler, source, a, b, c);
				if (r) { return r }
			}
		}
	};

	/**
	 * Listen to the following key names on a key down event
	 */

	var keyNames = { 8: "Backspace", 9: "Tab", 13: "Enter", 27: "Escape", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 45: "Insert", 46: "Delete",
									 112: "F1", 113: "F2", 114: "F3", 115: "F4", 116: "F5", 117: "F6", 118: "F7", 119: "F8", 120: "F9", 121: "F10", 122: "F11", 123: "F12" };

	/**
	 * Sets the on key down event (key listener for this control)
	 */

	obj.setEvent("onkeydown", function(event) {
		var key = keyNames[event.keyCode];

		if (event.keyCode >= 48 && event.keyCode <= 90) {
			key = String.fromCharCode(event.keyCode);
		}

		if (key) {
			if (event.shiftKey) { key = "Shift" + key }
			if (event.altKey)		{	key = "Alt" + key }
			if (event.ctrlKey)	{ key = "Ctrl" + key }

			this.raiseEvent("onKey" + key, event);
			event.cancelBubble = true;
		}
	});

	/**
	 * Raises a control event invoked by the mouse
	 *
	 * @param name (String) Action name
	 * @param element (Object) Action's element
	 * @param event (Object) Mouse event
	 */

	function raiseControlEvent(name, obj, event) {
		var a = ((obj.getId().match(/-*\d*-*\d*-*\d+$/)|| ["-"])+"").split("-");
		if (obj && obj.raiseEvent) { obj.raiseEvent(name, event, a[1], a[2], a[3]) }
	};

	/**
	 * Handle the mouse events
	 *
	 * @param e (Object) Element
	 * @param event (Object) Mouse event
	 */

	var targets = {};
	var capture = null;

	function setCapture(e) {
		ANet.attachEvent(e, "onmouseup", releaseCapture);
		ANet.attachEvent(e, "onlosecapture", releaseCapture);
		ANet.setCapture(e);
		capture = e;
	}

	function releaseCapture() {
		ANet.detachEvent(capture, "onmouseup", releaseCapture);
		ANet.detachEvent(capture, "onlosecapture", releaseCapture);
		ANet.releaseCapture(capture);
		capture = null;
	}

	function handleMouse(e, event) {
		try {
			var obj, c, i, t = {};

			while(e && e != ANet.docs[0].body) {
				if (e.getAttribute && (e.getAttribute("anet") || e.getAttribute("anetx"))) {
					t[e.id] = true;
				}

				e = e.parentNode
			}

			for(i in targets) {
				if(!t[i]) {
					c = false;
					e = ANet.element(i);
					obj = ANet.object(i);

					if (capture && capture != e) { break }
					try { if (obj.getStateProperty("disabled")) { break } } catch (err) {}

					if (e.getAttribute("anet")) {
						raiseControlEvent(ANet.camelCase("on", e.getAttribute("anet"), "mouseOut"), obj, event);

						if (e.getAttribute("anet") != "control") {
							e.className = e.className.replace(/ anet-mouseover-\w+/g, "");
							c = true;
						}
					}

					if (e.getAttribute("anetx")) {
						raiseControlEvent(ANet.camelCase("on", e.getAttribute("anetx"), "mouseOut"), obj, event);
						e.className = e.className.replace(/ anet-mouseover-\w+/g, "");
						c = true;
					}

					if (c && capture) {
						e.className = e.className.replace(/ anet-mousedown-\w+/g, "");
					}
				}
			}

			for(i in t) {
				if(!targets[i]) {
					e = ANet.element(i);
					obj = ANet.object(i);

					if (capture && capture != e) { break }
					try { if (obj.getStateProperty("disabled")) { break } } catch (err) {}

					if (e.getAttribute("anet")) {
						raiseControlEvent(ANet.camelCase("on", e.getAttribute("anet"), "mouseOver"), obj, event);

						if (e.getAttribute("anet") != "control") {
							e.className += " anet-mouseover-" + e.getAttribute("anet").toLowerCase();

							if (capture) {
								e.className += " anet-mousedown-" + e.getAttribute("anet").toLowerCase();
							}
						}
					}

					if (e.getAttribute("anetx")) {
						raiseControlEvent(ANet.camelCase("on", e.getAttribute("anetx"), "mouseOver"), obj, event);
						e.className += " anet-mouseover-" + e.getAttribute("anetx").toLowerCase();

						if (capture) {
							e.className += " anet-mousedown-" + e.getAttribute("anetx").toLowerCase();
						}
					}
				}
			}

			targets = t;
		} catch(error) {
		}
	};

	var empty = {};

	/**
	 * Control mouse handlers which will get attached to
	 * the document
	 */

	var handlers = {
		onmousemove: function(event) { handleMouse(ANet.srcElement(event), event) },
		onmouseover: function(event) { handleMouse(ANet.srcElement(event), event) },
		onmouseout:  function(event) { handleMouse(ANet.toElement(event), event)  },

		onmousedown: function(event) {
			try {
				var obj, c, e = ANet.srcElement(event);

				while(e && e != ANet.docs[0].body) {
					c = false;

					if (e.getAttribute && (e.getAttribute("anet") || e.getAttribute("anetx"))) {
						obj = ANet.object(e.id);

						try {
							if (obj.getStateProperty("disabled")) { break }
							if (obj.getStateProperty("inactive")) { break }
						} catch (err) {}

						if (e.getAttribute("anet")) {
							raiseControlEvent(ANet.camelCase("on", e.getAttribute("anet"), "mouseDown"), obj, event);

							if (e.getAttribute("anet") != "control") {
								e.className += " anet-mousedown-" + e.getAttribute("anet").toLowerCase();
								c = true;
							}
						}

						if (e.getAttribute("anetx")) {
							raiseControlEvent(ANet.camelCase("on", e.getAttribute("anetx"), "mouseDown"), obj, event);
							e.className += " anet-mousedown-" + e.getAttribute("anetx").toLowerCase();
							c = true;
						}
					}

					if (c) { setCapture(e) }
					e = e.parentNode;
				}
			} catch(x) {
			}
		},

		onmouseup: function(event) {
			try {
				var obj, e = ANet.srcElement(event);

				while (e && e != ANet.docs[0].body) {
					if (e.getAttribute && (e.getAttribute("anet") || e.getAttribute("anetx"))) {
						obj = ANet.object(e.id);

						try {
							if (obj.getStateProperty("disabled")) { break }
							if (obj.getStateProperty("inactive")) { break }
						} catch (err) {}

						if (e.getAttribute("anet")) {
							raiseControlEvent(ANet.camelCase("on", e.getAttribute("anet"), "mouseUp"), obj, event);

							if (e.getAttribute("anet") != "control") {
								e.className = e.className.replace(/ anet-mousedown-\w+/g, "");
							}
						}

						if (e.getAttribute("anetx")) {
							raiseControlEvent(ANet.camelCase("on", e.getAttribute("anetx"), "mouseUp"), obj, event);
							e.className = e.className.replace(/ anet-mousedown-\w+/g, "");
						}
					}

					e = e.parentNode;
				}
			} catch(x) {
			}
		},

		onclick: function(event) {
			try {
				var obj, e = ANet.srcElement(event), s = "Clicked";

				if (event.shiftKey) { s = "Shift" + s }
				if (event.altKey) { s = "Alt" + s }
				if (event.ctrlKey) { s = "Ctrl" + s }

				while (e && e != ANet.docs[0].body) {
					if (e.getAttribute && (e.getAttribute("anet") || e.getAttribute("anetx"))) {
						obj = ANet.object(e.id);

						try {
							if (obj.getStateProperty("disabled")) { break }
							if (obj.getStateProperty("inactive")) { break }
						} catch (err) {}

						if (e.getAttribute("anet")) {
							raiseControlEvent(ANet.camelCase("on", e.getAttribute("anet"), s), obj, event);
						}

						if (e.getAttribute("anetx")) {
							raiseControlEvent(ANet.camelCase("on", e.getAttribute("anetx"), s), obj, event);
						}
					}

					e = e.parentNode;
				}
			} catch(x) {
			}
		},

		ondblclick: function(event) {
			try {
				var obj, e = ANet.srcElement(event), s = "DoubleClicked";

				if (event.shiftKey) { s = "Shift" + s }
				if (event.altKey) { s = "Alt" + s }
				if (event.ctrlKey) { s = "Ctrl" + s }

				while (e && e != ANet.docs[0].body) {
					if (e.getAttribute && (e.getAttribute("anet") || e.getAttribute("anetx"))) {
						obj = ANet.object(e.id);

						try {
							if (obj.getStateProperty("disabled")) { break }
							if (obj.getStateProperty("inactive")) { break }
						} catch (err) {}

						if (e.getAttribute("anet")) {
							raiseControlEvent(ANet.camelCase("on", e.getAttribute("anet"), s), obj, event);
						}

						if (e.getAttribute("anetx")) {
							raiseControlEvent(ANet.camelCase("on", e.getAttribute("anetx"), s), obj, event);
						}
					}

					e = e.parentNode;
				}
			} catch(x) {
			}
		}
	};

	/**
	 * Detaches all the control handlers from the document when
	 * it gets unloaded
	 */

	ANet.register = function(win) {
		if (win != window) {
			win.ANet = ANet;
			ANet.docs.push(win.document);
		}

		/**
		 * Attach all the control handlers to the document
		 */

		ANet.forEach(handlers, function(name, handler) {
			ANet.attachEvent(win.document, name, handler);
		});

		function unregister() {
			ANet.unregister(win);
			ANet.detachEvent(win, "onunload", unregister);
			win = null;
		}

		/**
		 * Attach a window event to call the unload method when the
		 * document gets unloaded
		 */

		ANet.attachEvent(win, "onunload", unregister);
	};

	ANet.unregister = function(win) {
		ANet.forEach(handlers, function(name, handler) {
			ANet.detachEvent(win.document, name, handler);
		});

		if (win != window) {
			var i, docs = ANet.docs;

			for(i = 0; i < docs.length; i++) {
				if (docs[i] == win.document) {
					docs.splice(i, 1);
					return;
				}
			}

			win.ANet = null;
		}
	};

	ANet.register(window);
};
/**
 * Anobis Network String Data Formatting Class
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-27 - 07:43:45
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Formats.String = ANet.System.Format.subclass();
ANet.Formats.String.create = function() {
	var obj = this.prototype;

	obj.valueToText = function(data) {
		return data ? String(data).replace(ANet.textPattern, ANet.textReplace): "";
	};

	obj.textToValue = function(text) {
		return text ? String(text).replace(ANet.htmlPattern, ANet.htmlReplace): "";
	};

	/**
	 * Transforms the wire data into the primitive value.
	 *
	 * @param	data (String) Wire data.
	 * @return Primitive value.
	 */

	obj.textToData = obj.textToValue;

	/**
	 * Transforms the wire data into the readable text.
	 *
	 * @param	data (String) Wire data.
	 * @return Readable text.
	 */

	obj.dataToText = obj.valueToText;

	if ("".localeCompare) {
		obj.comparator = function(values, greater, less, equal, error) {
			return function(i, j) {
				try {
					return greater * ("" + values[i]).localeCompare(values[j]) || equal(i, j);
				} catch(e) {
					return error(i, j, e);
				}
			}
		};
	}
};
/**
 * Anobis Network Number Formatting Class
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-27 - 07:45:34
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Formats.Number = ANet.System.Format.subclass();
ANet.Formats.Number.create = function() {
	var obj = this.prototype;

	/**
	 * Transforms the wire data into the numeric value.
	 *
	 * @param	data (String) Wire data.
	 * @return Numeric value.
	 */

	obj.dataToValue = function(data) {
		return Number(("" + v).replace(numPattern, ""));
	};

	obj.textToValue = function(text) {
		return Number(("" + v).replace(numPattern, ""));
	};

	var numPattern = /[^0-9.\-+]+/gm;
	var noFormat = function(value) {
		return "" + value;
	};

	var doFormat = function(value) {
		var multiplier = this._multiplier;
		var abs = (value < 0) ? -value: value;
		var delta = (value < 0) ? -0.5: +0.5;
		var rounded = (Math.round(value * multiplier) + delta) / multiplier + "";
		if (abs < 1000) { return rounded.replace(this.p1, this.r1) }
		if (abs < 1000000) { return rounded.replace(this.p2, this.r2) }
		if (abs < 1000000000) { return rounded.replace(this.p3, this.r3) }

		return rounded.replace(this.p4, this.r4);
	};

	/**
	 * Allows to specify the format for the text output.
	 *
	 * @param	format	(String) Format pattern.
	 */

	obj.setTextFormat = function(format) {
		var pattern = /^([^0#]*)([0#]*)([ .,]?)([0#]|[0#]{3})([.,])([0#]*)([^0#]*)$/;
		var f = format.match(pattern);

		if (!f) {
			this.valueToText = function(value) { return "" + value };
			this.dataToText = function(value) { return "" + value };
			return;
		}

		this.valueToText = doFormat;
		this.dataToText = function(v) { return doFormat.call(this, Number(("" + v).replace(numPattern, ""))) };

		var rs = f[1]; // result start
		var rg = f[3]; // result group separator;
		var rd = f[5]; // result decimal separator;
		var re = f[7]; // result end

		var decimals = f[6].length;

		this._multiplier = Math.pow(10, decimals);

		var ps = "^(-?\\d+)", pm = "(\\d{3})", pe = "\\.(\\d{" + decimals + "})\\d$";

		this.p1 = new RegExp(ps + pe);
		this.p2 = new RegExp(ps + pm + pe);
		this.p3 = new RegExp(ps + pm + pm + pe);
		this.p4 = new RegExp(ps + pm + pm + pm + pe);

		this.r1 = rs + "$1" + rd + "$2" + re;
		this.r2 = rs + "$1" + rg + "$2" + rd + "$3" + re;
		this.r3 = rs + "$1" + rg + "$2" + rg + "$3" + rd + "$4" + re;
		this.r4 = rs + "$1" + rg + "$2" + rg + "$3" + rg + "$4" + rd + "$5" + re;
	};

	obj.setTextFormat("");
};
/**
 * Anobis Network Date Formatting Class
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-27 - 07:37:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Formats.Date = ANet.System.Format.subclass();
ANet.Formats.Date.create = function() {
	var obj = this.prototype;

	obj.date = new Date();

	obj.digits = [];
	obj.shortMonths = obj.shortMonths ? obj.shortMonths: ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
	obj.longMonths = obj.longMonths ? obj.longMonths: ["January","February","March","April","May","June","July","August","September","October","November","December"];
	obj.shortWeekdays = obj.shortWeekdays ? obj.shortWeekdays: ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
	obj.longWeekdays = obj.longWeekdays ? obj.longWeekdays: ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];

	for (var i = 0; i < 100; i++) { obj.digits[i] = i < 10 ? "0" + i: "" + i }

	var tokens = {
		"hh"	: "this.digits[this.date.getUTCHours()]",
		":mm"	: "':'+this.digits[this.date.getUTCMinutes()]",
		"mm:"	: "this.digits[this.date.getUTCMinutes()]+':'",
		"ss"	: "this.digits[this.date.getUTCSeconds()]",
		"dddd"	: "this.longWeekdays[this.date.getUTCDay()]",
		"ddd"	: "this.shortWeekdays[this.date.getUTCDay()]",
		"dd"	: "this.digits[this.date.getUTCDate()]",
		"d"		: "this.date.getUTCDate()",
		"mmmm"	: "this.longMonths[this.date.getUTCMonth()]",
		"mmm"	: "this.shortMonths[this.date.getUTCMonth()]",
		"mm"	: "this.digits[this.date.getUTCMonth()+1]",
		"m"		: "(this.date.getUTCMonth()+1)",
		"yyyy"	: "this.date.getUTCFullYear()",
		"yy"    : "this.digits[this.date.getUTCFullYear()%100]" };

	var match = "";
	for(i in tokens) {
		if (typeof(i) == "string") {
			match += "|" + i;
		}
	}

	var re = new RegExp(match.replace("|", "(")+")", "gi");

	/**
	 * Allows to specify the format for the text output.
	 *
	 * @param	format	(String) Format pattern.
	 */

	obj.setTextFormat = function(format) {
		format = format.replace(re, function(i) { return "'+" + tokens[i.toLowerCase()] + "+'" });
		format = "if (isNaN(value) || (value === this._valueError)) return this._textError;" +
				 		 "this.date.setTime(value + this._textTimezoneOffset);" +
						 ("return '" + format + "'").replace(/(''\+|\+'')/g, "");

		this.valueToText = new Function("value", format);
	};

	var xmlExpr = /^(....).(..).(..).(..).(..).(..)........(...).(..)/;
	var xmlOut = "$1/$2/$3 $4:$5:$6 GMT$7$8";

	var auto = function(data) {
		var value = Date.parse(data + this._dataTimezoneCode);
		return isNaN(value) ? this._valueError: value;
	};

	var RFC822 = function(data) {
		var value = Date.parse(data);
		return isNaN(value) ? this._valueError: value;
	};

	var ISO8061 = function(data) {
		var value = Date.parse(data.replace(xmlExpr, xmlOut));
		return isNaN(value) ? this._valueError: value;
	};

	/**
	 * Allows to specify the wire format for data input.
	 *
	 * @param	format (String) Format pattern.
	 */

	obj.setDataFormat = function(format) {
		if (format == "RFC822") {
			this.dataToValue = RFC822;
		} else if (format == "ISO8601" || format == "ISO8061") {
			this.dataToValue = ISO8601;
		} else {
			this.dataToValue = auto;
		}
	};

	/**
	 * Allows to specify the timezone used for the text output.
	 *
	 * @param	value	(Number) Timezone offset.
	 */

	obj.setTextTimezone = function(value) {
		this._textTimezoneOffset = value;
	};

	/**
	 * Allows to specify the timezone used for the data input.
	 *
	 * @param	value	(Number) Timezone offset.
	 */

	obj.setDataTimezone = function(value) {
		if (!value) {
			this._dataTimezoneCode = " GMT";
		} else {
			this._dataTimezoneCode = " GMT" +
				(value>0 ? "+" : "-") +
				this.digits[Math.floor(Math.abs(value / 3600000))] +
				this.digits[Math.abs(value / 60000) % 60];
		}
	};

	var localTimezone = -obj.date.getTimezoneOffset() * 60000;

	obj.setTextTimezone(localTimezone);
	obj.setDataTimezone(localTimezone);

	obj.setTextFormat("d mmm yy");
	obj.setDataFormat("default");

	obj.textToValue = RFC822;
};
/**
 * Anobis Network HTML Data Formatting Class
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-27 - 07:43:45
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Formats.HTML = ANet.System.Format.subclass();
ANet.Formats.HTML.create = function() {
	var obj = this.prototype;

	/**
	 * Transforms the wire data into the primitive value.
	 *
	 * @param	data (String) Wire data.
	 * @return Primitive value.
	 */

	obj.dataToValue = function(data) {
		return data ? data.replace(ANet.htmlPattern, ANet.htmlReplace): "";
	};

	/**
	 * Transforms the wire data into the readable text.
	 *
	 * @param	data (String) Wire data.
	 * @return Readable text.
	 */

	obj.dataToText = function(data) {
		return data;
	};

	obj.textToValue = obj.dataToValue;

	if ("".localeCompare) {
		obj.comparator = function(values, greater, less, equal, error) {
			return function(i, j) {
				try {
					return greater * ("" + values[i]).localeCompare(values[j]) || equal(i, j);
				} catch(e) {
					return error(i, j, e);
				}
			}
		};
	}
};
/**
 * Anobis Network HTML Tag Definition
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 14:34:10
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *	v1.0.1 - 2005-07-07 - 08:57:45 by Laroche Fabrice
 *		- Add the feature to define single or nomal HTML tags.
 *
 * Comments:
 */

ANet.HTML.define = function(name, tag, type) {
	if (!tag) { tag = name.toLowerCase() }

	ANet.HTML[name] = ANet.System.HTML.subclass();
	ANet.HTML[name].create = function() { this.prototype.setTag(tag, type) };
};

/**
 * Define HTML tags
 */

(function() {
	var i;
	var ctags = ["DIV", "SPAN", "IFRAME", "BUTTON", "TEXTAREA", "TABLE", "TR", "TD"];
	var stags = ["IMG", "INPUT"]

	for (i = 0; i < ctags.length; i++) { ANet.HTML.define(ctags[i]) }
	for (i = 0; i < stags.length; i++) { ANet.HTML.define(stags[i], null, true) }
})();
/**
 * Anobis Network Generic HTTP Request Class
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 11:50:34
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.HTTP.Request = ANet.System.Model.subclass();
ANet.HTTP.Request.create = function() {
	var obj = this.prototype;

	/**
	 * Sets or retrieves the remote data URL
	 */

	obj.defineProperty("URL");

	/**
	 * Indicates whether asynchronous download is permitted
	 */

	obj.defineProperty("async", true);

	/**
	 * Specifies HTTP request method
	 */

	obj.defineProperty("requestMethod", "GET");

	/**
	 * Allows to send data with the request
	 */

	obj.defineProperty("requestData", "");

	/**
	 * Returns response text
	 */

	obj.defineProperty("responseText", function() { return this._http ? this._http.responseText: "" });

	/**
	 * Returns response XML
	 */

	obj.defineProperty("responseXML", function() { return this._http ? this._http.responseXML: "" });

	/**
	 * Sets or retrieves the user name
	 */

	obj.defineProperty("username", null);

	/**
	 * Sets or retrieves the password
	 */

	obj.defineProperty("password", null);

	/**
	 * Allows to specify namespaces for use in XPath expressions.
	 *
	 * @param name (String) The namespace alias.
	 * @param value (String) The namespace URL.
	 */

	obj.setNamespace = function(name, value) {
		this._namespaces += " xmlns:" + name + " = \"" + value + "\"";
	};

	obj._namespaces = "";

	/**
	 * Allows to specify the request arguments/parameters.
	 *
	 * @param name (String) The parameter name.
	 * @param value (String) The parameter value.
	 */

	obj.setParameter = function(name, value) {
		this["_" + name + "Parameter"] = value;
		if (!this._parameters.match(new RegExp(" " + name + "( |$)"))) { this._parameters += " " + name }
	};

	obj._parameters = "";

	/**
	 * Sets HTTP request header.
	 *
	 * @param name (String) The request header name.
	 * @param value (String) The request header value.
	 */

	obj.setRequestHeader = function(name, value) {
		this["_" + name + "Header"] = value;
		if (!this._headers.match(new RegExp(" " + name + "( |$)"))) { this._headers += " " + name }
	};

	obj._headers = "";

	obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

	/**
	 * Returns HTTP response header (for example "Content-Type").
	 *
	 * @param name (String) The response header name.
	 */

	obj.getResponseHeader = function(name) {
		return this._http ? this._http.getResponseHeader(name): "";
	};

	/**
	 * Sends the request.
	 */

	obj.request = function() {
		var self = this;
		this._ready = false;

		var i, j, name, value, data = "", params = this._parameters.split(" ");

		for(i = 1; i < params.length; i++) {
			name = params[i];
			value = this["_" + name + "Parameter"];

			if (typeof value == "function") { value = value(); }
			if (typeof value == "object" && value.constructor == Array) {
				for (j = 0; j < value.length; j++) {
					data += name + "=" + encodeURIComponent(value[j]) + "&";
				}
			} else {
				data += name + "=" + encodeURIComponent(value) + "&";
			}
		}

		var URL = this._URL;

		if ((this._requestMethod != "POST") && data) {
			URL += "?" + data;
			data = null;
		}

		this._http = ANet.createXMLHttpRequest();
		this._http.open(this._requestMethod, URL, this._async, this._username, this._password);

		var headers = this._headers.split(" ");

		for(i = 1; i < headers.length; i++) {
			name = headers[i];
			value = this["_" + name + "Header"];

			if (typeof value == "function") { value = value(); }

			this._http.setRequestHeader(name, value);
		}

		this._http.send(data);

		if (this._async) {
			this.setTimeout(wait, 200);
		} else {
			returnResult();
		}

		function wait() {
			if (self._http.readyState == 4) {
				self._ready = true;
				returnResult();
			}	else {
				self.setTimeout(wait, 200);
			}
		}

		function returnResult() {
			var xml = self._http.responseXML;

			if (xml && xml.firstChild && xml.hasChildNodes() &&
				  !(xml.firstChild &&
					xml.firstChild.firstChild &&
					xml.firstChild.firstChild.firstChild &&
					xml.firstChild.firstChild.firstChild.nodeName == "parsererror")) {
				self.response(xml);
				xml = null;
				return;
			}

			xml = null;
			self.response(self._http.responseText);
		}
	};

	/**
	 * Allows to process the received data.
	 *
	 * @param result (Object) The downloaded data (XML DOMDocument object).
	 */

	obj.response = function(result) {
		if (this.$owner) { this.$owner.refresh() }
	};

	/**
	 * Indicates whether the request is already completed.
	 */

	obj.isReady = function() {
		return this._ready;
	};
};
/**
 * Anobis Network Table Model For Loading and Parsing Data in CSV Text Format.
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-27 - 07:32:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.CSV.Table = ANet.HTTP.Request.subclass();
ANet.CSV.Table.create = function() {
	var obj = this.prototype;
	var _super = this.superclass.prototype;

	/**
	 * Allows to process the received text.
	 *
	 * @param text (String) The downloaded text.
	 */

	obj.response = function(text) {
		var i, s, table = [];

		this._rows = text.split(/\r*\n/);

		if (this.$owner) {
			this.$owner.clearSelectionModel();
			this.$owner.clearSortModel();
			this.$owner.clearRowModel();
			this.$owner.setRowCount(this.getCount());
			this.$owner.refresh();
		}

		//_super.response.call(this);
	};

	obj._rows = [];
	obj._data = [];
	obj._formats = [];

	/**
	 * Allows to specify the formatting object for the column.
	 *
	 * @param format (Object) The formatting object.
	 * @param index (Index) The column index.
	 */

	obj.setFormat = function(format, index) {
		this._formats = this._formats.concat();
		this._formats[index] = format;
	};

	/**
	 * Allows to specify the formatting objects for each column.
	 *
	 * @param formats (Array) The array of formatting objects.
	 */

	obj.setFormats = function(formats) {
		this._formats = formats;
	};

	/**
	 * Returns the number of data rows.
	 */

	obj.getCount = function() {
		return this._rows.length;
	};

	/**
	 * Returns the index.
	 */

	obj.getIndex = function(i) {
		return i;
	};

	var pattern = new RegExp("(^|\\t|,)(\"*|'*)(.*?)\\2(?=,|\\t|$)", "g");

	/**
	 * Returns the cell text.
	 *
	 * @param r (Index) Row index.
	 * @param c (Index) Column index.
	 */

	obj.getData = function(c, r) {
		if (!this._data[r]) {

			var s = this._rows[r].replace(/""/g, "'");
			s = s.replace(pattern, "$3\t");
			s = s.replace(/\t$/, "");
			this._data[r] = s ? s.split(/\t/) : [];
		}

		return this._data[r][c];
	};

	/**
	 * Returns the cell text.
	 *
	 * @param i (Index) Row index.
	 * @param j (Index) Column index.
	 */

	obj.getText = function(i, j) {
		var data = this.getData(i, j) || "";
		var format = this._formats[i];
		return format ? format.dataToText(data): data.replace(ANet.textPattern, ANet.textReplace);
	};

	/**
	 * Returns the cell image.
	 *
	 * @param i (Index) Row index.
	 * @param j (Index) Column index.
	 */

	obj.getImage = function() {
		return "";
	};

	/**
	 * Returns the cell hyperlink.
	 *
	 * @param i (Index) Row index.
	 * @param j (Index) Column index.
	 */

	obj.getLink = function() {
		return "";
	};

	/**
	 * Returns the cell value.
	 *
	 * @param i (Index) Row index.
	 * @param j (Index) Column index.
	 */

	obj.getValue = function(i, j) {
		var data = this.getData(i, j) || "";
		var format = this._formats[i];
		return format ? format.dataToValue(data): data;
	};

	obj.getFormat = function(i) {
		return this._formats[i];
	};
};
/**
 * Anobis Network Tabel Model For Loading and Parsing XML Data
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 14:36:01
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.XML.Table = ANet.HTTP.Request.subclass();
ANet.XML.Table.create = function() {
	var obj = this.prototype;
	var _super = this.superclass.prototype;

	if (ANet.gecko) {
		var xpath = new XPathEvaluator();
	}

	/**
	 * Allows to process the received data.
	 *
	 * @param xml (DOMDocument) The received data.
	 */

	obj.response = function(xml) {
		this.setXML(xml);

		if (this.$owner) {
			this.$owner.clearSelectionModel();
			this.$owner.clearSortModel();
			this.$owner.clearRowModel();
			this.$owner.setRowCount(this.getCount());
			this.$owner.refresh();
		}

		//_super.response.call(this);
	};

	/**
	 * Sets or retrieves the XML document (or string).
	 */

	obj.defineProperty("XML");

	obj.setXML = function(xml) {
		if (!xml.nodeType) {
			var s = "" + xml;

			xml = new ActiveXObject("MSXML2.DOMDocument");
			xml.loadXML(s);
		}

		xml.setProperty("SelectionLanguage", "XPath");

		if (this._namespaces) { xml.setProperty("SelectionNamespaces", this._namespaces); }

		this._xml = xml;
		this._data = this._xml.selectSingleNode(this._dataPath);
		this._items = this._data ? this._data.selectNodes(this._itemPath): null;
		this._ready = true;
	};

	if (ANet.gecko) {
		obj.setXML = function(xml) {

			if (!xml.nodeType) {
				var parser = new DOMParser;
				xml = parser.parseFromString("" + xml, "text/xml");
			} else if (xml.nodeName == "XML" && xml.ownerDocument == document) {
				var node = xpath.evaluate("*", xml, null, 9, null).singleNodeValue;
				xml = document.implementation.createDocument("", "", null);
				xml.appendChild(node);
			}

			namespaces = {};
			var a = this._namespaces.split(" xmlns:");

			for (var i = 1; i < a.length; i++) {
				var s = a[i].split("=");
				namespaces[s[0]] = s[1].replace(/\"/g, "");
			}

			this._ns = {
				lookupNamespaceURI: function(prefix) { return namespaces[prefix] }
			};

			this._xml = xml;
			this._data = xpath.evaluate(this._dataPath, this._xml, this._ns, 9, null).singleNodeValue;
			this._items = this._data ? xpath.evaluate(this._itemPath, this._data, this._ns, 7, null): null;
			this._ready = true;
		};
	}

	obj.getXML = function() {
		return this._xml;
	};

	obj._dataPath = "*";
	obj._itemPath = "*";
	obj._valuePath = "*";
	obj._valuesPath = [];
	obj._formats = [];

	/**
	 * Sets the XPath expressions to retrieve values for each column.
	 *
	 * @param array (Array) The array of XPaths expressions.
	 */

	obj.setColumns = function(array) {
		this._valuesPath = array;
	};

	/**
	 * Specifies the XPath expression to retrieve the set of rows.
	 *
	 * @param xpath (String) The xpath expression.
	 */

	obj.setRows = function(xpath) {
		this._itemPath = xpath;
	};

	/**
	 * Specifies the XPath expression to select the table root element.
	 *
	 * @param xpath (String) The xpath expression.
	 */

	obj.setTable = function(xpath) {
		this._dataPath = xpath;
	};

	/**
	 * Allows to specify the formatting object for the column.
	 *
	 * @param format (Object) The formatting object.
	 * @param index (Index) The column index.
	 */

	obj.setFormat = function(format, index) {
		this._formats = this._formats.concat();
		this._formats[index] = format;
	};

	/**
	 * Allows to specify the formatting objects for each column.
	 *
	 * @param formats (Array) The array of formatting objects.
	 */

	obj.setFormats = function(formats) {
		this._formats = formats;
	};

	/**
	 * Returns the number of the data rows.
	 */

	obj.getCount = function() {
		if (!this._items) { return 0 }
		return ANet.gecko ? this._items.snapshotLength: this._items.length;
	};

	/**
	 * Returns the index.
	 */

	obj.getIndex = function(i) {
		return i;
	};

	/**
	 * Returns the cell text.
	 *
	 * @param i (Index) Row index.
	 * @param j (Index) Column index.
	 */

	obj.getText = function(i, j) {
		var node = this.getNode(i, j);
		var data = node ? (ANet.ie ? node.text: node.textContent): "";
		var format = this._formats[i];

		return format ? format.dataToText(data): data.replace(ANet.textPattern, ANet.textReplace);
	};

	/**
	 * Returns the cell image.
	 *
	 * @param i (Index) Row index.
	 * @param j (Index) Column index.
	 */

	obj.getImage = function() {
		return "none";
	};

	/**
	 * Returns the cell hyperlink.
	 *
	 * @param i (Index) Row index.
	 * @param j (Index) Column index.
	 */

	obj.getLink = function() {
		return "";
	};

	/**
	 * Returns the cell value.
	 *
	 * @param i (Index) Row index.
	 * @param j (Index) Column index.
	 */

	obj.getValue = function(i, j) {
		var node = this.getNode(i, j);
		var data = node ? (ANet.ie ? node.text: node.textContent): "";
		var format = this._formats[i];

		return format ? format.dataToValue(data): data;
	};

	/**
	 * Returns the cell XML node text (internal).
	 *
	 * @param i (Index) Row index.
	 * @param j (Index) Column index.
	 */

	obj.getNode = function(j, i) {
		if (!this._items || !this._items[i]) {
			return null;
		}

		if (this._valuesPath[j]) {
			return this._items[i].selectSingleNode(this._valuesPath[j]);
		} else {
			return this._items[i].selectNodes(this._valuePath)[j];
		}
	};

	if (ANet.gecko) {
		obj.getNode = function(c, r) {
			if (!this._items) { return null }

			var row = this._items.snapshotItem(r);

			if (!row) { return null }

			if (this._valuesPath[c]) {
				return xpath.evaluate(this._valuesPath[c], row, this._ns, 9, null).singleNodeValue;
			} else {
				return xpath.evaluate(this._valuePath, row, this._ns, 7, null).snapshotItem(c);
			}
		};
	}

	obj.getFormat = function(i) {
		return this._formats[i];
	};
};
/**
 * Anobis Network TreeView Data Model For Loading and Parsing XML Data
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 14:55:23
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.XML.TreeView = ANet.HTTP.Request.subclass();
ANet.XML.TreeView.create = function() {
	var obj = this.prototype;
	var _super = this.superclass.prototype;

	/**
	 * Allows to process the received data.
	 *
	 * @param xml (DOMDocument) The received data.
	 */

	obj.response = function(xml) {
		this.setXML(xml);
		_super.response.call(this);
	};

	/**
	 * Sets or retrieves the XML document (or string).
	 */

	obj.defineProperty("XML");

	obj.setXML = function(xml) {
		if (!xml.nodeType) {
			var s = "" + xml;

			xml = window.ActiveXObject ? new ActiveXObject("MSXML2.DOMDocument"): new XMLDocument;
			xml.loadXML(s);
		}

		xml.setProperty("SelectionLanguage", "XPath");

		if (this._namespaces) { xml.setProperty("SelectionNamespaces", this._namespaces); }

		this._xml = xml;
		this._data = this._xml.selectSingleNode(this._dataPath);
		this._items = this._data ? this._data.selectNodes(this._itemPath): null;

		/*
		 * Parse data and set status to ready
		 */

		this.parseData();
		this._ready = true;
	};

	obj.getXML = function() {
		return this._xml;
	};

	obj._dataPath = "*";
	obj._itemPath = "*";
	obj._valuePath = "*";
	obj._valuesPath = [];
	obj._formats = [];

	/**
	 * Sets the XPath expressions to retrieve values for each item.
	 *
	 * @param array (Array) The array of XPaths expressions.
	 */

	obj.setValuesPath = function(array) {
		this._valuesPath = array;
	};

	/**
	 * Specifies the XPath expression to select the treeview root element.
	 *
	 * @param xpath (String) The xpath expression.
	 */

	obj.setDataPath = function(xpath) {
		this._dataPath = xpath;
	};

	/**
	 * Returns the number of the data rows.
	 */

	obj.getCount = function() {
		if (!this._items) { return 0 }
		return this._items.length;
	};

	/**
	 * Returns the index.
	 */

	/**
	 * Returns the action to fire
	 */

	obj._actions = [];
	obj.getAction = function(i) {
		return this._actions[i];
	};

	/**
	 * Parse the items
	 */

	obj.parseData = function() {
		var data = [];

		this._valuesPath = ["id", "parent", "caption", "action", "target", "expicon", "colicon", "edit", "link"];

		for (var i = 0; i < this.getCount(); i++) {
			data[i] = new Array();

			for (var j = 0; j < this._valuesPath.length; j++)
				data[i][j] = this.getValue(i, j);

			if (data[i][3] != null) {
				/**
				 * Cache the action to fire as string and replace
				 * the string by a function which will evaluate the
				 * action when requested by the event.
				 */

				this._actions[i] = data[i][3];
				data[i][3] = function(i) { eval(this.getItemProperty("action", i)) };
			} else {
				data[i][3] = this.getValue(i, 8);
			}
		}

		this.$owner.setItemData(data);
		data = null;
	};

	/**
	 * Returns the item value.
	 *
	 * @param i (Index) Row index.
	 * @param j (Index) Column index.
	 */

	obj.getValue = function(i, j) {
		var node = this.getNode(i, j);
		var data = node ? node.text: null;

		return data != "" ? data: null;
	};

	/**
	 * Returns the item XML node text (internal).
	 *
	 * @param i (Index) Row index.
	 * @param j (Index) Column index.
	 */

	obj.getNode = function(i, j) {
		if (!this._items || !this._items[i]) {
			return null;
		}

		if (this._valuesPath[j]) {
			return this._items[i].selectSingleNode(this._valuesPath[j]);
		} else {
			return this._items[i].selectNodes(this._valuePath)[j];
		}
	};
};
/**
 * Anobis Network Error Template (Displays Error Information)
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-27 - 07:59:47
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.Error = ANet.System.Template.subclass();
ANet.Templates.Error.create = function(){
	var obj = this.prototype;

	obj.setClass("error", "template");
	obj.setContent("title", "Error: ");
	obj.setContent("text", function() { return this.getErrorProperty("text") });
};
/**
 * Anobis Network Status Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-26 - 15:20:45
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.Status = ANet.System.Template.subclass();
ANet.Templates.Status.create = function() {
	/**
	 * Display status text/animation
	 */

	var obj = this.prototype;

	function _image() { return this.getStatusProperty("image") || "none" };
	function _text()	{ return this.getStatusProperty("text") }

	var image = new ANet.HTML.SPAN;
	image.setClass("status", "image");
	image.setClass("image", _image);

	obj.setClass("status", "template");
	obj.setContent("image", image);
	obj.setContent("text", _text);
};
/**
 * Anobis Network Item Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-23 - 13:09:23
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.Item = ANet.System.Template.subclass();
ANet.Templates.Item.create = function() {
	var obj = this.prototype;
	var span = ANet.HTML.SPAN;

	function _image() 		{ return this.getControlProperty("image") || "none" };
	function _text()			{ return this.getControlProperty("text") };
	function _tooltip()		{ return this.getControlProperty("tooltip") };

	function _selected()	{ return this.getStateProperty("selected") ? "item": null };
	function _inactive()	{ return this.getStateProperty("inactive") ? "item": null };
	function _disabled()	{ return this.getStateProperty("disabled") ? "item": null };
	function _default()		{ return this.getStateProperty("default") ? "item": null };
	function _blured()		{ return this.getStateProperty("blured") ? "item": null };

	var image = new span;
	image.setClass("item", "image");
	image.setClass("image", _image);

	var ruler = new span;
	ruler.setClass("item", "ruler");

	var text = new span;
	text.setClass("item", "text");
	text.setContent("html", _text);

	var box = new span;
	box.setClass("item", "box");

	/**
	 * The sign content gets used by the treeview control
	 * and the marker content gets used by the checkbox control
	 */

	box.setContent("sign", "");
	box.setContent("marker", "");
	box.setContent("image", image);
	box.setContent("ruler", ruler);
	box.setContent("text", text);
	box.setContent("shortcut", "");
	box.setContent("end", "");

	obj.setTag("span");
	obj.setClass("item", "template");
	obj.setClass("templates", "item");
	obj.setClass("default", _default);
	obj.setClass("disabled", _disabled);
	obj.setClass("inactive", _inactive);
	obj.setClass("selected", _selected);
	obj.setClass("blured", _blured);

	obj.setAttribute("tooltip", _tooltip);
	obj.setContent("box", box);
};
/**
 * Anobis Network List Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-26 - 13:00:34
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.List = ANet.System.Template.subclass();
ANet.Templates.List.create = function() {
	var obj = this.prototype;

	obj.setTag("span");
	obj.setClass("templates", "list");

	obj.setContent("start", "");
	obj.setContent("items", function() {
		var i, ii, a = [];
		var count = this.getViewProperty("count");
		var offset = this.getViewProperty("offset");
		var indices = this.getViewProperty("indices");

		for (i = 0; i < count; i++) {
			ii = indices ? indices[i + offset]: i + offset;
			a[i] = this.getItemTemplate(ii).toString()
		}

		return a.join("");
	});

	obj.setContent("end", "");
};
/**
 * Anobis Network CheckBox Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-26 - 08:08:24
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.CheckBox = ANet.Templates.Item.subclass();
ANet.Templates.CheckBox.create = function() {
	var obj = this.prototype;

	obj.setClass("value", function() { return this.getStateProperty("selected") || false });
	obj.setClass("disabled", function() { return this.getStateProperty("disabled") ? "toggle": null });
	obj.setClass("templates", "checkbox");
	obj.setClass("toggle", "checkbox");

	obj.setAttribute("anetx", "toggle");

	var marker = new ANet.HTML.SPAN;
	marker.setClass("item", "marker");

	obj.setContent("box/marker", marker);

	obj.onToggleClicked = function() {
		var selected = this.getStateProperty("selected");
		this.setStateProperty("selected", !selected);
		this.onToggle(!selected);
	};

	obj.onToggle = function(selected) {
	};
};
/**
 * Anobis Network CheckList Item Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-27 - 06:25:35
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.CheckListItem = ANet.Templates.CheckBox.subclass();
ANet.Templates.CheckListItem.create = function() {
	var obj = this.prototype;

	obj.setClass("templates", "checklistitem");

	obj.onToggleClicked = function() {
		var selected = this.getStateProperty("selected");
		this.setStateProperty("selected", !selected);
	}
};
/**
 * Anobis Network Image Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-09-12 - 10:46:23
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.Image = ANet.Templates.Item.subclass();
ANet.Templates.Image.create = function() {
	var obj = this.prototype;
	var box = obj.getContent("box");

	obj.setClass("templates", "image");

	box.setTag("");
	box.setContent("text", "");
};
/**
 * Anobis Network Input Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-11-20 - 09:07:45
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.Input = ANet.Templates.Item.subclass();
ANet.Templates.Input.create = function() {
	var obj = this.prototype;

	obj.setClass("templates", "input");
	obj.setClass("input", "box");
	obj.setClass("text", "");

	var text = new ANet.HTML.INPUT;

	text.setClass("item", "text");
	text.setAttribute("name", function() { return this.getId() });
	text.setAttribute("type", function() { return this.getControlProperty("type") });
	text.setAttribute("value", function() { return this.getControlProperty("text") });
	text.setAttribute("disabled", function() { return this.getStateProperty("disabled") });
	//text.setAttribute("tabindex", "-1");

	if (ANet.safari) {
		obj.setEvent("onselectstart", "");

		text = new ANet.HTML.DIV;
		text.setClass("item", "text");
		text.setAttribute("contentEditable", "true");
		text.setContent("html", function() { return this.getControlProperty("text") });
	}

	text.setEvent("onfocus", function() {
		var self = this;
		var e = this.getContent("box/text").element();

		this.old = ANet.safari ? e.innerText: e.value;

		function cancelBubble(event) {
			event.cancelBubble = true;
		}

		function updateText(event) {
			var text = ANet.safari ? e.innerText: e.value;
			var old = self.getControlProperty("text");

			if (text != old) {
				self.setControlProperty("text", text);
			}
		}

		this.$target = "";

		function mark(event) {
			if (ANet.srcElement(event) != e) {
				self.$target = true;
			}
		}

		e.parentNode.scrollTop = 0;

		if (ANet.ie) {
			ANet.attachEvent(e, "onselectstart", cancelBubble);
			ANet.attachEvent(e, "oncontextmenu", cancelBubble);
			ANet.attachEvent(e, "onpropertychange", updateText);

			e.setExpression("test", "this.value");
		}

		if (ANet.gecko) {
			ANet.attachEvent(e, "oninput", updateText);
		}

		if(ANet.safari) {
			ANet.attachEvent(e, "onDOMCharacterDataModified", updateText);
		}

		ANet.attachEvent(e, "onblur", blur);
		ANet.attachEvent(window, "onunload", blur);
		ANet.attachEvent(self.element(), "onmousedown", mark);

		function blur() {
			if (ANet.ie) {
				ANet.detachEvent(e, "onselectstart", cancelBubble);
				ANet.detachEvent(e, "oncontextmenu", cancelBubble);
				ANet.detachEvent(e, "onpropertychange", updateText);

				e.removeExpression("test");
			}

			if (ANet.gecko) {
				ANet.detachEvent(e, "oninput", updateText);
			}

			if (ANet.safari) {
				ANet.detachEvent(e, "onDOMCharacterDataModified", updateText);
			}

			ANet.detachEvent(e, "onblur", blur);
			ANet.detachEvent(window, "onunload", blur);
			ANet.detachEvent(self.element(), "onmousedown", mark);

			if (self.$target) {
				self.$target = false;
				self.setTimeout(function() {
					e.focus();
					e = null;
				});
			} else {
				e = null;
				self.$target = false;
				self.raiseEvent("update");

				if (self.hidePopup) {
					self.hidePopup();
				}
			}
		}
	});

	obj.setContent("box/text", text);
};
/**
 * Anobis Network Link Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-26 - 06:56:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.Link = ANet.Templates.Item.subclass();
ANet.Templates.Link.create = function() {
	var obj = this.prototype;
	var text = obj.getContent("box/text");

	text.setTag("a");
	text.setAttribute("tabIndex", "-1");
	text.setAttribute("href", function() { return this.getStateDisabled() ? null: "javascript:void(0)" });

	var clicked = function() {
		var _link = this.getControlProperty("link") || null;
		var _target =	this.getControlProperty("target") || "_self";

		if (this.getStateDisabled()) {
			return false;
		} else {
			window.open(_link, _target);
		}
	};

	obj.setEvent("onclick", function() {
		this.setTimeout(clicked, 1);
	});
};
/**
 * Anobis Network Popup Item Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-08-13 - 13:21:24
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.PopupItem = ANet.Templates.Item.subclass();
ANet.Templates.PopupItem.create = function() {
	var obj = this.prototype;

	var shortcut = new ANet.HTML.SPAN;
	shortcut.setClass("column", "2");
	shortcut.setClass("item", function() { return this.getItemProperty("shortcut") ? "shortcut": null });
	shortcut.setContent("html", function() { return this.getItemProperty("shortcut") });

	obj.setAttribute("tooltip", function() { return this.getItemProperty("tooltip") || null });
	obj.getContent("box/text").setClass("column", "1");
	obj.setContent("box/shortcut", shortcut);
};
/**
 * Anobis Network Popup Separator Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-08-15 - 07:48:34
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.PopupSeparator = ANet.Templates.Item.subclass();
ANet.Templates.PopupSeparator.create = function() {
	var obj = this.prototype;

	obj.setClass("item", "separator");
	obj.setContent("box", "");
};
/**
 * Anobis Network Radio List Item Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-08-15 - 14:38:45
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.RadioListItem = ANet.Templates.CheckBox.subclass();
ANet.Templates.RadioListItem.create = function() {
	var obj = this.prototype;

	obj.setClass("toggle", "radio");
	obj.onToggleClicked = null;
};
/**
 * Anobis Network Text Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-09-12 - 10:48:46
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.Text = ANet.Templates.Item.subclass();
ANet.Templates.Text.create = function() {
	var obj = this.prototype;
	var box = obj.getContent("box");

	obj.setClass("templates", "text");

	box.setTag("");
	box.setContent("image", "");
};
/**
 * Anobis Network TreeView Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-08-19 - 06:53:56
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.TreeView = ANet.System.Template.subclass();
ANet.Templates.TreeView.create = function() {
	var obj = this.prototype;

	/**
	 * Calculates the indices of the item nodes. Do NOT pass
	 * any parameters to this method as this one gets called
	 * recursively by itself!
	 *
	 * @param parent (String) Item parent
	 * @param level (Numeric) Item node level
	 * @param previousNode (Numeric) ID of the previous node
	 * @return childNode (Numeric) ID of the child node (if present)
	 */

	var index = 0;
	var nodes = [];
	var indices = [];

	obj.calcIndices = function(parent, level, previousNode) {
		var childNode = null;

		/**
		 * Reset the variables on the main call of this method
		 */

		if (level == null) {
			index = level = 0;
			previousNode = null;
		}

		for (var i = 0; i < this.getItemProperty("count"); i++) {
			/**
			 * Get all the items corresponding to the parent
			 */

			if (this.getItemProperty("data")[i][1] == parent) {
				nodes[i] = new Array();
				nodes[i]["index"] = index;
				nodes[i]["level"] = level;

				index++;

				/**
				 * In case we have a previous node on the same level
				 * as the current node then we set the current node ID
				 * as next node ID of the previous node and the previous
				 * node as previous node ID on the current node
				 */

				if (previousNode != null && nodes[previousNode]["level"] == level) {
					nodes[previousNode]["nextNode"] = i;
					nodes[i]["previousNode"] = previousNode;
				}

				/**
				 * Set the previous node ID to the current node ID for the
				 * next recursive call of this method
				 */

				previousNode = i;

				/**
				 * In case the child node ID is not set yet then
				 * set it to the current node ID. This step is required
				 * as we just want the child node ID of the first child
				 * node.
				 */

				if (childNode == null) {
					childNode = i;
				}

				/**
				 * In case we have a valid item ID then proceed the child
				 * node check (recursive call)
				 */

				if (this.getItemProperty("data")[i][0] != null) {
					nodes[i]["childNode"] = null;

					/**
					 * Call this method again with current item parent as parameter
					 * and increase the level by one.
					 */

					if ((node = this.calcIndices(this.getItemProperty("data")[i][0], level + 1, previousNode)) != null) {
						/**
						 * Set the child node ID in case we found a child node
						 */

						nodes[i]["childNode"] = node;
					}
				}

				/**
				 * Set the indices of the nodes as those are used
				 * by the keyboard navigation
				 */

				indices[nodes[i]["index"]] = i;
			}

			/**
			 * When we reached the last item on level 0 then set
			 * the nodes and indices and reset the variables to release
			 * some memory
			 */

			if (level == 0 && i == this.getItemProperty("count") - 1) {
				this.setItemProperty("nodes", nodes);
				this.setViewProperty("indices", indices);

				indices = [];
				nodes = [];
			}
		}

		/**
		 * Return the child node ID of the first child node item
		 * or NULL if there is no child node present
		 */

		return childNode;
	};

	obj.builtTree = function(parent, first) {
		if (first != false) {
			this.calcIndices();
		}

		var buffer = "";
		var temp = "";

		for (var i = 0; i < this.getItemProperty("count"); i++) {
			if (this.getItemProperty("data")[i][1] == parent) {
				var cookie = eval(this.getCookie(i));

				this.setViewProperty("expanded", cookie != null ? cookie: false, i);

				buffer += this.getItemTemplate(i).toString();

				if (this.getItemProperty("data")[i][0] != null) {
					temp = this.builtTree(this.getItemProperty("data")[i][0], false);

					if (temp != "") {
						var node = this.getNodeTemplate(i);
						node.setContent("html", temp);
						node.setStyle("display", this.getViewProperty("expanded", i) ? "block": "none");
						node.setStyle("text-indent", ((this.getItemProperty("nodes")[i]["level"] + 1) * 16) + 3);

						buffer += node;
					}
				}
			}
		}

		return buffer;
	};

	obj.setTag("span");
	obj.setContent("items", function() { return this.builtTree(null, true) });
};
/**
 * Anobis Network TreeView Item Template
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-08-19 - 12:50:36
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Templates.TreeViewItem = ANet.Templates.Item.subclass();
ANet.Templates.TreeViewItem.create = function() {
	var obj = this.prototype;

	var sign = new ANet.HTML.SPAN;
	sign.setClass("item", "sign");
	sign.setClass("sign", function() {
		return this.getItemProperty("nodes")[this.$0]["childNode"] ? (this.getViewProperty("expanded") ? "collapse": "expand"): "none";
	});

	sign.setEvent("onmousedown", function() {
		if (event.button == 1) { this.raiseEvent("toggle") }
	});

	sign.setEvent("onmouseup", function() {
		event.cancelBubble = true
	});

	var image = obj.getContent("box/image");
	image.setClass("image", function() {
		var state = this.getStateProperty("selected", this.$0);
		return (this.getItemProperty("data")[this.$0][state ? 6: 5] || "none");
	});

	obj.setContent("box/ruler", "");
	obj.setContent("box/sign", sign);
	obj.setContent("box/image", image);
};
/**
 * Anobis Network List Controllers
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-09-15 - 07:55:56
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controllers.ListItem = (function() {
	function _refresh(v, i) {
		this.getItemTemplate(i).refresh()
	}

	function _classes(v, i) {
		this.getItemTemplate(i).refreshClasses()
	}

	ANet.Controllers.ListState = {
		onStateDefaultChanged: _classes,
		onStateSelectedChanged: _classes,
		onStateInactiveChanged: _classes,
		onStateDisabledChanged: _classes,
		onStateBluredChanged: _classes
	};

	return {
		onItemTextChanged: _refresh,
		onItemImageChanged: _refresh,
		onItemValueChanged: _refresh,
		onItemLinkChanged: _refresh,
		onItemTargetChanged: _refresh,
		onItemTooltipChanged: _refresh,
		onItemShortcutChanged: _refresh,
		onItemIndentChanged: _refresh
	}
})();

ANet.Controllers.ListView = {
	onViewIndicesChanged: function(indices) {
		var positions = [];

		for (var i = 0;	i < indices.length;	i++) {
			positions[indices[i]] = i;
		}

		this.setViewPosition(positions);

		/**
		 * We must comment this command as this one causes a stack
		 * overflow when the treeview items get rendered.
		 */

		//this.refresh();
	}
};

ANet.Controllers.ListNavigation = (function() {
	function go(dir, select) {
		return function(event, index) {
			var undef, i = (dir == "this" && index != undef) ? index: this.getCurrentItem();

			switch (dir) {
				case "next": 			i = this.getViewNext(i); break;
				case "previous":	i = this.getViewPrevious(i); break;
				case "first":			i = this.getViewFirst(); break;
				case "last":			i = this.getViewLast(); break
			}

			/**
			 * In case the next item is disabled then return
			 */

			if (this.getStateDisabled(i)) { return }

			/**
			 * Save the next selected item but the current item
			 * must be set before selecting the item!
			 */

			this.setCurrentItem(i);
			if (select) { this.setSelectedItems([i]) }

			ANet.setReturnValue(event, false);
		}
	}

	function toggleThis(event, i) {
		this.setCurrentItem(i);
		this.setStateSelected(!this.getStateSelected(i), i);
	}

	function toggleCurrent() {
		var i = this.getCurrentItem();
		this.setStateSelected(!this.getStateSelected(i), i);
	}

	return {
		gotoThisItem: go("this"),
		gotoPreviousItem: go("previous"),
		gotoNextItem: go("next"),
		gotoPreviousPage: go("pageup"),
		gotoNextPage: go("pagedown"),
		gotoFirstItem: go("first"),
		gotoLastItem: go("last"),

		selectThisItem: go("this", true),
		selectPreviousItem: go("previous", true),
		selectNextItem: go("next", true),
		selectPreviousPage: go("pageup", true),
		selectNextPage: go("pagedown", true),
		selectFirstItem: go("first", true),
		selectLastItem: go("last", true),

		toggleThisItem: toggleThis,
		toggleCurrent: toggleCurrent
	}
})();

ANet.Controllers.ListMouse_1 = {
	onItemClicked: "selectThisItem"
};

ANet.Controllers.ListMouse_2 = {
	onItemClicked: "toggleThisItem"
};

ANet.Controllers.ListKeyboard_1 = {
	onKeyHome: "selectFirstItem",
	onKeyEnd: "selectLastItem",
	onKeyUp: "selectPreviousItem",
	onKeyDown: "selectNextItem",
	onKeyLeft: "selectPreviousItem",
	onKeyRight: "selectNextItem",
	onKeyPageUp: "selectPreviousPage",
	onKeyPageDown: "selectNextPage"
};

ANet.Controllers.ListKeyboard_2 = {
	onKeyHome: "selectFirstItem",
	onKeyEnd: "selectLastItem",
	onKeyUp: "selectPreviousItem",
	onKeyDown: "selectNextItem",
	onKeyPageUp: "selectPreviousPage",
	onKeyPageDown: "selectNextPage",

	onKeyCtrlHome: "gotoFirstItem",
	onKeyCtrlEnd: "gotoLastItem",
	onKeyCtrlUp: "gotoPreviousItem",
	onKeyCtrlDown: "gotoNextItem",
	onKeyCtrlPageUp: "gotoPreviousPage",
	onKeyCtrlPageDown: "gotoNextPage",
	onKeyCtrlSpace: "toggleCurrent",

	onKeySpace: "toggleCurrent"
};

ANet.Controllers.ListSelection = {
	onSelectionModeChanged: function(mode) {
		switch (mode) {
			case "single":
				this.setController("mouse", ANet.Controllers.ListMouse_1);
				this.setController("keyboard", ANet.Controllers.ListKeyboard_1);
				break;
			case "multi":
				this.setController("mouse", ANet.Controllers.ListMouse_2);
				this.setController("keyboard", ANet.Controllers.ListKeyboard_2);
				break;
		}
	}
};

ANet.Controllers.ListSelected = {
	onStateSelectedChanged: function(value, index) {
		var i, undef, a = this.getSelectedItems();

		if (index == undef) { return; }

		for (i = 0;	i < a.length;	i++) {
			if (a[i] == index) {
				if (!value) {
					a = a.concat();
					a.splice(i, 1);

					this.setSelectedItems(a);
				}

				return
			}
		}

		if (value) {
			a = a.concat(index);
			this.setSelectedItems(a)
		}
	},

	onSelectedItemsChanging: function(items2) {
		this.$items1 = this.getSelectedItems();
	},

	onSelectedItemsChanged: function(items2) {
		//var items1 = this.getSelectedItems();
		var items1 = this.$items1;

		/**
		 * The timeout function will cause an overload while navigating too
		 * fast through the items. To skip the timeout proceedure, we must
		 * set the current item before selecting this item.
		 */

		//this.setTimeout(function() {
			var i, r1 = {}, r2 = {};

			for (i = 0; i < items1.length; i++) { r1[items1[i]] = true; }
			for (i = 0; i < items2.length; i++) { r2[items2[i]] = true; }

			for (i = 0; i < items1.length; i++) {
				if (!r2[items1[i]] && this.getStateSelected(items1[i])) {
					/**
					 * Remove the onblur event for non-selected items
					 */

					if (this.$autoFocus) {
						var e = this.getItemTemplate(items1[i]).getContent("box/text").element();

						if (e) {
							e.onblur = null;
							e.onfocus = null;
						}

						e = null;
						this.setStateBlured(false, items1[i]);
					}

					this.setStateSelected(false, items1[i]);
				}
			}

			for (i = 0; i < items2.length; i++) {
				if(!r1[items2[i]] && !this.getStateSelected(items2[i])) {
					this.setStateSelected(true, items2[i]);

					/**
					 * Add the onblure event for all the selected items
					 */

					if (this.$autoFocus) {
						var e = this.getItemTemplate(items2[i]).getContent("box/text").element();

						if (e) {
							var self = this;
							var index = items2[i];

							e.onblur = function() {
								self.setStateBlured(true, index);
							};

							e.onfocus = function() {
								self.setStateBlured(false, index);
							};
						}

						e = null;
					}
				}
			}
		//})
	},

	onCurrentItemChanging: function(i2) {
		var i1 = this.getCurrentItem();

		/**
		 * The timeout function will cause an overload while navigating too
		 * fast through the items. To skip the timeout proceedure, we must
		 * set the current item before selecting this item and we must get
		 * the second (current item, i2) template after the first template!
		 */

		//this.setTimeout(function() {
			var e1 = this.getItemTemplate(i1).getContent("box/text").element();

			if (e1 && i1 != i2) {
				e1.tabIndex = -1
			}

			e1 = null;

			var e2 = this.getItemTemplate(i2).getContent("box/text").element();

			if (e2 && e2.focus) {
				e2.tabIndex = this.getTabIndex();

				if (this.$autoFocus) {
					e2.focus();
				}
			}

			e2 = null;
		//})
	}
};
/**
 * Anobis Network TreeView Controllers
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-09-17 - 07:29:45
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controllers.TreeView = {
	onEditorTemplateChanged: function(editor) {
		editor.setClass("item", "editor");
		editor.mapModel("control", "item");
	},

	onItemDataChanged: function(value) {
		this.setItemText(function(i) {
			return this.getItemData()[i][2];
		});

		this.setItemCount(value.length);
	},

	toggle: function(src, i) {
		this.setViewProperty("expanded", !this.getViewProperty("expanded", i), i);
	}
};

ANet.Controllers.TreeViewNavigation = (function() {
	function nav(dir) {
		return function(event, index) {
			var id = -1, i = (this.getCurrentItem() >= 0 ? this.getCurrentItem(): 0);
			var node = this.getItemProperty("nodes")[i];

			switch (dir) {
				case "this":
					id = index || this.getCurrentItem(); break;

				case "first":
					id = this.getViewFirst(); break;

				case "last":
					id = this.getViewLast(); break;

				case "up":
					var preNode = this.getItemProperty("nodes")[node["previousNode"]] || null;

					if (preNode && preNode["childNode"] && !this.getViewProperty("expanded", node["previousNode"])) {
						id = node["previousNode"];
					} else {
						id = this.getViewPrevious(i);
					}

					break;

				case "down":
					if (node["childNode"] && !this.getViewProperty("expanded", i)) {
						id = node["nextNode"];
					} else {
						id = this.getViewNext(i);
					}

					break;

				case "left":
					if (node["childNode"] && this.getViewProperty("expanded", i)) {
						this.setViewProperty("expanded", false, i);
					} else if (this.getItemProperty("nodes")[i]["level"] > 0) {
						var parent = this.getItemProperty("data")[i][1];

						if (parent != null) {
							for (var j = 0; j < this.getItemProperty("count"); j++) {
								if (this.getItemProperty("data")[j][0] == parent) {
									id = j;
									break;
								}
							}
						}
					}

					break;

				case "right":
					if (node["childNode"] && !this.getViewProperty("expanded", i)) {
						this.setViewProperty("expanded", true, i);
					} else if (node["childNode"] && this.getViewProperty("expanded", i)) {
						id = node["childNode"];
					}

					break;
			}

			if (id != -1) {
				this.setCurrentItem(id);
				this.setSelectedItems([id]);
			}

			this.getItemTemplate(i).refresh();
			this.getItemTemplate(id).refresh();
		}
	};

	return {
		navThis: nav("this"),
		navFirst: nav("first"),
		navLast: nav("last"),
		navUp: nav("up"),
		navDown: nav("down"),
		navLeft: nav("left"),
		navRight: nav("right")
	}
})();

ANet.Controllers.TreeViewMouse = {
	onItemMouseUp: "navThis"
};

ANet.Controllers.TreeViewKeyboard = (function() {
	function _refresh() {
		this.refresh();

		this.setTimeout(function() {
			this.element().focus();
		});
	}

	return {
		onKeyHome: "navFirst",
		onKeyEnd: "navLast",
		onKeyUp: "navUp",
		onKeyDown: "navDown",
		onKeyLeft: "navLeft",
		onKeyRight: "navRight",
		onKeyF2: "editCurrentItem",
		onKeyF5: _refresh
	}
})();

ANet.Controllers.TreeViewItem = {
	editCurrentItem: function() {
		var i = this.getCurrentItem();

		if (this.getItemProperty("data")[i][7] != true) { return }

		var item = this.getItemTemplate(i).getContent("box/text");
		var editor = new ANet.Controls.Input; //this.getEditorTemplate(i);

		alert(editor.getContent("box/text").element());
		//alert(editor.getContent("box/text"));

		if (item.element()) {
			ANet.setOuterHTML(item.element(), editor);
			//alert(editor.toString());
			//item.setContent(editor);

			this.setTimeout(function() {
				var text = editor.element().getElementsByTagName("input")[0];
				text.focus();
				text.select();
				text = null
			})
		}
	},

	update: function(text, i) {
		var item = this.getItemTemplate(i);
		var editor = this.getEditorTemplate(i);

		if (editor.element()) {
			//editor.element().outerHTML = item.getContent("box/text").element().outerHTML;
			item.refresh();
		}

		this.setTimeout(function() {
			this.element().focus()
		})
	}
};
/**
 * Anobis Network ImageText Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-23 - 18:23:56
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.ImageText = ANet.System.Control.subclass();
ANet.Controls.ImageText.create = function() {
	/**
	 * Define this control as default item template
	 */

	ANet.Templates.Item.create.call(this);

	var obj = this.prototype;

	obj.setClass("templates", "");
	obj.setClass("ui", "imagetext");
	obj.setClass("item", "control");
	obj.setClass("text", "expand");
	obj.setClass("disabled", function() { return this.getStateProperty("disabled") ? "imagetext": null });

	function _tabIndex() 	{ return this.getTabProperty("index") };

	obj.getContent("box/text").setAttribute("tabIndex", _tabIndex);

	obj.onInit = function(args) {
		var undef;

		if (args[0] != undef && args[0] != null) { this.setId(args[0]) }
		if (args[1] != undef && args[1] != null) { this.setControlImage(args[1]) }
		if (args[2] != undef && args[2] != null) { this.setControlText(args[2]) }
	}

	/**
	 * ImageText controllers
	 */

	function _refresh() {
		this.refresh();
	};

	function _classes() {
		this.refreshClasses();
	};

	obj.setController("item", {
		onControlTextChanged: _refresh,
		onControlImageChanged: _refresh,
		onControlValueChanged: _refresh,
		onControlLinkChanged: _refresh,
		onControlTargetChanged: _refresh,
		onControlTooltipChanged: _refresh,
		onControlShortcutChanged: _refresh
	});

	obj.setController("state", {
		onStateDefaultChanged: _classes,
		onStateSelectedChanged: _classes,
		onStateInactiveChanged: _classes,
		onStateDisabledChanged: _classes,
		onStateBluredChanged: _classes
	});
};
/**
 * Anobis Network List Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-26 - 08:46:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.List = ANet.System.Control.subclass();
ANet.Controls.List.create = function() {
	var obj = this.prototype;

	/**
	 * In case autoFocus is set to false then no focus is set while
	 * navigation through the items of a list. This is escpecially
	 * needed by the popup control to prevent a blur.
	 */

	obj.$autoFocus = true;

	obj.setAttribute("tabIndex", 1);
	obj.setAttribute("hideFocus", "true");

	obj.setClass("ui", "list");
	obj.setClass("list", "control");
	obj.setClass("flow", "vertical");
	obj.setClass("text", "normal");

	/**
	 * List box containing the list items
	 */

	var box = new ANet.HTML.SPAN;
	box.setClass("list", "box");
	box.setContent("html", function() {	return this.getLayoutTemplate()	});

	obj.setContent("box", box);

	/**
	 * When the item template changed then map the new list data
	 * model with the item template model
	 */

	obj.onItemTemplateChanged = function(item) {
		item.setClass("list", "item");

		item.setStyle("text-indent", function() {
			return (this.getItemProperty("indent", this.$0) > 0 ? this.getItemProperty("indent", this.$0) + "px": null)
		});

		item.setAttribute("anet", "item");
		item.mapModel("control", "item");
		item.mapModel("state", "state");
	};

	obj.onContentTemplateChanged = function(view) {
		view.setClass("list", "template");
	};

	/**
	 * Define list templates
	 */

	obj.defineTemplate("layout", function() {	return this.getScrollTemplate()	});
	obj.defineTemplate("scroll", function() {	return this.getContentTemplate() });
	obj.defineTemplate("content", new ANet.Templates.List);
	obj.defineTemplate("item", new ANet.Templates.Item);

	obj.onInit = function(args) {
		var undef;

		if (args[0] != undef && args[0] != null) { this.setId(args[0]) }
		if (args[1] != undef && args[1] != null) { this.setItemCount(args[1]) }
	};

	/**
	 * List navigation functions (next, previous, first and last)
	 */

	function viewNext(i, j) {
		/**
		 * When the next index is bigger than the total item count
		 * then return the last selected index
		 */

		if (Number(this.getViewPosition(i)) + 1 > this.getViewOffset() + this.getViewCount() - 1) {
			if (this.getNavigationMode() == "turn") {
				return this.getViewFirst();
			} else {
				return j || i;
			}
		}

		var p = Math.min(this.getViewPosition(i) + 1, this.getViewOffset() + this.getViewCount() - 1);
		var a = this.getViewIndices();
		var r = a ? a[p]: p;

		/**
		 * When the next item's state is disabled then navigate forward
		 * one more item
		 */

		if (this.getStateDisabled(r)) {
			r = viewNext.call(this, r, i);
		}

		return r;
	}

	function viewPrevious(i, j) {
		/**
		 * When the previous index is smaller than 0 then return the
		 * last selected index
		 */

		if (Number(this.getViewPosition(i)) - 1 < this.getViewOffset()) {
			if (this.getNavigationMode() == "turn") {
				return this.getViewLast();
			} else {
				return j || i;
			}
		}

		var p = Math.max(this.getViewPosition(i) - 1, this.getViewOffset());
		var a = this.getViewIndices();
		var r = a ? a[p]: p;

		/**
		 * When the previous item's state is disabled then navigate backward
		 * one more item
		 */

		if (this.getStateDisabled(r)) {
			r = viewPrevious.call(this, r, i);
		}

		return r;
	}

	function viewFirst(i) {
		var p = this.getViewOffset();
		var a = this.getViewIndices();
		var r = a ? a[p]: p;

		/**
		 * When the first item's state is disabled then navigate forward
		 * one more item
		 */

		if (this.getStateDisabled(r)) {
			r = viewNext.call(this, r);
		}

		return r;
	}

	function viewLast() {
		var p = this.getViewOffset() + this.getViewCount() - 1;
		var a = this.getViewIndices();
		var r = a ? a[p]: p;

		/**
		 * When the last item's state is disabled then navigate backward
		 * one more item
		 */

		if (this.getStateDisabled(r)) {
			r = viewPrevious.call(this, r);
		}

		return r;
	}

	function itemValue(i) {
		var text = this.getItemText(i);
		var format = this.getItemFormat(i);
		return format ? format.textToValue(text): text;
	}

	/**
	 * Define the list models
	 */

	var itemModel = {
		count: 0,
		text: "",
		image: "",
		link: "",
		target: "",
		value: itemValue,
		format: "",
		tooltip: "",
		shortcut: "",
		selected: false,
		indent: 0
	};

	var viewModel = {
		offset: 0,
		count: function() { return this.getItemCount() },
		position: function(i) { return Number(i) },
		next: viewNext,
		previous: viewPrevious,
		first: viewFirst,
		last: viewLast,
		endless: false,
		expanded: false
	};

	var navigationModel = { mode: "normal" }; /* Or turn */

	/**
	 * The selection mode is used to indicate whenever a single item
	 * or multiple items can get selected
	 */

	var selectionModel = { mode: "single" }; /* Or multiple */

	/**
	 * The selected model is a list containing all the selected items
	 * in multi selection mode or only the current selected item in
	 * single selection mode
	 */

	var selectedModel = {};

	/**
	 * The current model is used to save the current selected or active
	 * item in single as well as in multi selection mode
	 */

	var currentModel = { item: -1 };

	/**
	 * Define the list models
	 */

	obj.defineModel("item", itemModel);
	obj.defineModel("view", viewModel);
	obj.defineModel("navigation", navigationModel);
	obj.defineModel("selection", selectionModel);
	obj.defineModel("selected", selectedModel);
	obj.defineModel("current", currentModel);
	obj.defineViewProperty("indices", "", true);
	obj.defineSelectedProperty("items", [], true);

	/**
	 * Set list controllers
	 */

	obj.setController("item", ANet.Controllers.ListItem);
	obj.setController("state", ANet.Controllers.ListState);
	obj.setController("view", ANet.Controllers.ListView);
	obj.setController("mouse", ANet.Controllers.ListMouse_1);
	obj.setController("keyboard", ANet.Controllers.ListKeyboard_1);
	obj.setController("navigation", ANet.Controllers.ListNavigation);
	obj.setController("selection", ANet.Controllers.ListSelection);
	obj.setController("selected", ANet.Controllers.ListSelected);
};
/**
 * Anobis Network Button Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-26 - 06:38:16
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.Button = ANet.Controls.ImageText.subclass();
ANet.Controls.Button.create = function() {
	var obj = this.prototype;

	obj.setClass("ui", "button");
	obj.setClass("default", function() { return this.getStateProperty("default") ? "button": null });
	obj.setClass("disabled", function() { return this.getStateProperty("disabled") ? "button": null });

	obj.setAttribute("anetx", "button");

	/**
	 * Button controllers
	 */

	obj.setController("button", {
		onControlClicked: "onClick",
		onKeySpace: "onClick",
		onKeyEnter: "onClick"
	});
};
/**
 * Anobis Network CheckBox Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-26 - 08:06:34
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.CheckBox = ANet.Controls.ImageText.subclass();
ANet.Controls.CheckBox.create = function() {
	ANet.Templates.CheckBox.create.call(this);

	var obj = this.prototype;

	obj.setClass("ui", "checkbox");
	obj.setStateProperty("selected", false);
};
/**
 * Anobis Network CheckList Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-27 - 06:21:54
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.CheckList = ANet.Controls.List.subclass();
ANet.Controls.CheckList.create = function() {
	var obj = this.prototype;

	obj.setClass("ui", "checklist");
	obj.setItemTemplate(new ANet.Templates.CheckListItem);

	/**
	 * CheckList controllers
	 */

	obj.setController("keyboard", {
		onKeyHome: "gotoFirstItem",
		onKeyEnd: "gotoLastItem",
		onKeyUp: "gotoPreviousItem",
		onKeyDown: "gotoNextItem",
		onKeyPageUp: "gotoPreviousPage",
		onKeyPageDown: "gotoNextPage",
		onKeySpace: "toggleCurrent"
	});

	obj.setController("mouse", {
		onItemClicked: "gotoThisItem"
	});
};
/**
 * Anobis Network Dialog Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-02 - 08:16:29
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.Dialog = ANet.System.Control.subclass();
ANet.Controls.Dialog.create = function() {
	var obj = this.prototype;
	var span = ANet.HTML.SPAN;

	obj.setClass("ui", "dialog");
	obj.setTabIndex(-1);

	obj.onCaptionTemplateChanged = function(caption) {
		caption.mapModel("control", "caption");
	};

	/**
	 * Define the caption template
	 */

	obj.defineTemplate("caption", new ANet.Templates.Item);

	/**
	 * Define the models
	 */

	obj.defineModel("dialog", { URL: "", left: -1, top: -1, width: 0, height: 0, center: true, modal: false });
	obj.defineModel("caption", { text: "", image: "", tooltip: "" });

	/**
	 * Create the dialog window
	 */

	var caption = new span;
	caption.setClass("dialog", "caption");
	caption.setContent("caption", function() { return this.getCaptionTemplate() });

	var header = new span;
	header.setClass("dialog", "header");
	header.setContent("caption", caption);
	header.setEvent("onmousedown", function() {
		var obj = this.getContent("window");
		var el = obj.element();

		var offsetX = event.clientX - obj.getStyle("left");
		var offsetY = event.clientY - obj.getStyle("top");

		var doMove = function() {
			var x = event.clientX - offsetX;
			var y = event.clientY - offsetY;

			if (x < 0) { x = 0 };
			if (y < 0) { y = 0 };

			obj.setStyle("left", x);
			obj.setStyle("top", y);
		};

		var endMove = function() {
			ANet.detachEvent(el, "onmousemove", doMove);
			ANet.detachEvent(el, "onmouseup", endMove);
			ANet.detachEvent(el, "onlosecapture", endMove);
			ANet.releaseCapture(el);

			el = null;
		};

		ANet.attachEvent(el, "onmousemove", doMove);
		ANet.attachEvent(el, "onmouseup", endMove);
		ANet.attachEvent(el, "onlosecapture", endMove);
		ANet.setCapture(el);

		event.cancelBubble = true;
	});

	var frame = new ANet.HTML.IFRAME;
	frame.setClass("dialog", "frame");
	frame.setAttribute("tabIndex", -1);
	frame.setAttribute("frameborder", 0);
	frame.setAttribute("scrolling", "no");
	frame.setAttribute("src", function() { return this.getDialogProperty("URL") });

	var panelLeft = new span;
	panelLeft.setClass("panel", "left");

	var panelCenter = new span;
	panelCenter.setClass("panel", "center");
	panelCenter.setContent("frame", "");

	var panelRight = new span;
	panelRight.setClass("panel", "right");

	var body = new span;
	body.setClass("dialog", "body");
	body.setContent("left", panelLeft);
	body.setContent("center", panelCenter);
	body.setContent("right", panelRight);

	var footerBox = new span;
	footerBox.setClass("footer", "box");

	var footer = new span;
	footer.setClass("dialog", "footer");
	footer.setContent("box", footerBox);

	var dialogWindow = new span;
	dialogWindow.setClass("dialog", "window");
	dialogWindow.setContent("header", header);
	dialogWindow.setContent("body", body);
	dialogWindow.setContent("footer", footer);

	obj.setContent("window", dialogWindow);

	obj.onInit = function(args) {
		var undef, self = this;

		if (args[0] != undef && args[0] != null) { this.setId(args[0]) }

		var startResize = function() {
			self.setDialogLeft();
			self.setDialogTop();
		};

		function onunload() {
			ANet.detachEvent(window, "onresize", startResize);
			ANet.detachEvent(window, "onunload", onunload);
		};

		ANet.attachEvent(window, "onresize", startResize);
		ANet.attachEvent(window, "onunload", onunload);
	};

	obj.open = function(URL, width, height, icon, caption, modal) {
		this.setControlDisplay("block");

		this.setDialogURL(URL);
		this.setDialogWidth(width || 500);
		this.setDialogHeight(height || 260);
		this.setDialogModal(modal);

		this.setCaptionImage(icon);
		this.setCaptionText(caption || "");

		this.setContent("window/body/center/frame", frame);
		this.refresh();

		document.frames(frame.getId()).dialog = this;
	};

	obj.close = function() {
		this.setControlDisplay("none");

		this.setContent("window/body/center/frame", "");
		this.refresh();
	};

	/**
	 * Dialog controllers
	 */

	function _refresh() {
		this.refresh();
	}

	function _refreshCaption() {
		this.getCaptionTemplate().refresh();
	}

	function _refreshClasses() {
	}

	obj.setController("dialog", {
		onDialogURLChanged: _refresh,

		onDialogLeftChanged: function(x) {
			if (this.getDialogProperty("center")) {
				x = Math.round(ANet.scrollLeft(document.body) + (document.body.clientWidth / 2) - (this.getDialogWidth() / 2));
			}

			this.getContent("window").setStyle("left", x);
		},

		onDialogTopChanged: function(y) {
			if (this.getDialogProperty("center")) {
				y = Math.round(ANet.scrollTop(document.body) + (document.body.clientHeight / 2) - (this.getDialogHeight() / 2));
			}

			this.getContent("window").setStyle("top", y);
		},

		onDialogWidthChanged: function(width) {
			this.getContent("window").setStyle("width", width);

			if (this.getDialogProperty("center")) {
				this.setDialogLeft();
			}
		},

		onDialogHeightChanged: function(height) {
			this.getContent("window").setStyle("height", height);

			if (this.getDialogProperty("center")) {
				this.setDialogTop();
			}
		},

		onDialogCenterChanged: function(center) {
			if (center) {
				this.setDialogLeft();
				this.setDialogTop();
			}
		},

		onDialogModelChanged: function(modal) {
			this.setStyle("background", modal ? "url(none)": "none");
		}
	});

	obj.setController("caption", {
		onCaptionTextChanged: _refreshCaption,
		onCaptionImageChanged: _refreshCaption,
		onCaptionTooltipChanged: _refreshCaption
	});

	obj.setController("state", {
		onStateDefaultChanged: _refreshClasses,
		onStateSelectedChanged: _refreshClasses,
		onStateInactiveChanged: _refreshClasses,
		onStateDisabledChanged: _refreshClasses
	});
};
/**
 * Anobis Network Group Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-24 - 08:24:15
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.Group = ANet.Controls.ImageText.subclass();
ANet.Controls.Group.create = function() {
	var obj = this.prototype;

	obj.setTag("fieldset");
	obj.setClass("ui", "group");
	obj.setClass("text", "normal");
	obj.setClass("disabled", function() { return this.getStateProperty("disabled") ? "group": null });

	obj.setTabIndex(-1);

	var box = obj.getContent("box");
	box.setTag("legend");
	box.setClass("item", "legend");
};
/**
 * Anobis Network Image Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-10-15 - 06:03:45
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.Image = ANet.Controls.ImageText.subclass();
ANet.Controls.Image.create = function() {
	var obj = this.prototype;

	obj.setClass("ui", "image");
	obj.setClass("disabled", function() { return this.getStateProperty("disabled") ? "image": null });
	obj.setClass("templates", function() { return null });

	obj.setTabIndex(-1);

	var box = obj.getContent("box");

	box.setTag("");
	box.setContent("text", "");
	box.setContent("ruler", "");

	function _tooltip() { return this.getControlProperty("tooltip") || null };

	obj.setAttribute("tooltip", _tooltip);

	/**
	 * Image controllers
	 */

	function _refresh() {
		this.refresh();
	};

	function _classes() {
		this.refreshClasses();
	};

	obj.setController("image", {
		onControlImageChanged: _refresh,
		onControlValueChanged: _refresh,
		onControlLinkChanged: _refresh,
		onControlTargetChanged: _refresh,
		onControlTooltipChanged: _refresh
	});

	obj.setController("state", {
		onStateDisabledChanged: _classes
	});
};
/**
 * Anobis Network Input Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-26 - 07:24:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.Input = ANet.Controls.ImageText.subclass();
ANet.Controls.Input.create = function() {
	ANet.Templates.Input.create.call(this);

	var obj = this.prototype;
	obj.old = null;

	obj.setClass("ui", "input");
	obj.setClass("disabled", function() { return this.getStateProperty("disabled") ? "input": null });

	obj.defineControlProperty("type", "text");

	obj.onKeyEnter = function() {
		try {
			if (this.$owner) {
				this.$owner.element().focus();
				this.setTimeout(function() {
					this.$owner.element().focus();
				});
			} else {
				this.raiseEvent("update");
			}
		} catch(e) {}
	};

	obj.onChange = function(text) {
	};

	/**
	 * Input controllers
	 */

	var _update = function() {
		var text = this.getControlProperty("text");
		var format = this.getControlProperty("format");
		var value = format ? format.textToValue(text): text;

		this.setControlProperty("value", value);

		if (this.$owner) {
			this.$owner.raiseEvent("update", "", this.$0, this.$1);
		}

		if (text != this.old) {
			this.old = text;
			this.onChange(text);
		}
	};

	var _text = function() {
		var e = this.getContent("box/text").element();
		var text = this.getControlProperty("text");

		if (ANet.safari && e && e.innerText != text) {
			e.innerHTML = text;
		}

		if (!ANet.safari && e && e.value != text) {
			e.value = text;
		}
	};

	var _refresh = function() { this.refresh() };

	obj.setController("item", {
		update: _update,
		onControlTextChanged: _text,
		onControlImageChanged: _refresh,
		onControlValueChanged: _text,
		onControlLinkChanged: _refresh,
		onControlTooltipChanged: _refresh,
		onStateDisabledChanged: _refresh
	});
};
/**
 * Anobis Network Label Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-24 - 08:16:23
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.Label = ANet.Controls.ImageText.subclass();
ANet.Controls.Label.create = function() {
	var obj = this.prototype;

	obj.setClass("ui", "label");
	obj.setClass("disabled", function() { return this.getStateProperty("disabled") ? "label": null });

	obj.setTabIndex(-1);
};
/**
 * Anobis Network Link Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-26 - 07:05:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.Link = ANet.Controls.ImageText.subclass();
ANet.Controls.Link.create = function() {
	ANet.Templates.Link.create.call(this);

	var obj = this.prototype;
	obj.setClass("ui", "link");
	obj.setClass("disabled", function() { return this.getStateProperty("disabled") ? "link": null });
};
/**
 * Anobis Network Popup Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-08-05 - 07:34:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.Popup = ANet.Controls.List.subclass();
ANet.Controls.Popup.create = function() {
	var obj = this.prototype;

	obj.setClass("ui", "popup");
	obj.setClass("text", "expand");
	obj.setClass("flow", "vertical");

	obj.setItemTemplate(new ANet.Templates.PopupItem);

	obj.defineItemProperty("action", "");
	obj.defineItemProperty("target", "");

	obj.$autoFocus = false;

	obj.addItem = function() {
		var undef, i = this.getItemCount();

		this.setItemText(arguments[0] != undef ? arguments[0]: "", i);
		this.setItemImage(arguments[1] != undef ? arguments[1]: "", i);
		this.setItemTooltip(arguments[2] != undef ? arguments[2]: "", i);
		this.setItemShortcut(arguments[3] != undef ? arguments[3]: "", i);
		this.setItemAction(arguments[4] != undef ? arguments[4]: null, i);
		this.setItemTarget(arguments[5] != undef ? arguments[5]: null, i);

		this.setItemCount(i + 1);
	};

	obj.addSeparator = function() {
		var i = this.getItemCount();

		this.setItemTemplate(new ANet.Templates.PopupSeparator, i);
		this.getItemTemplate(i).setAttribute("anet", null);
		this.setStateDisabled(true, i);

		this.setItemCount(i + 1);
	}

	obj.onPaint = function() {
		var undef, imageShow = false, textWidth = 0, shortcutWidth = 0;

		for (i = 0; i < this.getItemCount(); i++) {
			var tmp = this.getItemTemplate(i);

			if (typeof tmp.getContent("box") == "object") {
				var e1 = tmp.getContent("box/text").element();
				var e2 = tmp.getContent("box/shortcut").element();

				if (e1 && e1.offsetWidth > textWidth) { textWidth = e1.offsetWidth }
				if (e2 && e2.offsetWidth > shortcutWidth) { shortcutWidth = e2.offsetWidth }
			}

			if ((this.getItemImage(i) != null || this.getItemImage(i) != undef) && this.getItemImage(i) != "") {
				imageShow = true;
			}
		}

		var ss = document.styleSheets[document.styleSheets.length - 1];
		var selector_0 = "#" + this.getId() + " .anet-item-image";
		var selector_1 = "#" + this.getId() + " .anet-column-1";
		var selector_2 = "#" + this.getId() + " .anet-column-2";
		var rules = ANet.getRules(ss);
		var set = [false, false, false];

		for (var i = 0; i < rules.length; i++) {
			if (set[0] && set[1] && set[2]) { return }

			if (rules[i].selectorText == selector_0) {
				rules[i].style.cssText = "display: " + (imageShow ? "inline-block!important": "none");
				set[0] = true;
			} else if (rules[i].selectorText == selector_1) {
				rules[i].style.width = textWidth;
				set[1] = true;
			} else if (rules[i].selectorText == selector_2) {
				rules[i].style.width = shortcutWidth;
				set[2] = true;
			}
		}

		if (!set[0]) { ANet.addRule(ss, selector_0, "display: " + (imageShow ? "inline-block!important": "none")) }
		if (!set[1]) { ANet.addRule(ss, selector_1, "width: " + textWidth + "px") }
		if (!set[2]) { ANet.addRule(ss, selector_2, "width: " + shortcutWidth + "px") }
	};

	obj.show = function(x, y) {
		if (this.getItemCount() > 0 && !ANet.srcElement(event).id.match(this.getId())) {
			this.setControlDisplay("block");
			this.onPaint();

			var el = this.element();
			var self = this;

			h = el.offsetHeight;
			w = el.offsetWidth;
			x = x || (ANet.scrollLeft(document.body) + event.clientX);
			y = y || (ANet.scrollTop(document.body) + event.clientY);
			i = document.body.scrollWidth || document.body.clientWidth;
			j = document.body.scrollHeight || document.body.clientHeight;

			this.setPosition((x + w > i ? i - w: x), (y + h > j ? j - h: y));

			el.focus();
			el.onblur = function() {
				x = el.style.pixelLeft;
				y = el.style.pixelTop;
				w = x + el.offsetWidth;
				h = y + el.offsetHeight;
				i = ANet.scrollTop(document.body);
				j = ANet.scrollLeft(document.body);

				if ((event.x + j < x || event.x + j > w) || (event.y + i < y || event.y + i > h)) {
					self.hide();
					el = null;
				} else if (self.getControlDisplay() == "block") {
					this.focus();
				}
			};
		}
	};

	obj.onItemMouseOver = function(item, index) {
		this.setCurrentItem(index);
		this.setSelectedItems([index]);
	};

	obj.hide = function() {
		this.setControlDisplay("none");

		this.setTimeout(function() {
			this.setCurrentItem(-1);
			this.setSelectedItems([]);
		});

		this.onHide();
	};

	obj.onHide = function() {
	};

	obj.onClick = function(item, index) {
		var undef;

		if (this.getItemAction(index) != undef) {
			if (typeof this.getItemAction(index) == "function") {
				this.getItemAction(index).call(this);
			} else if (typeof this.getItemAction(index) == "string") {
				window.open(this.getItemAction(index), this.getItemTarget(index) || "_self");
			}
		}
	};

	obj.onKeyEnter = function(item) {
		var i = this.getCurrentItem();

		if (!this.getStateDisabled(i) && !this.getStateInactive(i)) {
			this.hide();
			this.raiseEvent("onClick", item, i);
		}
	};

	obj.onKeyEscape = function() {
		this.hide();
	};

	obj.onItemClicked = function() {
		this.hide();
	};

	/**
	 * Popup controllers
	 */

	obj.setController("mouse", {
		onItemClicked: "onClick"
	});

	obj.setController("keyboard", {
		onKeyUp: "selectPreviousItem",
		onKeyDown: "selectNextItem"
	});
};
/**
 * Anobis Network Radio Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-08-15 - 14:00:56
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.Radio = ANet.Controls.ImageText.subclass();
ANet.Controls.Radio.create = function() {
	ANet.Templates.CheckBox.create.call(this);

	var obj = this.prototype;

	obj.setClass("ui", "radio");
	obj.setClass("toggle", "radio");

	obj.setStateProperty("selected", false);

	obj.onToggleClicked = function() {
		this.setStateProperty("selected", true);
		this.onSelect();
	};

	obj.onSelect = function(index) {
	};
};
/**
 * Anobis Network Radio List Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-08-15 - 14:37:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.RadioList = ANet.Controls.List.subclass();
ANet.Controls.RadioList.create = function() {
	var obj = this.prototype;

	obj.setClass("ui", "radiolist");
	obj.setItemTemplate(new ANet.Templates.RadioListItem);

	/**
	 * RadioList controllers
	 */

	obj.setController("keyboard", {
		onKeyHome: "gotoFirstItem",
		onKeyEnd: "gotoLastItem",
		onKeyUp: "gotoPreviousItem",
		onKeyDown: "gotoNextItem",
		onKeyPageUp: "gotoPreviousPage",
		onKeyPageDown: "gotoNextPage",
		onKeySpace: "selectThisItem"
	});
};
/**
 * Anobis Network Spin Edit Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-09-24 - 07:52:12
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.SpinEdit = ANet.Controls.Input.subclass();
ANet.Controls.SpinEdit.create = function() {
	var obj = this.prototype;
	var span = ANet.HTML.SPAN;

	obj.setClass("ui", "spinedit");
	obj.setClass("disabled", function() { return this.getStateDisabled() ? "spin": null });

	obj.defineModel("spin", { step: 1, min: 0, max: 0 });

	var spinUp = new span;
	spinUp.setClass("spin", "button");
	spinUp.setClass("button", "up");
	spinUp.setAttribute("anet", "spinup");
	spinUp.setEvent("onmousedown", function() {
		if (this.getStateDisabled()) { return }

		var e = this.getContent("box/end/up").element();
		this.getContent("box/text").element().focus();

		ANet.attachEvent(e, "onmouseup", stopInt);
		ANet.attachEvent(e, "onlosecapture", stopInt);
		ANet.setCapture(e);

		var self = this;

		function stopInt() {
			if (!e) { return }

			ANet.detachEvent(e, "onmouseup", stopInt);
			ANet.detachEvent(e, "onlosecapture", stopInt);
			ANet.releaseCapture(e);
			self.$target = false;

			window.clearInterval(int);
			e = null;
		}

		var int = this.setInterval(function() {
			this.raiseEvent("onKeyUp");
		}, 50);
	});

	var spinDown = new span;
	spinDown.setClass("spin", "button");
	spinDown.setClass("button", "down");
	spinDown.setAttribute("anet", "spindown");
	spinDown.setEvent("onmousedown", function() {
		if (this.getStateDisabled()) { return }

		var e = this.getContent("box/end/down").element();
		this.getContent("box/text").element().focus();

		ANet.attachEvent(e, "onmouseup", stopInt);
		ANet.attachEvent(e, "onlosecapture", stopInt);
		ANet.setCapture(e);

		var self = this;

		function stopInt() {
			if (!e) { return }

			ANet.detachEvent(e, "onmouseup", stopInt);
			ANet.detachEvent(e, "onlosecapture", stopInt);
			ANet.releaseCapture(e);
			self.$target = false;

			window.clearInterval(int);
			e = null;
		}

		var int = this.setInterval(function() {
			this.raiseEvent("onKeyDown");
		}, 50);
	});

	var box = new span;
	box.setClass("spin", "box");
	box.setContent("up", spinUp);
	box.setContent("down", spinDown);

	obj.setContent("box/end", box);

	obj.setEvent("onmousewheel", function() {
		this.getContent("box/text").element().focus();
		var delta = event.wheelDelta;

		this.setTimeout(function() {
			if (delta < 0) {
				this.raiseEvent("onKeyDown");
			} else {
				this.raiseEvent("onKeyUp");
			}
		});

		event.cancelBubble = true;
		ANet.setReturnValue(event, false);
	});

	/**
	 * SpinEdit controllers
	 */

	obj.setController("editor", {
		onKeyUp: function() {
			var value = Number(this.getControlText()) + Number(this.getSpinStep());

			if ((this.getSpinMin() != 0 || this.getSpinMax() != 0) && value > this.getSpinMax()) { return }
			this.setControlText(value);
		},

		onKeyDown: function() {
			var value = Number(this.getControlText()) - Number(this.getSpinStep());

			if ((this.getSpinMin() != 0 || this.getSpinMax() != 0) && value < this.getSpinMin()) { return }
			this.setControlText(value);
		}
	});
};
/**
 * Anobis Network Tabs Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-07-26 - 13:32:45
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

ANet.Controls.Tabs = ANet.Controls.List.subclass();
ANet.Controls.Tabs.create = function() {
	var obj = this.prototype;
	var line = new ANet.HTML.SPAN;

	obj.setClass("ui", "tabs");
	obj.setClass("text", "expand");
	obj.setClass("flow", "horizontal");

	line.setClass("top", "line");
	obj.setContent("line", line);

	obj.defineModel("panel", { content: "" });

	obj.onPanelTemplateChanged = function(panel) {
		panel.setClass("tabs", "panel");
	};

	obj.defineTemplate("panel", new ANet.System.Template);

	obj.defineTemplate("panels", function() {
		var buffer = "";

		for (var i = 0; i < this.getItemProperty("count"); i++) {
			var panel = this.getPanelTemplate(i);
			panel.setContent("html", this.getPanelProperty("content", i));

			buffer += panel.toString();
		}

		var panels = new ANet.HTML.SPAN;
		panels.setId(this.getId() + "-panels");
		panels.setEvent("oncontextmenu", "return false");
		panels.setEvent("onselectstart", "return false");
		panels.setClass("tabs", "panels");
		panels.setContent("html", buffer);

		return panels;
	});

	if (ANet.ie) {
		var paint = new ANet.HTML.SPAN;
		paint.setStyle("visibility", "expression(ANet.paint(this))");
		obj.setContent("paint", paint);
	}

	if (ANet.safari || ANet.opera) {
		obj.toString = function() {
			this.setTimeout(function() {
				this.raiseEvent("onPaint");
			}, 3000);

			return _super.toString.call(this);
		}
	}

	obj.onLoading = function() {
		if (!this._outerHTML) { this.outerHTML() }
		this._outerHTML += this.getPanelsTemplate();
	};

	obj.onPaint = function() {
		var e = this.element();

		if (e) {
			var o = ANet.object(this.getId() + "-panels");

			if (o) {
				o.setSize(e.offsetWidth, e.offsetHeight - 24);
				o.setPosition(e.offsetLeft, e.offsetTop + 24);
				o.setStyle("display", "block");
			}
		}

		this.getPanelTemplate(0).setStyle("display", "inline-block");
		this.raiseEvent("selectFirstItem");
	};

	obj.onStateSelectedChanging = function(v, i) {
		if (this.getCurrentItem() == i) {
			this.getPanelTemplate(i).setStyle("display", "inline-block");
		} else {
			this.getPanelTemplate(i).setStyle("display", "none");
		}
	};

	/**
	 * Tabs controllers
	 */

	function _refresh(v, i) {
		this.getPanelTemplate(i).setContent("html", this.getPanelProperty("content", i));
		this.getPanelTemplate(i).refresh();
	};

	obj.setController("panel", {
		onPanelContentChanged: _refresh
	});
};
/**
 * Anobis Network TreeView Control
 *
 * By Laroche Fabrice (Anobis Network Web and Software Developer)
 * flaroche@anobis.com
 *
 * Version 1.0.0 - 2005-06-28 - 08:04:35
 * Copyright (C) 2005, Anobis Network - All rights reserved.
 *
 * Revision History:
 *
 * Comments:
 */

/**
 *  TreeView Data Block
 *
 * Id							(String, Number)
 * Parent					(String, Number)
 * Caption				(String, Number)
 * Action/Link		(String, Function)
 * Link Target		(String)
 * Expand Icon		(String)
 * Collapse Icon	(String)
 * Allow Edit			(Boolean)
 */

ANet.Controls.TreeView = ANet.Controls.List.subclass();
ANet.Controls.TreeView.create = function() {
	var obj = this.prototype;
	//var xml = new ANet.XML.TreeView;

	obj.setClass("ui", "treeview");

	/**
	 * Redefine the list item and content templates
	 */

	obj.setItemTemplate(new ANet.Templates.TreeViewItem);
	obj.setContentTemplate(new ANet.Templates.TreeView);

	obj.setLayoutTemplate(function() {
		/*if (this.getItemProperty("URL") != "" && !this.getStatusProperty("done") && this.getStatusProperty("code") == "") {
			xml.setURL(this.getItemProperty("URL"));
			xml.request();

			this.setItemModel(xml);
		}*/

		//switch(this.getStatusProperty("code")) {
		//	case "":
		//		this.setStatusProperty("done", false);
				return this.getScrollTemplate();
		//	default:
		//		return this.getStatusTemplate();
		//}
	});

	/**
	 * Set the TreeView controllers
	 */

	obj.setController("item", ANet.Controllers.TreeViewItem);
	obj.setController("treeview", ANet.Controllers.TreeView);

	obj.setController("mouse", ANet.Controllers.TreeViewMouse);
	obj.setController("keyboard", ANet.Controllers.TreeViewKeyboard);
	obj.setController("navigation", ANet.Controllers.TreeViewNavigation);

	/**
	 * Define the templates and properties
	 */

	obj.defineTemplate("node", new ANet.System.Template);
	//obj.defineTemplate("status", new ANet.Templates.Status);
	obj.defineTemplate("editor", new ANet.Controls.Input);

	obj.defineItemProperty("data", "", []);
	obj.defineItemProperty("nodes", "", []);
	obj.defineItemProperty("action", "");
	obj.defineItemProperty("URL", "");

	/**
	 * Define the status model
	 */

	/*obj.defineModel("status");
	obj.defineStatusProperty("done", false);

	obj.defineStatusProperty("image", function() {
		switch(this.getStatusProperty("code")) {
			case "loading":
				return "loading";
			default:
				return "none";
		}
	});

	obj.defineStatusProperty("text", function() {
		switch(this.getStatusProperty("code")) {
			case "loading":
				return "Loading...";
			default:
				return "";
		}
	});

	obj.defineStatusProperty("code", function() {
		var items = this.getItemModel();

		if (!items.isReady()) {
			return "loading";
		}

		this.setStatusProperty("done", true);
		return "";
	});*/

	/**
	 * Handle TreeView events
	 */

	obj.setItems = function(data) {
		this.setItemData(data);
	};

	/*obj.onItemMouseUp = function(event, i) {
		if (event.button == 1 || event.button == 2) {
			if (event.button == 1) {
				this.setViewProperty("expanded", true, i);
			}

			var action = this.getItemProperty("data")[i][3];

			if (action != null) {
				if (typeof action == "function") {
					action.call(this, i);
				} else if (event.button == 1) {
					var target = this.getItemProperty("data")[i][4] || "_self";
					window.open(action, target);
				}
			}
		}
	};*/

	obj.onViewExpandedChanged = function(v, i) {
		this.setCookie(v, i);

		this.getItemTemplate(i).refresh();
		this.getNodeTemplate(i).setStyle("display", (v ? "block": "none"));
	};

	/**
	 * Returns the real item index or the index
	 * of the current selected item in case no ID is
	 * specified.
	 *
	 * @param id (String, Number) Item ID [optional]
	 */

	/*obj.getItemIndex = function(id) {
		var undef;

		if (id == undef) {
			return this.getCurrentItem();
		} else {
			for (var i = 0; i < this.getItemProperty("count"); i++) {
				if (this.getItemProperty("data")[i][0] == id) {
					return i;
				}
			}
		}

		return -1;
	};*/

	/**
	 * Public TreeView actions
	 */

	/*obj.edit = function() {
		this.raiseEvent("onKeyF2");
	};

	obj.toggle = function(id) {
		this.raiseEvent("toggle", null, this.getItemIndex(id));
	};

	obj.expand = function(id) {
		this.setViewProperty("expanded", true, this.getItemIndex(id));
	};

	obj.collapse = function(id) {
		this.setViewProperty("expanded", false, this.getItemIndex(id));
	};

	obj.expandAll = function() {
		for (var i in this.getItemNodes()) {
			this.setViewProperty("expanded", true, i);
		}
	};

	obj.collapseAll = function() {
		for (var i in this.getItemNodes()) {
			this.setViewProperty("expanded", false, i);
		}
	};*/
};
