﻿

/** Root namespace with basic tools @singleton */
Netxion = {__package:1};

/** The namespace for objects wich can collect items. @singleton */
Netxion.Collections = {__package:1};

/** The namespace for objects which generate checksums. @singleton */
Netxion.Checksum = {__package:1};

/** Drawing related objects @singleton */
Netxion.Drawing = {__package:1};

/** Data layer objects @singleton */
Netxion.Data = {__package:1};

/** SQL query parse result objects, <span style="color: red;">Experimental, currently used for quick testing a queryparser.</span> @singleton */
Netxion.Data.Sql = {__package:1};

/** Namespace for text based encryptions @singleton */
Netxion.Encryption = {__package:1};

/** Network objects, protocol related @singleton */
Netxion.Net = {__package:1};

/** Network messaging objects, protocol related @singleton */
Netxion.Net.Mail = {__package:1};

/** User Interface design package @singleton */
Netxion.Ui = {__package:1};

/** Animation package for user interfaces @singleton */
Netxion.Ui.Animation = {__package:1};

/** Data controlling user interfaces @singleton */
Netxion.Ui.Controls = {__package:1};

/** User interfaces wich obtain data @singleton */
Netxion.Ui.Controls.Input = {__package:1};

/** The devices package contains interfaces concerning devices @singleton */
Netxion.Ui.Devices = {__package:1};

/** Package wich cotains web related objects @singleton */
Netxion.Web = {__package:1};

/** XML related objects @singleton */
Netxion.Xml = {__package:1};

/** XML transform related objects @singleton */
Netxion.Xml.Xsl = {__package:1};

/** Database Markup Language package @singleton */
Netxion.Xml.Dbml = {__package:1};

/** Simple Object Access Protocol object context @singleton */
Netxion.Xml.Soap = {__package:1};

/** Rss related objects @singleton */
Netxion.Xml.Rss = {__package:1};

/**
* Event interface, supplies event stacking and execution. Supports the javascript native Function object and Netxion.Delegate, Netxion.TimedDelegate types.
* @created 12:34 AM 4/3/2008
* @modified 6:16 AM 4/16/2008
* @constructor
*/
Netxion.IEvent = function()
{
	/** Event by name collection, store the stack of Function objects by event name @type Function[] */
	this.events = {};

	/** Add a handler to an event by name */
	this.attachEvent = function(sName, vHandler)
	{
		if(!this.events[sName] || !this.events[sName].pop){this.events[sName] = [];}
		if(typeof vHandler == "undefined" || typeof vHandler.apply == "undefined" && typeof vHandler.execute == "undefined"){throw new Error("Netxion.IEvent.attachEvent: Invalid parameter specified, expected: Function or Delegate"); return;}
		this.events[sName].push(vHandler);
	};
	/** Insert a handler into the stack by next index or handler */
	this.insertEvent = function(sName, vHandler, vNext)
	{
		if(!this.events[sName] || !this.events[sName].pop){this.events[sName] = [];}
		if(typeof vHandler == "undefined" || typeof vHandler.apply == "undefined" && typeof vHandler.execute == "undefined"){throw new Error("Netxion.IEvent.attachEvent: Invalid parameter specified, expected: Function or Delegate"); return;}
		var intNext = this.getEventIndex(sName, vNext);
		if(vNext > -1)
		{
			var arr = this.events[sName].splice(intNext, this.events[sName].length - intNext);
			this.events[sName] = this.events[sName].concat(vHandler, arr);
			return;
		}
		this.events[sName].push(vHandler);
	};
	/** Remove an event from the stack by index or handler @type Function */
	this.detachEvent = function(sName, vSearch)
	{
		var intIndex = this.getEventIndex(sName, vSearch);
		if(intIndex>-1){return this.events[sName].splice(intIndex, 1)[0];}
		return null;
	};
	/** Drop the entire stack of functions by event name @type Function[] */
	this.clearEvent = function(sName)
	{
		if(this.events[sName] && this.events[sName].pop){return this.events[sName].splice(0, this.events[sName].length);}
		return [];
	};
	/** Execute all functions by event name and returns the last result @type Object*/
	this.fireEvent = function(sName, aArgs)
	{
		var varRet = null;
		aArgs = aArgs? aArgs: [];
		if(this.events[sName])
		{
			for(var i=0; i<this.events[sName].length; i++)
			{
				var evt = this.events[sName][i];
				if(evt)
				{
					if(evt.apply)
					{
						varRet = evt.apply(this, aArgs);
					}
					if(evt.execute)
					{
						evt.arguments = evt.arguments.concat(aArgs);
						varRet = evt.execute();
					}
				}
			}
		}
		return varRet;
	};
	/** Get an event index by name and handler @type Number */
	this.getEventIndex = function(sName, vHandler)
	{
		if(!this.events[sName] || !this.events[sName].pop){return -1;}
		
		for(e in this.events[sName])
			if(this.events[sName][e] == vHandler)
				return e;

		return -1;
	};
};

