////////////////////////////////////////////////////////////////////////////////////////////
// Core client-side script
////////////////////////////////////////////////////////////////////////////////////////////

addNamespace("Core");
addNamespace("Core.Type");

////////////////////////////////////////////////////////////////////////////////////////////

Core.Enum = Class.create();
Core.Enum.prototype =
{
	initialize: function(type, value)
	{
		if (!type)
			return;
		
		if (value != null)
		{
			this.__value = value;
			return;
		}
		
		for (attr in this)
		{
			if (typeof this[attr] != "function" && this[attr] != null)
				this[attr] = eval("new " + type + "('" + type + "', " + Number(this[attr]) + ")");
		}
	},
	
	toString: function(value)
	{
		if (value == null)
			value = this.__value;
		
		if (value == null)
			return "[enum]";
		
		for (attr in this)
		{
			if (typeof this[attr] != "function" && this[attr] != null && 
				String(attr) != "__value" && eval(this[attr]) == Number(value))
				return String(attr);
		}

		if (value == 0)
			return "Unknown";
		
		return this.toString(0);
	},
	
	toJSON: function()
	{
		return "{\"__type\":\"System.Enum\",\"__value\":\"" + this.toString() + "\"}";
	}
};

////////////////////////////////////////////////////////////////////////////////////////////

Core.BrowserClass = Class.inherit(Core.Enum, 
{
	Unknown: 0,
	IE: 1,
	Netscape: 2,
	Opera: 3,
	Safari: 4,
	OmniWeb: 5,
	WebTV: 6,
	iCab: 7,
	Konqueror: 8,
	Firefox: 9
});
Core.Browser = new Core.BrowserClass("Core.BrowserClass");

////////////////////////////////////////////////////////////////////////////////////////////

Core.PlatformClass = Class.inherit(Core.Enum, 
{
	Unknown: 0,
	Windows: 1,
	Linux: 2,
	Unix: 3,
	Mac: 4
});
Core.Platform = new Core.PlatformClass("Core.PlatformClass");

////////////////////////////////////////////////////////////////////////////////////////////

Core.EnvironmentClass = Class.create();
Core.EnvironmentClass.prototype =
{
	initialize: function()
	{
		this._detect = navigator.userAgent.toLowerCase();
		
		if (this._checkIt("konqueror"))
		{
			this.browser = Core.Browser.Konqueror;
			this.platform = Core.Platform.Linux;
		}
		else if (this._checkIt("safari"))
			this.browser = Core.Browser.Safari;
		else if (this._checkIt("omniweb"))
			this.browser = Core.Browser.OmniWeb;
		else if (this._checkIt("opera"))
			this.browser = Core.Browser.Opera;
		else if (this._checkIt("webtv"))
			this.browser = Core.Browser.WebTV;
		else if (this._checkIt("icab"))
			this.browser = Core.Browser.iCab;
		else if (this._checkIt("msie"))
			this.browser = Core.Browser.IE;
		else if (!this._checkIt("compatible"))
		{
			this.browser = Core.Browser.Netscape;
			this.version = this._detect.charAt(8);
		}
		else
			this.browser = Core.Browser.Unknown;
		
		if (!this.version)
			this.version = this._detect.charAt(this._place + this._thestring.length);
		
		if (!this.platform)
		{
			if (this._checkIt("linux"))
				this.platform = Core.Platform.Linux;
			else if (this._checkIt("x11"))
				this.platform = Core.Platform.Unix;
			else if (this._checkIt("mac"))
				this.platform = Core.Platform.Mac;
			else if (this._checkIt("win"))
				this.platform = Core.Platform.Windows;
			else
				this.platform = Core.Platform.Unknown;
		}
		
		this._checkIt = this._detect = this._thestring = this._place = null;
	},
	
	_checkIt: function(string)
	{
		this._place = this._detect.indexOf(string) + 1;
		this._thestring = string;
		return this._place;
	}
};
Core.Environment = new Core.EnvironmentClass();

////////////////////////////////////////////////////////////////////////////////////////////

