/*
 * Savvy.js Library
 * Name: Savvy.Core
 * Version: 0.1.1.4 (Beta)
 * Required: Tested on IE6, IE7, Firefox 1.5+ and Opera 9.2. Other browser support is unknown/untested.
 * Last Updated: 22.06.2007
 * Author: Cryno Bone http://www.chronosight.net/
 ***************************************************
 * References:
 * 1. pick() function taken directly from Mootools Framework
 * 2. Draggable and Resizable object taken with modification from dom-drag.js by www.youngpup.net
 * 3. DOM.addAfter() function taken from Dustin Diaz's Top 10 JaScript Functions at <http://www.dustindiaz.com/top-ten-javascript/>
 * 4. Few prototype function taken from <http://www.hunlock.com/blogs/Ten_Javascript_Tools_Everyone_Should_Have> and <http://20bits.com/2007/03/08/the-philosophy-of-javascript/>
*/
var Savvy = {};
Savvy = {
	version : "0.1.1.5 (Beta)",
	debug : false,
	logs : [],
	logger : function(er) {
		if(er !== "") {
			Savvy.logs.push(er);
			if(Savvy.debug) {
				try {
					console.log(er); 
				} catch(e) { 
					alert(er); 
				}
			}
		}
	},
	image : "",
	href : function(uri) {
		try {
			window.location.href = uri;
		} catch(e) { 
			Savvy.logger("Savvy.href() request to " + uri + " failed, return error " + e);
		} 
	},
	browser:function() {
		return function() {
			var win 	= new Object;
			win.ie 		= win[window.XMLHttpRequest ? "ie7" : "ie6"] = (window.ActiveXObject ? true : false);
			win.khtml 	= ((document.childNodes && !document.all && !navigator.taintEnabled) ? true : false);
			win.gecko 	= (document.getBoxObjectFor != null ? true : false);
			win.opera 	= (window.opera ? true : false);
			return win;
		}();
	}()
};

Array.prototype.inArray = function(value){
	for (var i = 0; i < this.length; i++) {
		if(this[i] === value) {
			return true;
		}
	}
	return false;
};

Array.prototype.indexOf = function(value){
       for(var i = this.length; i-- && this[i] !== value;);
       return i;
};

Array.prototype.each = function(f) {
	for(var key = 0; key < this.length; key++) {
		if(typeof(v) == "function") {
			this.callback(f);
		}
	}
};
Array.prototype.map = function(f) {
	var r=[];
	for(var i = 0; i < this.length; i++) {
		r.push(f(this[i]));
	}
	return r;
};
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
};
String.prototype.ltrim = function() {
	return this.replace(/^\s+/g,"");
};
String.prototype.rtrim = function() {
	return this.replace(/\s+$/g,"");
};
String.prototype.striptags = function() {
	return this.replace(/<([^>]+)>/g,"");
};
String.prototype.htmlentities = function () {
	return this.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
};
String.prototype.toNumber = function () {
	return parseInt(this,10);
};
Object.prototype.toNumber = function () {
	return parseInt(this,10);
};
Number.prototype.toNumber = function() {
	return this;
};

var Attrib = {};
Attrib = {
	Get : function(object, tag) {
		if(!is_null(object)) {
			return object.getAttribute(tag);
		} else {
			Savvy.logger("Attrib.Get failed: " + object + " is null");
			return false;
		}
	},
	Set : function(object, tag, value) {
		if(!is_null(object)) {
			object.setAttribute(tag, value);
			return object;
		} else {
			Savvy.logger("Attrib.Set failed: " + object + " is null");
			return false;
		}
	},
	Remove : function(object, tag) {
		if(!is_null(object)) {
			object.removeAttribute(tag);
			return object;
		} else {
			Savvy.logger("Attrib.Remove failed: " + object + " is null");
			return false;
		}
	},
	Setup : function(arg) {
		var object 	= arg.object;
		var cT 		= [];
		cT 			= arg.attrib;
		
		if(cT.length > 0) {
			for(var i = 0;i < cT.length; i++) {
				for(var inst in cT[i]) {
					if(cT[i].hasOwnProperty(inst)) { 
						this.Set(object, inst, cT[i][inst]);
					}
				}
			}
			return object;
		} else {
			Savvy.logger("Attrib.Setup() failed: please provide attribute");
		}
	}
};