/** 
* Script info class, tracks state and enlists dependencies for scripts.
* After a script is downloaded it can be added to the engine with evaluate.
* @modified 9:01 AM 11/12/2007
* @created 9:01 AM 11/12/2007
* @constructor
*/
Netxion.Script = function(sName, bLoaded, bEvaluated)
{
	/** Script's filename @type String */
	this.name         = sName || "";
	/** Indication whether it's loaded @type Boolean */
	this.loaded       = bLoaded || false;
	/** Indication whether the script is evaluated @type Boolean */
	this.evaluated    = bEvaluated || false;
	/** Script text @type String */
	this.text         = "";
	/** Dependency list @type Netxion.Script[] */
	this.dependencies = [];

	/** Set the text attribute of the object and filters out dependencies */
	this.setText = function(sText)
	{
		this.text = sText.replace(/\/\*[^*]*\*+([^\/][^*]*\*+)*\//ig,"");

		var arr = this.text.match(/^netxion\.util\.include\(.*\);$/igm);
		this.text = this.text.replace(/^netxion\.util\.include\(.*\);$/igm,"");

		if(arr==null){return;}
		for(var i=0; i<arr.length; i++)
		{
			arr[i] = arr[i].substr(21).replace(/[\(\'\"\);]/ig,"");
			var obj = Netxion.Util.include(arr[i]);
			if(obj != null){this.dependencies.push(obj);}
		}

	};
};

/** 
* Logger interface suplies logging functionality to objects.
* @constructor 
* @modified 12:41 AM 2/7/2008
* @created 12:41 AM 2/7/2008
*/
Netxion.ILogger = function()
{
	/** Indicator whether the log is enabled, logWrite() does not add lines until this is set to true @type Boolean */
	this.logEnabled = false;
	/** Internal log array to wich lines are added @type String[] */
	this.log = [];
	/** Write an item to the log, time information will be added. */
	this.logWrite = function(sString)
	{
		if(!this.logEnabled){return;}
		this.log.push(this.logPrefix() + sString);
	};
	this.logPrefix = function()
	{
		var h,m,s,ms="0";
		var dtmNow = new Date();
		h = dtmNow.getHours().toString();
		m = dtmNow.getMinutes().toString();
		s = dtmNow.getSeconds().toString();
		ms = dtmNow.getMilliseconds().toString();
		h = h.length==2? h: "0" + h;
		m = m.length==2? m: "0" + m;
		s = s.length==2? s: "0" + s;
		ms = ms.length==1? ms + "00": ms.length==2? ms + "0": ms;
		return h + ":" + m + ":" + s + "." + ms + " ";
	};
	/** Clear the log */
	this.logClear = function()
	{
		this.log.splice(0, this.log.length);
	};
};

/** 
* Referencing objects to the global available list Netxion.Util.objects[].
* Furter it adds functionality to remove it and supplies a method for the global reference string.
* @constructor 
* @modified 10:00 AM 12/13/2007
* @created 10:00 AM 12/13/2007
*/
Netxion.IReference = function()
{
	/** Incremental pointer @type Number */
	this._ptr = -1;

	/** Register this object */
	this.register = function(){this._ptr = Netxion.Util.objects.push(this)-1;};

	/** Remove this object from registry */
	this.unregister = function()
	{
		Netxion.Util.objects.splice(this._ptr, 1); 
		for(var i=this._ptr; i<Netxion.Util.objects.length; i++){Netxion.Util.objects[i]._ptr=i;}
	};
	
	/** Global reference string @type String */
	this.referenceString = function(){return "Netxion.Util.objects[" + this._ptr.toString() + "]";};

	/** @ignore */
	this.main = function(){this.register();}; this.main();
};

/** 
* Netxion globalization class. Some objects require regional adjustments, these are held within a XML document and can be accessed with this object.
* <div style="color:red;">Not yet available</div>
* @singleton 
* @created 12:12 AM 07/14/2007
* @modified 12:12 AM 07/14/2007
*/
Netxion.Globalization = 
{
	file: "/classes/lang/1033.xml",
	xmlDocument: null,
	loaded: false,
	getText: function(sClassMember)
	{
		var strRet = null;
		var objNode = this.getNode(sClassMember);
		if(objNode!=null){strRet = objNode.getAttribute("text");}
		return strRet != null? strRet: "";
	},
	getTitle: function(sClassMember)
	{
		var strRet = null;
		var objNode = this.getNode(sClassMember)
		if(objNode!=null){strRet = objNode.getAttribute("title");}
		return strRet != null? strRet: "";
	},
	getNode: function(sClassMember)
	{
		if(!this.loaded){return null;}
		var arrPath = sClassMember.split(".");
		var objNode = this.xmlDocument;
		if(arrPath.length>0)
		{
			for(var i=0; i<arrPath.length; i++)
			{
				if(objNode == null){break;}
				objNode = objNode.getElementsByTagName(arrPath[i])[0];
			}
		}

		return objNode;
	},

	init: function()
	{
		if(this.file!="")
		{
			this.xmlDocument = Netxion.Util.getXmlDocument();
			this.xmlDocument.async = false;
			//this.loaded            = this.xmlDocument.load(this.file);
		}
	}
};

/** 
* Execute a function in a give context. Properties are all different types, therefor constructor arguments can be placed in any order.
* If the argument is a 'Function' type it will be the .task property.
* If the argument is a 'Array' type it will be the .arguments property.
* If the argument is a 'Object' type it will be the .context property.
* @constructor
* @requires Netxion.IReference
* @created 3:10 AM 4/6/2008
* @modified 3:10 AM 4/6/2008
*/
Netxion.Delegate = function(fTask, aArgs, oContext)
{
	/** @ignore */
	this.applyInterface = Netxion.IReference;
	this.applyInterface();

	/** Function to be executed after a certain time @type Number */
	this.task = null;
	/** Argument array @type Array */
	this.arguments = [];
	/** Context object to wich this task is applied @type Object */
	this.context = window;

	/** Execute this task */
	this.execute = function()
	{
		return this.task.apply(this.context, this.arguments);
	};

	/** @ignore */
	this.main = function(arguments)
	{
		var args = [];
		if(arguments.length == 1 && typeof arguments[0] == "object")
		{
			for(var i=0; i<arguments[0].length; i++){args.push(arguments[0][i]);}
		}
		else
		{
			for(var i=0; i<arguments.length; i++){args.push(arguments[i]);}
		}
		
		for(var i=0; i<args.length; i++)
		{
			var arg = args[i];
			if(typeof arg == "function"){this.task = arg;}
			if(typeof arg == "object" && arg.pop){this.arguments = arg;}
			if(typeof arg == "object" && !arg.pop){this.context = arg;}
		}
	}; this.main(arguments);
};

/**
* The TimedDelegate will run a task after a certain time in a given context.
* Due to the difference in property types arguments can be added in any order.
* If the argument is a 'Function' type it will be the .task property.
* If the argument is a 'Array' type it will be the .arguments property.
* If the argument is a 'Object' type it will be the .context property.
* If the argument is a 'Number' type it will be the .time property.
* If the argument is a 'Boolean' type and equals true, it will execute the delegate immediately.
* @extends Netxion.Delegate
* @requires Netxion.Delegate
* @constructor
* @created 3:30 AM 4/6/2008
* @modified 3:30 AM 4/6/2008
*/
Netxion.TimedDelegate = function(fTask, aArgs, oContext)
{
	/** @ignore */
	this.inheritFrom = Netxion.Delegate;
	this.inheritFrom(arguments);

	/** Time in milliseconds to delay the task @type Number */
	this.time = 0;
	/** Internal timer object */
	this._timer = null;

	/** Execute this function with after a certian timeout */
	this.execute = function()
	{
		this._timer = setTimeout("var obj=" + this.referenceString() + "; obj.task.apply(obj.context, obj.arguments);", this.time);
	};

	/** Cancel this task */
	this.cancel = function()
	{
		if(this._timer){clearTimeout(this._timer);}
	};

	/** @ignore */
	this.main = function(arguments)
	{
		var blnExecute = false;
		for(var i=0; i<arguments.length; i++)
		{
			var arg = arguments[i];
			if(typeof arg == "number"){this.time = arg;}
			if(typeof arg == "boolean"){blnExecute = arg;}
		}
		if(blnExecute){this.execute();}
	}; this.main(arguments);
};

/** 
* Netxion utillity class, supplies basic functionality such as debugging, script inclusion, current loaded script and more.
* @requires Netxion.Script
* @singleton 
* @modified 6:45 PM 4/2/2008
* @created 10:11 AM 04/04/2007
*/
Netxion.Util = 
{
	/** Debug indication, if set to true script's will be included with.src reference.
	* <div style="color:#FF0000;">This will throw an error in Internet Explorer browsers, debugging should be done with a Gecko browser.</div>
	* @type Boolean
	*/
	debug: false,

	/** Buffer scripts before loading, buffer should be used with the load and onload methods */
	buffer: true,

	/** Global object list, used for gobal identification eg. asynchronous operations @type Object[] */
	objects: [],

	/** List of warning add by the 'warn' method @type String[] */
	warnings: [],

	/** Reference to a pre tag created on first use of write() @type HTMLElement */
	_writePre: null,

	/** Internal interval wich checks scripts */
	_interval: null,

	/** Boot script name @type String */
	_boot: "Netxion.js",

	/** Script root path @type String */
	_root: "",

	/** XmlHttpRequest object for retrieving scripts @type XMLHttpRequest */
	_request: null,

	/** Current script loading @type Netxion.Script */
	_current: "",

	/** Indication whether the object is busy loading a script @type Boolean */
	_busy: false,

	_startTime: new Date(),
	loadTime: 0,

	/** Scripts collection object, scripts are referenced by filename @type Object */
	scripts: {},

	/** Include a script @type Netxion.Script */
	include: function(sScript)
	{
		if(sScript == null || sScript.length ==0){Netxion.Util.logWrite("Can't include '" + sScript + "'"); return null;}
		if(sScript.toLowerCase() in this.scripts){return this.scripts[sScript.toLowerCase()];}
		if(this._root.length == 0)
		{
			var arrScript = document.documentElement.getElementsByTagName("script");
			Netxion.Util.logWrite("Appending current scripts from HTMLHead (count: " + arrScript.length.toString() + ")");
			for(var i=0; i<arrScript.length; i++)
			{
				if(arrScript[i].src.length != 0)
				{
					var strName = arrScript[i].src.split("/").pop();
					if(!strName.toLowerCase() in this.scripts){this.scripts[strName.toLowerCase()] = new Netxion.Script(strName, true, true);}
					if(strName.toLowerCase() == this._boot.toLowerCase())
					{
						this._root = arrScript[i].src.substr(0, arrScript[i].src.length - this._boot.length);
						Netxion.Util.logWrite("Scripts root set to: '" + this._root + "'");
					}
				}
			}
		}
		if(this._request == null){this._request = Netxion.Util.getXmlHttpRequest();}

		if(this.debug)
		{
			var script   = document.createElement("script");
			script.type  = "text/javascript";
			script.src   = this._root + sScript; 
			script.defer = false;
			if(this._timeout){clearTimeout(this._timeout);}
			this._timeout = setTimeout("Netxion.Util.onload();", 500);
			document.getElementsByTagName("head")[0].appendChild(script);
			this.scripts[sScript.toLowerCase()] = sScript;
		}
		else
		{
			this.scripts[sScript.toLowerCase()] = new Netxion.Script(sScript);
			if(this._interval == null){this._interval = setInterval("Netxion.Util._checkscripts()", 10);}
			return this.scripts[sScript.toLowerCase()];
		}
	},

	/** Get the full script loaded @type String */
	getFullScript: function()
	{
		if(this._fullScript){return this._fullScript;}
		var arr = [];
		for(e in this.scripts){arr = arr.concat(this._getScriptRecursive(this.scripts[e]));}
		this._fullScript = arr.join(";\r\n");
		return this._fullScript;
	},

	_getScriptRecursive: function(oScript)
	{
		var arr = [];

		if(oScript._appended){return [];}
		oScript._appended = true;

		for(var i=0; i<oScript.dependencies.length; i++)
			if(!oScript.dependencies[i]._appended)
				arr = arr.concat(this._getScriptRecursive(oScript.dependencies[i]));

		arr.push(oScript.text);
		return arr;
	},

	/** Internal method for handeling XMLHttpRequest states */
	_requeststatechanged: function()
	{
		if(this._request.readyState == 4)
		{
			this._current.setText(this._request.responseText);
			this._current.loaded = true;
			this._busy = false;
			if(this._request.status>400){throw new Error("Failed to load '" + this._root + this.current.name + "' (HTTP" + this._request.status + ")"); return;}
		}
	},

	/** Internal method for handeling script loading and queueing */
	_checkscripts: function()
	{
		if(this._busy){return;}
		for(e in this.scripts)
		{
			if(!this.scripts[e].loaded)
			{
				this._current = this.scripts[e];
				this._busy = true;

				this._request.open("GET", this._root + this.scripts[e].name, true);
				this._request.onreadystatechange = new Function("Netxion.Util._requeststatechanged()");
				this._request.setRequestHeader("Content-Type", "text/plain");
				this._request.send(null);
				return;
			}
		}

		clearInterval(this._interval);
		eval(this.getFullScript());

		this.loadTime = new Date() - this._startTime;
		if(!this._loaded){this.onload(); this._loaded = true;}
	},

	/** Get a new XMLHttpRequest @type XMLHttpRequest */
	getXmlHttpRequest: function()
	{
		if(typeof XMLHttpRequest != "undefined"){return new XMLHttpRequest();} 
		if(typeof ActiveXObject != "undefined")
		{
			var progids = ["MsXml2.XmlHttp.6.0", "MsXml2.XmlHttp.4.0", "MsXml2.XmlHttp.3.0", "Microsoft.XmlHttp"];
			for(var i=0; i<progids.length; i++)
			{
				try{obj = new ActiveXObject(progids[i]); return obj;}
				catch(x){}
			}
		}
		return null;
	},

	/** Get a new XMLDocument, with optional the specified XML string loaded @type XMLDocument */
	getXmlDocument: function(sXml)
	{
		if(sXml && typeof DOMParser != "undefined"){return DOMParser.parseFromString(sXml, "text/xml");}
		if(navigator.appName.indexOf("Microsoft")==-1){return document.implementation.createDocument("", "", null);}
		if(typeof ActiveXObject != "undefined")
		{
			var progids = ["MsXml2.DomDocument.6.0", "MsXml2.DomDocument.4.0", "MsXml2.DomDocument.3.0", "Microsoft.XmlDom"];
			for(var i=0; i<progids.length; i++)
			{
				try
				{
					var obj = new ActiveXObject(progids[i]);
					if(sXml){obj.loadXML(sXml);}
					return obj;
				}
				catch(x){}
			}
		}
		return null;
	},

	/** Remove all loaded objects */
	unload: function()
	{
		for(var i=0; i<this.objects.length; i++)
		{
			if(this.objects[i].dispose instanceof Function){this.objects[i].dispose();}
			if(this.objects[i].element){this.objects[i].element = null;}
			this.objects[i] = null;
		}
		this.objects.splice(0, this.objects.length);
	},

	/** Event fires when all scripts have been evaluated */
	onload: function(){},

	/** When an exception isn't necessary and script progression is */
	warn: function(sString)
	{
		this.warnings.push(sString);
	},

	/** writes a line of debugging information */
	write: function(sString)
	{
		if(!this._writeElement)
		{
			this._writeElement = document.body.appendChild(document.createElement("div"));
			this._writeElement.style.cssText = "width:600px; height:300px; overflow:auto; border:dotted #999999 1px; color:#999999;";
		}
		var item = document.createElement("div");
		item.style.cssText = "padding:10px; font:12px 'Lucida Console';";
		item.appendChild(document.createTextNode(this.logPrefix() + sString));
		if(this._writeElement.childNodes.length>0){item.style.borderTop = "dotted #999999 1px";}
		if(this._writeElement.childNodes.length %2 == 1){item.style.backgroundColor = "#F9F9F9";}
		this._writeElement.appendChild(item);
		this._writeElement.scrollTop = this._writeElement.scrollHeight;
	},
	/** Generates an identifier */
	generateId: function(iLength)
	{
		var arrChar = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789").split();
		var arrRet  = [];
		iLength = parseInt(iLength);
		iLength = isNaN(iLength) || iLength<=0? 8: iLength;
		for(var i=0; i<iLength; i++)
		{
			arrRet.push(arrChar[parseInt(Math.random() * arrChar.length)]);
		}
		return arrRet.join("");
	},
	/** 
	* Extend supplied class with a target object. This will add a base object reference 'oTarget.base'. 
	* All none Function properties of the supplied class will be copied to the current object.
	* The Function type properties are wrapped in a new function wich call 'apply' on the base function substituting the base object with the target.
	* When refering to a base function use the apply merhod of that function.
	* It also adds a _class property, this property consists of the string representation of the class constructor between 'function' and '(', namespace paths can be seperated with a '$' symbol.
	*/
	extend: function(fnClass, oTarget)
	{
		oTarget._class = oTarget.constructor.toString();
		
		if(oTarget._class.indexOf("function") != -1){oTarget._class = oTarget._class.substr(oTarget._class.indexOf("function")+8);}
		if(oTarget._class.indexOf("(")!=-1){oTarget._class = oTarget._class.substr(0, oTarget._class.indexOf("("));}
		oTarget._class = oTarget._class.replace("$", ".");

		oTarget.base = new fnClass();
		for(e in oTarget.base)
		{
			if(e != "base" && e != "_class")
			{
				oTarget[e] = oTarget.base[e];
				if(oTarget.base[e].apply)
				{
					oTarget[e] = function(){this.base[e].apply(this, arguments);};
				}
			}
		}
	},
	init: function()
	{

	}
};
Netxion.Util.applyInterface = Netxion.ILogger;
Netxion.Util.applyInterface();