Core.Collection = Class.create();
Core.Collection.prototype =
{
	initialize: function()
	{
		this.items = new Array();
	},
	
	// determine if an item exists in the collection
	contains: function(id)
	{
		for (i = 0; i < this.items.length; i++)
		{
			if (this.items[i] != null && this.items[i].id == id)
				return true;
		}
		
		return false;
	},
	
	// get an item based on its id
	get: function(id)
	{
		for (i = 0; i < this.items.length; i++)
		{
			if (this.items[i] != null && this.items[i].id == id)
				return this.items[i];
		}
		
		return null;
	},
	
	// add an item to the collection
	add: function(item)
	{
		this.items.push(item);
	},
	
	// remove an item from the collection
	remove: function(id)
	{
		for (i = 0; i < this.items.length; i++)
		{
			if (this.items[i] != null && this.items[i].id == id)
			{
				this.items.splice(i, 1);
				return true;
			}
		}
		
		return false;
	}
};

////////////////////////////////////////////////////////////////////////////////////////////

Core.UtilityClass = Class.create();
Core.UtilityClass.prototype =
{
	initialize: function()
	{
	},
	
	getRootNode: function()
	{
		var root = document.body;
		while (root.parentElement != null)
			root = root.parentElement;
		return root;
	},
	
	setEvent: function(e)
	{
		if (!e) var e = window.event;
		this.lastEvent = e;
	},
	
	cancelEvent: function(e)
	{
		if (!e && this.lastEvent)
			e = this.lastEvent;
		else if (!e)
			e = window.event;
		
		if (window.event)
			e.returnValue = false;
		else if (e)
		{
			e.preventDefault();
			e.stopPropagation();
		}
	},
	
	getTarget: function(e)
	{
		if (!e && this.lastEvent)
			e = this.lastEvent;
		else if (!e)
			e = window.event;
			
		if(window.event) return e.srcElement;
		if(e) return e.target;
	},
	
	setText: function(obj, text)
	{
		if(obj == null) return;
		if(document.all)
			obj.innerText = text;
		else
			obj.textContent = text;
	},
	
	setHtml: function(obj, html)
	{
		if(obj == null) return;
		obj.innerHTML = html;
	},
	
	getClientX: function()
	{
		if (this.lastEvent == null)
			return 0;
		
		return this.lastEvent.clientX;
	},
	
	getClientY: function()
	{
		if (this.lastEvent == null)
			return 0;
		
		return this.lastEvent.clientY;
	},
	
	getClientTop: function()
	{
		if (document.documentElement && document.documentElement.scrollTop)
			return document.documentElement.scrollTop;
		else if (document.body.scrollTop)
			return document.body.scrollTop;
		else if (window.scrollY)
			return window.scrollY;
		
		return 0;
	},
	
	getClientLeft: function()
	{
		if (document.documentElement && document.documentElement.scrollLeft)
			return document.documentElement.scrollLeft;
		else if (document.body.scrollLeft)
			return document.body.scrollLeft;
		else if (window.scrollX)
			return window.scrollX;
		
		return 0;
	},
	
	getElementInnerX: function(obj, parent)
	{
		Element.makePositioned(obj);
		
		var curleft = 0;
		if (obj.offsetParent)
		{
			while (obj.offsetParent)
			{
				if (Core.Environment.browser == Core.Browser.IE)
				{
					if (Element.getStyle(obj, "border-left-style") != "none")
						curleft += this.fromSize(Element.getStyle(obj, "border-left-width"));
					
					curleft += this.fromSize(Element.getStyle(obj, "padding-left"));
				}
				
				curleft += obj.offsetLeft;
				obj = obj.offsetParent;
				
				if (obj == parent)
					break;
			}
		}
		else if (obj.x != null)
			curleft += obj.x;
		
		//Element.undoPositioned(obj);
		return curleft;
	},

	getElementInnerY: function(obj, parent)
	{
		Element.makePositioned(obj);
		
		var curtop = 0;
		if (obj.offsetParent)
		{
			while (obj.offsetParent)
			{
				if (Core.Environment.browser == Core.Browser.IE)
				{
					if (Element.getStyle(obj, "border-top-style") != "none")
						curtop += this.fromSize(Element.getStyle(obj, "border-top-width"));
					
					curtop += this.fromSize(Element.getStyle(obj, "padding-top"));
				}
				
				curtop += obj.offsetTop;
				obj = obj.offsetParent;
				
				if (obj == parent)
					break;
			}
		}
		else if (obj.y != null)
			curtop += obj.y;
		
		//Element.undoPositioned(obj);
		return curtop;
	},
	
	getElementInnerLocation: function(obj, parent)
	{
		return {left:this.getElementInnerX(obj, parent),top:this.getElementInnerY(obj, parent)};
	},
	
	getElementInnerBounds: function(obj, parent)
	{
		return {left:this.getElementInnerX(obj, parent),top:this.getElementInnerY(obj, parent),width:this.getElementInnerWidth(obj),height:this.getElementInnerHeight(obj)};
	},
	
	getElementInnerHeight: function(obj)
	{
		Element.makePositioned(obj);
		
		if (obj.offsetHeight)
			return obj.offsetHeight;
		
		//Element.undoPositioned(obj);
		return 0;
	},
	
	getElementInnerWidth: function(obj)
	{
		Element.makePositioned(obj);
		
		if (obj.offsetWidth)
			return obj.offsetWidth;
		
		//Element.undoPositioned(obj);
		return 0;
	},
	
	getElementInnerSize: function(obj)
	{
		return {width:this.getElementInnerWidth(obj),height:this.getElementInnerHeight(obj)};
	},
	
	
	
	
	_positionMe: function(obj)
	{
		/*if (obj._originalHeight == null)
		{
			Position.absolutize(obj);
			Position.relativize(obj);
			Position.absolutize(obj);
		}*/
		
		////Element.undoPositioned(obj);
	},
	
	getElementX: function(obj, parent)
	{
		Element.makePositioned(obj);
		
		var curleft = 0;
		if (obj.offsetParent)
		{
			while (obj.offsetParent)
			{
				/*if (Core.Environment.browser != Core.Browser.IE)
				{
					if (Element.getStyle(obj, "border-left-style") != "none")
						curleft -= this.fromSize(Element.getStyle(obj, "border-left-width"));
					
					curleft -= this.fromSize(Element.getStyle(obj, "padding-left"));
				}*/
				
				curleft += obj.offsetLeft;
				obj = obj.offsetParent;
				
				if (obj == parent)
					break;
			}
		}
		else if (obj.x != null)
		{
			curleft += obj.x;
		}
		
		//Element.undoPositioned(obj);
		return curleft;
	},

	getElementY: function(obj, parent)
	{
		Element.makePositioned(obj);
		
		var curtop = 0;
		if (obj.offsetParent)
		{
			while (obj.offsetParent)
			{
				/*if (Core.Environment.browser != Core.Browser.IE)
				{
					if (Element.getStyle(obj, "border-top-style") != "none")
						curtop -= this.fromSize(Element.getStyle(obj, "border-top-width"));
					
					curtop -= this.fromSize(Element.getStyle(obj, "padding-top"));
				}*/
				
				curtop += obj.offsetTop;
				obj = obj.offsetParent;
				
				if (obj == parent)
					break;
			}
		}
		else if (obj.y != null)
			curtop += obj.y;
		
		//Element.undoPositioned(obj);
		return curtop;
	},

	getElementLocation: function(obj, parent)
	{
		return {left:this.getElementX(obj, parent),top:this.getElementY(obj, parent)};
	},
	
	getElementHeight: function(obj)
	{
		return this.getElementInnerHeight(obj);// + this.getElementOffset(obj).Y;
	},
	
	getElementWidth: function(obj)
	{
		return this.getElementInnerWidth(obj);// + this.getElementOffset(obj).X;
	},
	
	getElementSize: function(obj)
	{
		return {width:this.getElementWidth(obj),height:this.getElementHeight(obj)};
	},
	
	getElementBounds: function(obj, parent)
	{
		return {left:this.getElementX(obj, parent),top:this.getElementY(obj, parent),width:this.getElementWidth(obj),height:this.getElementHeight(obj)};
	},
	
	getElementOffset: function(obj)
	{
		var offsetX = 0;
		var offsetY = 0;
		while (obj.offsetParent)
		{
			if (Element.getStyle(obj, "border-left-style") != "none")
				offsetX += this.fromSize(Element.getStyle(obj, "border-left-width"));
			if (Element.getStyle(obj, "border-right-style") != "none")
				offsetX += this.fromSize(Element.getStyle(obj, "border-right-width"));
			
			offsetX += this.fromSize(Element.getStyle(obj, "padding-left"));
			offsetX += this.fromSize(Element.getStyle(obj, "padding-right"));
			
			if (Element.getStyle(obj, "border-top-style") != "none")
				offsetY += this.fromSize(Element.getStyle(obj, "border-top-width"));
			if (Element.getStyle(obj, "border-bottom-style") != "none")
				offsetY += this.fromSize(Element.getStyle(obj, "border-bottom-width"));
			
			offsetY += this.fromSize(Element.getStyle(obj, "padding-top"));
			offsetY += this.fromSize(Element.getStyle(obj, "padding-bottom"));
			
			obj = obj.offsetParent;
		}
		
		return {X:offsetX, Y:offsetY};
	},
	
	numbersAreClose: function(n1, n2, distance)
	{
		return (n1 + distance >= n2 && n1 <= n2);
	},
	
	numberWithin: function(n1, n2, test)
	{
		return (n1 <= test && n2 > test)
	},
	
	getInputChar: function()
	{
		if (this.lastEvent == null)
			return "";
		
		var e = this.lastEvent;
		var keyCode = e.which ? e.which : (e.keyCode ? e.keyCode : (e.charCode ? e.charCode : 0));
		var shift = e.shiftKey || (e.modifiers && (e.modifiers & 4));
		
		if (keyCode == 32) // space
			return " ";
		else if (keyCode >= 48 && keyCode <= 57) // 0-9
			return String.fromCharCode(keyCode);
		else if ((keyCode > 64 && keyCode < 91 && !shift) || (keyCode > 96 && keyCode < 123 && shift)) // a-zA-Z
			return String.fromCharCode(keyCode).toLowerCase();
		else if (((keyCode > 64 && keyCode < 91) || (keyCode > 96 && keyCode < 123))) // a-zA-Z
			return String.fromCharCode(keyCode);
		
		return "";
	},
	
	convertBase: function(value, fromBase, toBase)
	{
		var frb3 =	parseInt(fromBase, 10);
		var frn3 = parseInt(value, frb3);
		var tob3 =	parseInt(toBase, 10);
		var toHex = frn3.toString(tob3);
		toHex = toHex.toUpperCase();
		return toHex;
	},
	
	toSize: function(value)
	{
		value = String(value);
		
		if (value.indexOf("px") > 0 || value.indexOf("%") > 0)
			return value;
		
		return value + "px";
	},
	
	fromSize: function(value)
	{
		return Number(value.replace("px",""));
	}
};
Core.Utility = new Core.UtilityClass();