var AJAX = function() {
	this.object 	= null;
	this.debug 		= false;
	this.reply 		= null;
	this.method		= null;
};
AJAX.prototype = {
	Initialize : function() {
		var xhttp = false;
		
		if(window.XMLHttpRequest) {
			xhttp = new XMLHttpRequest();
		} else if(window.ActiveXObject) {
			var msxml = ["MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
			for(var i = 0; i < msxml.length; i++) {
				try {
					xhttp = new ActiveXObject(msxml[i]);
					break;
				} catch(e) { }
			}
		}
		
		if(!xhttp) {
			Savvy.logger("AJAX.Initialize() failed, browser does not support Ajax!");
			return false;
		} else {
			this.object = xhttp;
		}
	},
	Call : function(arg) {
		if(this.object == null) {
			this.Initialize(); 
		}
		
		this.method = (!arg.method || arg.method != "GET" ? "POST" : "GET");
		this.debug = (arg.debug ? arg.debug : this.debug);
		
		if (this.object.readyState == 4 || this.object.readyState == 0) {
			if(this.method == "POST") {
				this.object.open("POST", arg.uri, true);
				
				if(!is_null(arg.type)) {
					this.object.setRequestHeader("Content-Type", arg.type);
				} else { 
					this.object.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
				}
				
				this.object.send(arg.parameters);
			} else {
				this.object.open("GET", arg.uri + arg.parameters, true);
				this.object.send("");
			}
			
			if(arg.oncomplete) {
				this.object.onreadystatechange = arg.oncomplete;
			} else {
				var the_object = this.object;
				var this_object = this;
				
				this.object.onreadystatechange = function() {
					if(the_object.readyState == 4) {
						the_object.reply = the_object.responseText;
							
						if(the_object.debug == true) {
							Savvy.logger(req.responseText);
						}
						
						if(Replacer.Trim(the_object.responseText) != "" && the_object.status == 200) {
							var a = eval("("+the_object.responseText+")");
							
							if(!is_null(a.alertpop) && Replacer.Trim(a.alertpop) != "") {
								alert(a.alertpop);
							}
							
							if(!is_null(a.jumpto) && Replacer.Trim(a.jumpto) != "") {
								Savvy.href(a.jumpto);
							}
							
							if(!is_null(a.result)) {
								if(!is_null(a.add2id) && Replacer.Trim(a.add2id) != "" && a.result != "") {
									var add2id = new Elements;
									add2id.Id(a.add2id).setHTML(Replacer.Xml(a.result));
								}
								
								if(!is_null(a.exec) && typeof(a.exec) == "function") { 
									try { 
										a.exec(a.result);
									} catch(e) {
										var fn = a.exec;
										fn(a.result); 
									}
								}
							}
						} else {
							this_object.Cancel();
						}
					}
				}
			}
		}
	},
	Cancel : function() {
		var req = this.object;
		req.abort();
		this.object = null;
	}
};

var Classes = {};
var Classes = {
	Add:function(object, value) {
		object.className = value;
		return object;
	},
	Append:function(object, value) {
		if(!is_null(object.className) && object.className.trim() != "") {
			object.className = object.className + " " + value;
			return object;
		} else if(is_null(object.className) || object.className.trim() == "") {
			object.className = value;
			return object;
		} else {
			return false;
		}
	},
	Remove:function(object, value) {
		if(!is_null(object.className) && object.className.trim() != "") {
			var classes = object.className.split(" ");
			object.className = "";
			
			for(var i = 0; i < classes.length; i++) {
				if(classes[i] != value) {
					object.className = object.className + " " + value;
				}
			}
		}
		return object;
	},
	Clear:function(object, value) {
		if(!is_null(object.className) && object.className.trim() != "") {
			object.className = "";
			return object;
		}
	},
	Has:function(object, value) {
		if(!is_null(object.className) && object.className.trim() != "") {
			var classes = object.className.split(" ");
			return classes.inArray(value);
		}
	}
};

var CSS = {};
CSS = {
	Styler:function(arg) {
		var object	= arg.object;
		var csses 	= [];
		csses		= arg.css;
		
		for(var i = 0; i < csses.length; i++) {
			for(var inst in csses[i]) {
				if(csses[i].hasOwnProperty(inst)) {
					this.Set(object, inst, csses[i][inst]);
				}
			}
		}
		
		return object;
	},
	Set:function(object, tag, value) {
		try { 
			object.style[tag] = value;
			return object;
		} catch(e) { 
			return false;
		}
	},
	Get:function(object, value) {
		try {
			return object.style[value];
		} catch(e) { 
			return false;
		}
	},
	Show:function(object) {
		try {
			this.Set(object, "visibility", "visible");
			return object;
		} catch(e) {
			return false;
		}
	},
	Hide:function(object) {
		try {
			this.Set(object, "visibility", "hidden");
			return object;
		} catch(e) {
			return false;
		}
	},
	Opacity: function(object, v) {
		v = (v > 100 ? 100 : (v < 0 ? 0 : v));
		try {
			if(v == 0 && this.Get(object, "visibility") != "hidden") { 
				this.Hide(object);
			} else if(v > 0 && o.getCSS("visibility") == "hidden") {
				this.Show(object);
			}
			
			if (window.ActiveXObject || Savvy.browser.ie == true) {
				if (!object.currentStyle || !object.currentStyle.hasLayout) {
					object.setCSS("zoom", 1);
				}
				this.Set(object, "filter", (v < 100 ? "alpha(opacity="+v+")" : ""));
			} else {
				this.Set(object, "opacity", (v/100));
				this.Set(object, "MozOpacity", (v/100));
			}
		} catch(e) { }
	},
	Png:function(arg) {
		var object	= Func.Grab(arg.object, arg.element, "obj");
		arg.gecko 	= pick(arg.gecko, "");
		arg.ie 		= pick(arg.ie, "scale");
		
		if(window.ActiveXObject) {
			this.Set(object, "filter", "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + arg.uri + "',sizingMethod='" + arg.ie + "')");
		} else {
			this.Set(object, "background", "url('" + arg.uri + "') " + arg.gecko);
		}
		
		return object;
	}
};

var DOM = {};
DOM = {
	Add:function(parent, child) {
		if(!is_null(parent) && !is_null(child)) {
			parent.appendChild(child);
			
			return parent;
		} else {
			try { 
				document.body.appendChild(parent); 
				
				return parent;
			} catch(e) { 
				return false;
			}
		}
	},
	AddText : function(parent, text) {
		if(!is_null(parent) && text != "") {
			return this.Add(parent, document.createTextNode(text));
		} else {
			return false;
		}
	},
	AddBefore:function(params) {
		var args = arguments;
		
		if(args.length == 3 && !is_null(args[0]) && !is_null(args[1]) && !is_null(args[2])) {
			arguments[0].InsertBefore(args[1], args[2]);
			
			return true;
		} else if(args.length == 2 && !is_null(args[0]) && !is_null(args[1])) {
			args[1].parentNode.InsertBefore(args[0], args[1]);
			
			return true;
		} else {
			return false;
		}
	},
	AddAfter:function(params) {
		var args = arguments;
		
		if(!is_null(r.nextSibling)) {
			if(args.length == 3 && !is_null(args[0]) && !is_null(args[1]) && !is_null(args[2])) {
				this.AddBefore(args[0], args[1], args[2].nextSibling);
				
				return true;
			} else {
				try {
					this.addBefore(args[0], args[1].nextSibling);
					
					return true;
				} catch(e) { 
					return false; 
				}
			}
		} else {
			return this.Add(args[0], args[1]);
		}
	},
	Remove:function(params) {
		var args = arguments;
		
		if(args.length === 2 && !is_null(args[0]) && !is_null(args[1])) {
			args[0].removeChild(args[1]);
			
			return args[0];
		} else {
			args[0].parentNode.removeChild(args[0]);
			
			return args[0];
		}
	},
	Change:function(params) {
		var args = arguments;
		
		if(args.length == 3 && !is_null(args[0]) && !is_null(args[1]) && !is_null(args[2])) {
			args[0].ReplaceChild(args[1], args[2]);
		} else {
			args[1].parentNode.ReplaceChild(args[0], args[1]);
		}
	},
	Empty:function(parent) {
		if(!is_null(parent)) {
			if(parent.hasChildNodes || parent.innerHTML != "") {
				parent.innerHTML = "";
			}
			return true;
		} else {
			return false;
		}
	}
};

var Draggable = {};
Draggable = {
	obj : null,
	Initialize : function(arg) {
		
		var o			= arg.obj;
		o.root 			= pick(arg.objRoot, o);
		o.onmousedown 	= Draggable.Start;
		o.hmode			= true;
		o.vmode			= true;
		
		if(isNaN(CSS.Get(o.root, "left").toNumber())){
			CSS.Set(o.root, "left", "0px");
		}
		if(isNaN(CSS.Get(o.root, "top").toNumber())) {
			CSS.Set(o.root, "top", "0px");
		}
		
		o.minX = pick(arg.minX, null);
		o.maxX = pick(arg.maxX, null);
		o.minY = pick(arg.minY, null);
		o.maxY = pick(arg.maxY, null);
		o.root.onDragStart = new Function();
		o.root.onDragEnd = new Function();
		o.root.onDrag = new Function();
	},
	Start:function(e) {
		
		var o = Draggable.obj = this;
		
		e = Draggable.fixE(e);
		var y = CSS.Get(o.root, "top").toNumber();
		var x = CSS.Get(o.root, "left").toNumber();
		
		o.root.onDragStart(x, y);
		o.lastMouseX = e.clientX;
		o.lastMouseY = e.clientY;
		
		if(o.minX != null) {
			o.minMouseX = e.clientX - x + o.minX;
		}
		if(o.maxX != null) {
			o.maxMouseX = o.minMouseX + o.maxX - o.minX;
		}
		if(o.minY != null) {
			o.minMouseY = e.clientY - y + o.minY;
		}
		if(o.maxY != null) {
			o.maxMouseY = o.minMouseY + o.maxY - o.minY;
		}
		
		document.onmousemove = Draggable.Drag;
		document.onmouseup = Draggable.End;
		
		return false;
	},
	Drag:function(e){
		e = Draggable.fixE(e);
		
		var o = Draggable.obj;
		
		var ey	= e.clientY;
		var ex	= e.clientX;
		var y = CSS.Get(o.root, "top").toNumber();
		var x = CSS.Get(o.root, "left").toNumber();
		var nx;
		var ny;
		
		if (o.minX != null) {
			ex = Math.min(ex, o.mixMouseX);
		}
		if (o.maxX != null) {
			ex = Math.max(ex, o.maxMouseX);
		}
		if (o.minY != null) {
			ey = Math.min(ey, o.minMouseY);
		}
		if (o.maxY != null) {
			ey = Math.max(ey, o.maxMouseY);
		}
		
		nx = x + ((ex - o.lastMouseX) * 1);
		ny = y + ((ey - o.lastMouseY) * 1);
		CSS.Set(o.root, "left", nx + "px");
		CSS.Set(o.root, "top", ny + "px");
		o.lastMouseX = ex;
		o.lastMouseY = ey;
		o.root.onDrag(nx, ny);
		
		return false;
	},
	End : function(){
		var o = Draggable.obj;
		document.onmousemove = null;
		document.onmouseup = null;
		o.root.onDragEnd(Draggable.obj.root.style.left.toNumber(), Draggable.obj.root.style.top.toNumber(), Draggable.obj.root);
		o = null;
	},
	fixE : function(e) {
		if (is_null(e)) {
			e = window.event;
		}
		if (is_null(e.layerX)) {
			e.layerX = e.offsetX;
		}
		if (is_null(e.layerY)) {
			e.layerY = e.offsetY;
		}
		
		return e;
	}
};

var Func = {
	Callback : function(object, fn) {
		try {
			object.callbackfunc = fn;
			object.callbackfunc();
			return object;
		} catch(e) {
			alert("Func.Callback: " + fn + e);
		}
	},
	On : function(object, trigger, fn) {
		try {
			object["on".concat(trigger.trim())] = fn;
		} catch(e) { alert("Func.On: " + fn + e); }
	},
	CheckId : function(element) {
		if(document.getElementById(element.trim())) {
			return true;
		} else {
			return false;
		}
	},
	Each : function(object, fn) {
		for(var i = 0; i < object.length; i++) {
			try {
				Func.Callback(object[i], fn);
			} catch(e) {
				alert("Func.Each: " + fn + e);
			}
		}
	},
	Grab : function(object, element, r) {
		var r = (!is_null(r) ? r : "element");
		
		if(!is_null(object) && !is_null(element)) {
			if(Attrib.Get(object,"id") == element) {
				return (r == "obj" ? object : element);
			} else {
				return false;
			}
		} else if (!is_null(element)) {
			if(r == "obj") {
				var obj = new Elements;
				obj.Id(element);				
				return obj.getElement();
			} else {
				return element;
			}
		} else if (!is_null(object)) {
			return (r == "obj" ? object : Attrib.Get(object, "id"));
		} else {
			return false;
		}
	}
};

var Elements = function(objects) {
	this.elements 	= [objects];
	return this;
};
Elements.prototype = {
	Add : function(objects) {
		for(var i = 0; i < objects.length; i++) {
			this.elements.push(objects[i]);
		}
		return this;
	},
	Create : function(elm) {
		var object = [];
		var args = arguments;
		
		if(args.length === 2) {
			if(!is_null(args[0])) {
				object[0] = document.createElement(args[1]);
				try {
					DOM.Add(args[0], object[0]);
				} catch(e) {
					DOM.Add(document.body, object[0]);
				}
			} 
			else {
				object[0] = document.createElement(args[1]);
				DOM.Add(document.body, object[0]);
			}
		}
		else if(!is_null(elm)) {
			var element = elm.trim().split(" ");
			if(element.length > 1) {
				if(element[0].charAt(0) == "#") {
					object[0] = document.createElement(element[1]);
					var obj = new Elements;
					obj.Id(element[0].substring(1, element[0].length));
					obj.addDOM(object[0]);
				} else {
					object[0] = document.createElement(element[0]);
					DOM.Add(document.body, object[0]);
				}
			} else {
				object[0] = document.createElement(elm);
				DOM.Add(document.body, object[0]);
			}
		}
		
		this.elements = object;
		
		return this;
	},
	Id : function(element) {
		var object = [];
		var args = arguments;
		var elements = element.trim().split(",");
		
		if(elements.length > 1) {
			for(var i = 0; i < elements.length; i++) {
				if(elements[i].trim().charAt(0) == "#") {
					elements[i] = elements[i].trim();
					elements[i] = elements[i].substring(1, elements[i].length);
					object.push(document.getElementById(elements[i].trim())); 
				}
			}
		} else {
			try {
				object.push(document.getElementById(element.trim())); 
			} catch(e) { 
				return false;
			}
		}
		this.elements = object;
		
		return this;
	},
	Tags : function(element) {
		var object = [];
		var objects = [];
		var elm = "";
		var args = arguments;
		
		function has_class(objects, value, i) {
			var tag = value.trim().split(".");
			var regexp = new RegExp(/\./);
			
			try {
				obj = objects.getElementsByTagName(tag[0].trim());
			} catch(e) {
				obj = document.getElementsByTagName(tag[0].trim());
			}
			
			if(regexp.test(value)) {
				var classes = [];
				Func.Each(obj, function() {
					var cA = this.className.split(" ");
					if(cA.inArray(tag[1].trim())) {
						 if(classes.length === 0) {
							classes[0] = this;
						} else {
							classes.push(this);
						} 
					}
				});
				return classes;
			} else {
				return obj;
			}
		};
		
		if(args.length === 2) {
			objects = has_class(args[0], args[1]);
		} 
		else if(args.length === 1) {
			var obj = element.trim().split(" ");
			if(obj.length > 1 && obj[0].trim().charAt(0) == "#") {
				var el = obj[0].trim();
				el = el.substring(1, el.length);
				
				var o = new Elements;
				o.Id(el);
				
				object = has_class(document, obj[1].trim());
				for(var i = 0; i < object.length; i++) {
					if(Attrib.Get(o.getElement(), "id") == Attrib.Get(object[i].parentNode, "id") || Attrib.Get(o.getElement(), "id") == Attrib.Get(object[i].parentNode.parentNode, "id") ) {
						objects.push(object[i]);  
					}
				}
			} else {
				objects = has_class(document, element.trim());
			} 
		}
		this.elements = objects;
		this.elements = this.elements;
		
		return this;
	},
	toNumber : function() {
		
	},
	getElement: function(index) {
		var index = pick(index, 0);
		return this.elements[index];
	},
	Each : function(fn) {
		Func.Each(this.elements, function() {
			Func.Callback(this, fn); 
		});
		return this;
	},
	Callback : function(fn) {
		this.callbackfunc = fn;
		this.callbackfunc();
		return this;
	},
	setProperty : function(tag, value) {
		Func.Each(this.elements, function() {
			Attrib.Set(this, tag, value);
		});
		return this;
	},
	setProperties : function(arg) {
		Func.Each(this.elements, function() {
			Attrib.Setup({
				object:this,
				attrib:arg
			});
		});
		return this;
	},
	getProperty : function(tag) {
		var values = [];
		Func.Each(this.elements, function() {
			values.push(Attrib.Get(this, tag));
		});
		return values;
	},
	removeProperty : function(tag) {
		Func.Each(this.elements, function() {
			Attrib.Remove(this, tag);
		});
		return this;
	},
	addClass : function(tag) {
		Func.Each(this.elements, function() {
			Classes.Add(this, tag); 
		});
		return this;
	},
	hasClass : function(tag) {
		var values = [];
		Func.Each(this.elements, function() {
			values.push(Classes.Has(this, tag));
		});
		return values;
	},
	appendClass : function(tag) {
		Func.Each(this.elements, function() {
			Classes.Append(this, tag); 
		});
		return this;
	},
	removeClass : function(tag) {
		Func.Each(this.elements, function() {
			Classes.Remove(this, tag); 
		});
		return this;
	},
	addDOM : function(child) {
		Func.Each(this.elements, function() {
			DOM.Add(this, child);
		});
		return this;
	},
	addTextDOM : function(text) {
		Func.Each(this.elements, function() {
			DOM.AddText(this, text);
		});
		return this;
	},
	removeDOM : function(child) {
		Func.Each(this.elements, function() {
			DOM.Remove(this, child);
		});
		return this;
	},
	setStyle : function(tag, value) {
		Func.Each(this.elements, function() {
			CSS.Set(this, tag, value);
		});
		return this;
	},
	setStyles : function(args) {
		Func.Each(this.elements, function() {
			CSS.Styler({
				object:this,
				css:args
			});
		});
		return this;
	},
	getStyle : function(tag) {
		var values = [];
		Func.Each(this.elements, function() {
			values.push(pick(CSS.Get(this, tag), false));
		});
		return values;
	},
	alphaPNG : function(args) {
		Func.Each(this.elements, function() {
			var json = args;
			json.obj = this;
			CSS.Png(json);
		});
	},
	setHTML : function(text) {
		Func.Each(this.elements, function() {
			this.innerHTML = text;
		});
		return this; 
	},
	updateHTML : function(text) {
		Func.Each(this.elements, function() {
			this.innerHTML = this.innerHTML.concat(text);
		});
		return this;
	},
	removeHTML : function() {
		Func.Each(this.elements, function() {
			this.innerHTML = "";
		});
		return this;
	},
	On : function(t, fn) {
		Func.Each(this.elements, function() {
			try {
				this["on".concat(t.trim())] = fn;
			} catch(e) { }
		});
		return this;
	}
};

var Event = function() {
	this.trigger 	= null;
	this.init		= null;
};
Event.prototype = {
	On : function(arg) {
		var object 	= pick(arg.object, window);
		var t 		= pick(this.trigger, arg.trigger.toString());
		var f 		= pick(this.init, arg.init);
		var r;
		
		if(object.addEventListener) {
			try { 
				r = object.addEventListener(t, f, false);
				return r;
			} catch(e) { }
		} else if(object.attachEvent) {
			try { 
				object.attachEvent("on" + concat(t), f); 
			} catch(e) { }
			return true;
		} else {
			object["on" + t] = f;
		}
	},
	Off : function(arg) {
		var r 	= false;
		var obj = pick(arg.object, window);
		var t 	= pick(this.trigger, arg.trigger.toString());
		var f 	= pick(this.init, arg.init);
		
		if(object.removeEvent) {
			try { 
				r = object.removeEvent("on" + concat(t), f); 
			} catch(e) { 
				try {
					r = object.removeEventListener(t, f, false); 
				} catch(e) { 
					r = "Unable to load window.attachEvent: " + e;
				}
			}
		} else { 
			try { 
				r = object.removeEventListener(t, f, false); 
			} catch(e) { 
				r = "Unable to load window.addEventListener: " + e; 
			}
		}
		return r;
	}
};

var Form = function() {
	this.first 		= null;
	this.object 	= null; 
};
Form.prototype = {
	Confirm : function(text) {
		if(!text || text.trim() == "") {
			text = "Do you really want to run this action?";
		}
		return window.confirm(text);
	},
	Clear : function(object) {
		var obj = object.elements;
		Func.Each(obj, function() {
			if(this.type == "text" || this.type == "password" || this.type == "textarea") {
				this.value = "";
			}
		});
	},
	Validate : function(object) {
		this.object		= pick(this.object, object);
		var elm 		= Attrib.Get(this.object, "id");
		var output 		= "";
		
		var field 		= new Elements;
		field.Tags(this.object, "*");
		
		this.first 		= null;
		var the_object 	= this;
		var tn		 	= ["INPUT","SELECT","TEXTAREA"];
		
		field.Each(function() {
			if(tn.inArray(this.tagName)) {
				if (this.name != "") {
					this.onchange = function() { 
						return false;
					};
					var rule = new RegExp("(max|min|exact)\-(\d*)");
					this.className = (!is_null(this.className) ? this.className : "");
					var classes = this.className.split(" ");
					
					if(classes.inArray("required") && this.value.trim() == "") {
						the_object.Error(object, this, "Please fill the following field!");
						the_object.Mark(object);
					} 
					else if(classes.inArray("string") && !Test.isString(this.value)) {
						the_object.Error(object, this, "Please fill the following field (string)!");
						the_object.Mark(object);
					} 
					else if(classes.inArray("integer") && !Test.isInteger(this.value)) {
						the_object.Error(object, this, "Please fill the following field (integer)!");
						the_object.Mark(object);
					} 
					else if(classes.inArray("email") && !Test.isEmail(this.value)) {
						the_object.Error(object, this, "Please fill correct e-mail address!");
						the_object.Mark(object);
					} 
					else {
						CSS.Set(this, "border", "1px solid #06c");
					}
					
					for(var i = 0; i < classes.length; i++) {
						if(classes[i].match(rule)) {
							if(!Test.Lengths(classes[i], this.value)) {
								var match_error = classes[i].split("-");
								the_object.Error(object, this, "Require " + match_error[0] + " of " + match_error[1] + " characters.", true);
								the_object.Mark(object);
							}
						}
					}
					
					if (this.type == "checkbox" && this.checked == true) {
						output = output + "&" + this.name + "=" + Replacer.Html(this.value);
					}
					else if (this.type == "radio" && this.checked == true) {
						output = output + "&" + this.name + "=" + Replacer.Html(this.value);
					} else if (this.type != "checkbox" && this.type != 'radio') {
						output = output + "&" + this.name + "=" + Replacer.Html(this.value);
					}
				}
			}
		});
		
		if(!is_null(this.first)) { 
			this.first.focus();
			return false; 
		} else {
			return output;
		}
	},
	Mark:function(object) {
		var elm = Attrib.Get(object, "id");
		if(is_null(this.first)) {
			this.first = object;
		}
	},
	Error: function(object, field, message, booleans) {
		var elm 		= Attrib.Get(object, "id");
		var booleans 	= pick(booleans, false);
		var the_object	= this;
		
		if(!Func.CheckId(elm + "_" + field.name + "_error")) {
			var oE = new Elements;
			oE.Create("span").setProperty("id", elm + "_" + field.name + "_error").addTextDOM(message);
			oE.addClass("form_error");
			DOM.Add(field.parentNode, oE.getElement());
			CSS.Set(field, "border", "1px solid #f00");
			field.onchange = function() {
				if(this.value != "") { 
					CSS.Set(this, "border", "1px solid #06c");
					if(oE) {
						DOM.Remove(this.parentNode, oE.getElement());
					}
					the_object.first = null;
				}
			};
		} 
		else if(Func.CheckId(elm + "_" + field.name + "_error") && booleans == true) {
			if(object.innerHTML.match(message) == false && object.innerHTML.trim() != "") {
				object.innerHTML += message;
			}
			var err = new Elements;
			err.Id(elm + "_" + field.name + "_error");
			
			CSS.Set(field, "border", "1px solid #f00");
			field.onchange = function() {
				if(this.value != "") { 
					CSS.Set(this, "border", "1px solid #06c");
					if(object) {
						DOM.Remove(object.parentNode, err.getElement());
					}
					the_object.first = null;
				}
			};
		}
	},
	Post:function(arg) {
		var object	= Func.Grab(arg.object, arg.element, "obj");
		var init	= pick(arg.onsuccess, null);
		var fail	= pick(arg.onfail, null);
		var params 	= this.Validate(object);
		
		if(params) {
			params = (arg.params ? arg.params : "") + params;
			if(init != null && typeof(init) == "function") {
				init();
			}
			
			var ajax = new AJAX;
			ajax.Call({
				parameters:params,
				uri:arg.uri,
				method:"POST"
			});
			
			return true;
		} else {
			if(fail != null && typeof(fail) == "function") {
				fail();
			}
			
			return false;
		}
	}
};

var Hash = {};
Hash = {
	object:{},
	Add:function(object, tag, value) {
		var element = null;
		if(typeof(object) == "object") {
			element = Attrib(object, "id");
		} else if(typeof(object) == "string") {
			element = object;
		}
		if(!is_null(element)) {
			if(is_null(Hash.object[element])) {
				Hash.object[element] = [];
			}
			Hash.object[element][tag] = value;
		}
	},
	Get:function(object, tag) {
		var element = null;
		if(typeof(object) == "object") {
			element = Attrib(object, "id");
		} else if(typeof(object) == "string") {
			element = object;
		}
		
		if(!is_null(element)) {
			if(!is_null(Hash.object[element]) && !is_null(Hash.object[element][tag])) {
				return Hash.object[element][tag];
			} else {
				return false;
			}
		} else {
			return false;
		}
	},
	Remove:function(object, tag) {
		var element = null;
		if(typeof(object) == "object") {
			element = Attrib(object, "id");
		} else if(typeof(object) == "string") {
			element = object;
		}
		
		if(!is_null(element)) {
			Hash.object[element][tag] = null;
		}
	}
};

var Replacer = {};
Replacer = {
	Html : function(text) {
		var s 	= new String(text);
		s 		= s.htmlentities();
		s 		= encodeURIComponent(s);
		
		return s;
	},
	Trim : function(text) {
		var s 	= new String(text);
		s 		= s.replace(/^\s+/g, "");
		s 		= s.replace(/\s+$/g, "");
		
		return s;
	},
	Xml:function(text) {
		var s 	= new String(text);
		s 		= s.replace(/\[lt\]/g, "<");
		s 		= s.replace(/\[gt\]/g, ">");
		s 		= s.replace(/\[n\]/g, "&");
		s 		= s.replace(/\&quot\;/g, "\"");
		s 		= s.replace(/\&rsquo\;/g, "\'");
		s 		= s.replace(/\[br\]/g, "\n");
		s 		= s.replace(/\[break\]/g, "<br />");
		
		return s;
	}
};

var Resizable = {};
Resizable = {
	obj:null,
	init:function(arg) {
		var o = arg.obj;
		o.onmousedown = Resizable.Start;
		o.root = pick(arg.objRoot, o);
		o.hmode	= true;
		o.vmode	= true;
		o.minX = pick(arg.minX, null);
		o.minY = pick(arg.minY, null);
		o.maxX = pick(arg.maxX, null);
		o.maxY = pick(arg.maxY, null);
		
		o.root.onResizeStart = new Function();
		o.root.onResizeEnd = new Function();
		o.root.onResize	= new Function();
	},
	Start:function(e){
		var o = Resizable.obj = this;
		e = Resizable.FixE(e);
		var y = CSS.Get(o.root, "height").toNumber();
		var x = CSS.Get(o.root, "width").toNumber();
		o.root.onResizeStart(x, y);
		o.lastMouseX = e.clientX;
		o.lastMouseY = e.clientY;
		
		if(o.minX != null) {
			o.minMouseX = e.clientX - x + o.minX;
		}
		if(o.maxX != null) {
			o.maxMouseX = o.minMouseX + o.maxX - o.minX;
		}
		if(o.minY != null) {
			o.minMouseY	= e.clientY - y + o.minY;
		}
		if(o.maxY != null) {
			o.maxMouseY	= o.minMouseY + o.maxY - o.minY;
		}
		
		document.onmousemove = Resizable.Resize;
		document.onmouseup = Resizable.End;
		
		return false;
	},
	Resize : function(e){
		e = Resizable.FixE(e);
		var o = Resizable.obj;
		var ey = e.clientY;
		var ex = e.clientX;
		var y = CSS.Get(o.root, "height").toNumber();
		var x = CSS.Get(o.root, "width").toNumber();
		var ow = x;
		var oh = y;
		var nx, ny;
		
		if (o.minX != null) {
			ex = Math.max(ex, o.minMouseX);
		}
		if (o.maxX != null) {
			ex = Math.min(ex, o.maxMouseX);
		}
		if (o.minY != null) {
			ey = Math.max(ey, o.minMouseY);
		}
		if (o.maxY != null) {
			ey = Math.min(ey, o.maxMouseY);
		}
		
		nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
		ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));
		CSS.Set(o.root, "width", (ow + (nx - x)) + "px");
		CSS.Set(o.root, "height", (oh + (ny - y)) + "px");
		o.lastMouseX = ex;
		o.lastMouseY = ey;
		o.root.onResize(Math.round(nx-x), Math.round(ny-y));
		
		return false;
	},
	End : function(){
		document.onmousemove = null;
		document.onmouseup   = null;
		Resizable.obj.root.onResizeEnd(Resizable.obj.root.style.width.toNumber(), Resizable.obj.root.style.height.toNumber(), Resizable.obj.root);
		Resizable.obj = null;
	},
	FixE : function(e){
		if (typeof(e) == "undefined") {
			e = window.event;
		}
		if (typeof(e.layerX) == "undefined") {
			e.layerX = e.offsetX;
		}
		if (typeof(e.layerY) == "undefined") {
			e.layerY = e.offsetY;
		}
		
		return e;
	},
	childResize:function(arg) {
		var o = arg.obj;
		var child = arg.child;
		
		for(var i = 0; i < child.length; i++) {
			try {
				CSS.Set(child[i], "width", (CSS.Get(child[i], "width").toNumber() + arg.width)+"px");
			} catch(e) {}
			
			CSS.Set(child[i], "height", (CSS.Get(child[i], "height").toNumber() + arg.height)+"px");
		}
	}
};