////////////////////////////////////////////////////////////////////////////////////////////

Core.DebugClass = Class.create();
Core.DebugClass.prototype =
{
	initialize: function(enable)
	{
		if (enable)
			this.enable = enable;
		else
			this.enable = false;
		
		this.output = null;
	},

	write: function(msg)
	{
		if (!this.enable)
			return;
		
		if (this.output)
			this.output.value = msg + "\r\n";
		else if (document.getElementById("debug") != null)
			document.getElementById("debug").innerHTML = msg;
		else
			window.status = msg;
	}
};
Core.Debug = new Core.DebugClass();

////////////////////////////////////////////////////////////////////////////////////////////

Core.Timer = Class.create();
Core.Timer.prototype =
{
	initialize: function(delay)
	{
		this.delay = 1000;
		this._timer = null;
		this.running = false;
		this.ontimer = null;
		
		if (delay)
			this.delay = delay;
	},
	
	start: function()
	{
		if (this.running)
			this.stop();
		
		var _this = this;
		this._timer = window.setTimeout(function()
			{
				if (_this.ontimer)
				{
					if (_this.ontimer())
						_this.start();
				}
			}, this.delay
		);
		
		this.running = true;
	},
	
	stop: function()
	{
		if (this._timer != null)
		{
			window.clearTimeout(this._timer);
			this._timer = null;
		}
		
		this.running = false;
	}
};

////////////////////////////////////////////////////////////////////////////////////////////

Core.StringBuilder = Class.create();
Core.StringBuilder.prototype =
{
	initialize: function()
	{
		this.v = [];
	},
	
	append: function(s)
	{
		this.v.push(s);
	},
	
	appendLine: function(s)
	{
		this.v.push(s + "\r\n");
	},
	
	clear: function()
	{
		this.v.clear();
	},
	
	toString: function()
	{
		return this.v.join("");
	}
};

////////////////////////////////////////////////////////////////////////////////////////////

Core.Type.Range = Class.create();
Core.Type.Range.prototype =
{
	initialize: function(minimum, maximum, extent, value)
	{
		this.value = 0;
		this.minimum = 0;
		this.maximum = 100;
		this.extent = 0;
		this._changing = false;
		this.onchange = null;
		
		if (minimum) this.minimum = minimum;
		if (maximum) this.maximum = maximum;
		if (extent) this.extent = extent;
		if (value) this.value = value;
	},
	
	setValue: function(value)
	{
		value = parseInt(value);
		if (isNaN(value))
			return;
		
		if (this.value != value)
		{
			if (value + this.extent > this.maximum)
				this.value = this.maximum - this.extent;
			else if (value < this.minimum)
				this.value = this.minimum;
			else
				this.value = value;
			
			if (!this._changing && this.onchange)
				this.onchange();
		}
	},
	
	setExtent: function(extent)
	{
		if (this.extent != extent)
		{
			if (extent < 0)
				this.extent = 0;
			else if (this.value + extent > this.maximum)
				this.extent = this.maximum - this.value;
			else
				this.extent = extent;
			
			if (!this._changing && this.onchange)
				this.onchange();
		}
	},
	
	setMinimum: function(minimum)
	{
		if (this.minimum != minimum)
		{
			var _changing = this._changing;
			
			this._changing = true;
			this.minimum = minimum;
			
			if (minimum > this.value)
				this.setValue(minimum);
			
			if (minimum > this.maximum)
			{
				this.extent = 0;
				this.setMaximum(minimum);
				this.setValue(minimum);
			}
			
			if (minimum + this.extent > this.maximum)
				this.extent = this.maximum - this.minimum;
			
			this._changing = _changing;
			
			if (!this._changing && this.onchange)
				this.onchange();
		}
	},
	
	setMaximum: function(maximum)
	{
		if (this.maximum != maximum)
		{
			var _changing = this._changing;
			
			this._changing = true;
			this.maximum = maximum;
			
			if (maximum < this.value)
				this.setValue(maximum - this.extent);
			
			if (maximum < this.minimum)
			{
				this.extent = 0;
				this.setMinimum(maximum);
				this.setValue(maximum);
			}
			
			if (maximum < this.minmum + this.extent)
				this.extent = this.maximum - this.minmum;
			
			if (maximum < this.value + this.extent)
				this.extent = this.maximum - this.value;
			
			this._changing = _changing;
			
			if (!this._changing && this.onchange)
				this.onchange();
		}
	}
};

////////////////////////////////////////////////////////////////////////////////////////////

Core.Type.DoublePoint = Class.create();
Core.Type.DoublePoint.prototype =
{
	initialize: function(x, y)
	{
		this.X = this.Y = 0;

		if (x) this.X = x;
		if (y) this.Y = y;
	},
	
	toString: function()
	{
		return this.X + ", " + this.Y;
	},
	
	toJSON: function()
	{
		return "{\"__type\":\"System.Drawing.PointF\",\"X\":" + this.X + ",\"Y\":" + this.Y + "}";
	}
};

////////////////////////////////////////////////////////////////////////////////////////////

Core.Type.IntegerPoint = Class.create();
Core.Type.IntegerPoint.prototype =
{
	initialize: function(x, y)
	{
		this.X = this.Y = 0;

		if (x) this.X = x;
		if (y) this.Y = y;
	},
	
	toString: function()
	{
		return this.X + ", " + this.Y;
	},
	
	toJSON: function()
	{
		return "{\"__type\":\"System.Drawing.Point\",\"X\":" + Math.ceil(this.X) + ",\"Y\":" + Math.ceil(this.Y) + "}";
	}
};