var Test = {
	isString:function(v) {
		return (typeof(v) == "string" && v != "" && isNaN(v));
	},
	isInteger:function(v) {
		return (!isNaN(v) && v != "");
	},
	isEmail:function(v) {
		var rX = new RegExp(/^[\w-\.\']{1,}\@([\da-zA-Z-]{1,}\.){1,}[\da-zA-Z-]{2,}$/);
		
		return (v != "" && rX.test(v));
	},
	Lengths:function(r,v) {
		var epx = r.split("-");
		
		if(epx[0] == "max") {
			return (v.length <= epx[1].toNumber() ? true : false); 
		} else if(epx[0] == "min") {
			return (v.length >= epx[1].toNumber()? true : false);
		} else if(epx[0] == "exact") {
			return (v.length == epx[1].toNumber()? true : false);
		}
	},
	isIpAddress:function(v) {
		var rX = new RegExp(/^\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\]$/);
		return (v != "" && rX.test(v));
	}
};

var Windows = {
	getScroll: function () {
		var scrOfX = 0;
		var scrOfY = 0;
		if(typeof window.pageYOffset == "number") {
			scrOfY = window.pageYOffset;
			scrOfX = window.pageXOffset;
		} else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
			scrOfY = document.body.scrollTop;
			scrOfX = document.body.scrollLeft;
		} else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
			scrOfY = document.documentElement.scrollTop;
			scrOfX = document.documentElement.scrollLeft;
		}
		return [scrOfX, scrOfY];
	},
	getRelative:function(o) {
		var curwidth = 0;
		var curheight = 0;
		var curtop = 0;
		var curleft = 0;
		if(o.offsetParent) {
			curwidth = o.offsetWidth;
			curheight = o.offsetHeight;
			while(o.offsetParent) {
				curtop += o.offsetTop;
				curleft += o.offsetLeft;
				o = o.offsetParent;
			}
		} else {
			curwidth = pick(o.width, 0);
			curheight = pick(o.height, 0);
			curtop = pick(o.y, 0);
			curLeft = pick(o.x, 0);
		}
		
		return [curwidth, curheight, curtop, curleft];
	},
	getPositionCenter:function(oW,oH) {
		var d = document.body;
		var hW = d.offsetWidth.toNumber();
		var hH = d.offsetHeight.toNumber();
		var sXY = Windows.getScroll();
		var xS = Math.round(((hW - oW) / 2) + sXY[0]);
		var yS = Math.round((((screen.height - 200) - oH) / 2) + sXY[1]);
		xS = (xS < 0 ? 0 : xS);
		yS = (yS < 0 ? 0 : yS);
		return [yS, xS];
	}
};

function include(jsf) {
	var st = Element.Create("script").setAttrib("text/javascript");
	st.src = jsf.trim();
	Element.Tags("HEAD")[0].addDOM(st);
}

function is_null(obj) {
	return (typeof(obj) == "undefined" || obj == null); 
};

function pick(choose,option) {
	return (!is_null(choose) ? choose : option);
};