/*
WARP: Web-based Asynchronous Remote Procedures
 (c) 2007 Messaging Architects

Written by:
 Owen Swerkstrom
 Joshua Faul
 Micah N. Gorrell
 Paul King

Requires:
 MooTools 1.11
 Firebug Lite
*/
 

var Warp = {
	Version: "...", // gets loaded from server.
	cssHack: [], // IE limits to 31 CSS docs, 288k each, so we'll chunk 'em

	addCSS: function (cssFile) {
		var that = this;
		var a = null;
		cssFile = cssFile + "?release=" + this.Version;
		if(window.ie) {
			var css = null;
			if(!this.cssHack.length) {
				this.cssHack.push(new Element("style"));
				css = this.cssHack[this.cssHack.length - 1];
				css.set({"type": "text/css"});
				css.injectInside(document.head);
			} else {
				css = this.cssHack[this.cssHack.length - 1];
			}

			var path = cssFile.substring(0, cssFile.lastIndexOf("/") + 1);
			var x = new XHR({"method": "get", "onSuccess": function() {
				var newCSS = this.response.text.split("\n");
				var lines = [];

				if(css.styleSheet.cssText.length + this.response.text.length >
				   250000) {
					// we'd be going over our size limit, start a new doc
					that.cssHack.push(new Element("style"));
					css = that.cssHack[that.cssHack.length - 1];
					css.set({"type": "text/css"});
					css.injectInside(document.head);
				}

				// absolute-ize URL's mentioned in loaded CSS
				$each(newCSS, function(line) {
					if(line.contains("url('") && !line.contains("url('/")) {
						lines.push(line.replace("url('", "url('" + path));
					} else if(line.contains("url(\"") &&
							  !line.contains("url(\"/")) {
						lines.push(line.replace("url(\"", "url(\"" + path));
					} else {
						lines.push(line);
					}
				});
				css.styleSheet.cssText += "\n" + lines.join("");
			}});
			x.send(cssFile, null);
		} else {
			return new Asset.css(cssFile, {id: cssFile});
		}
	},

	addJS: function (jsFile, id) {
		if(id) {
			var a = new Asset.javascript(jsFile, {"id": id});
		} else {
			var j = new Asset.javascript(jsFile);
		}
	},

	preload: function(widget, callback) {
		var jsFile = ["/warp/widgets/", widget, "/",
					  widget, ".js?release=", this.Version];
		var id = null;
		if(callback) {
			id = "warp_" + widget;
			var check = function() {
				if($(id)) {
					callback();
				} else {
					check.delay(10);
				}
			};
			check.delay(10);
		}
		Warp.addJS(jsFile.join(""), id);
		return;
	},

	bodyClass: function () {
		var theBody = document.getElementsByTagName("BODY")[0];

		if (window.ie) { theBody.className = "IE"; }
		if (window.opera) { theBody.className = "Opera"; }
		if (window.webkit) { theBody.className = "Safari"; }
		if (window.gecko) { theBody.className = "Firefox"; }
	},

	// Container for all of the widgets
	widgets: {},
	

	// currently-loading widget names
	loading: [],
	loadingCallbacks: [],

	evolve: function(widgetList, callback, parentElement) {
		var that = this;
		if(!callback) {
			callback = function(element) {};
		}
		var callb = function callbb(cb, elm) {
			if(!that.loading.length) {
				// we're done loading, callback now
				cb(elm);
				// also do any waiting callbacks
				$each(that.loadingCallbacks, function(item) {
					item.cb(item.elm);
				});
				that.loadingCallbacks = [];
			} else {
				that.loadingCallbacks.push({"cb": cb, "elm": elm});
			}
		};
		if(parentElement) {
			// go through the list and resolve element references that
			// are CSS selectors instead of elements
			$each(widgetList, function(ev) {
				if($type(ev.element) == "string" &&
				   parentElement.getElement(ev.element)) {
					ev.element = parentElement.getElement(ev.element);
				}
			});
		}

		// a-synchronize this function
		var func = function() {
			$each(widgetList, function(widg) {
				if(!widg) {
//					alert(Json.toString(widgetList));
					return;
				}
				var oozeElm = $(widg.element);

				if(oozeElm) {
					$each(oozeElm.className.split(" "), function(cls) {
						if(cls.contains("widget_")) {
	//						alert(cls + " becoming " + widg.widget);
							oozeElm.widget = null;
						}
					});
				} else {
//					alert(Json.toString(widg));
					return;
				}

				if(Warp.widgets[widg.widget]) {
					// we have the widget code, no need to load
					oozeElm.widget = new Warp.widgets[widg.widget](oozeElm, widg.options);
					callb(callback, widg.element);
				} else if(Warp.loading.contains(widg.widget)) {
					// widget code is loading, wait for it
					var check = function() {
						if(Warp.widgets[widg.widget]) {
							oozeElm.widget = new Warp.widgets[widg.widget](oozeElm, widg.options);
							callb(callback, widg.element);
						} else {
							check.delay(100);
						}
					};
					check.delay(100);
					// FIXME: loading a non-existant (or non-checked in...)
					// widget snarfs up all CPU, probably second instance
				} else {
					// we don't have the code and it isn't loading
					Warp.loading.include(widg.widget);
					var jsFile = ["/warp/widgets/", widg.widget, "/", widg.widget];
					jsFile.push(".js?release=", that.Version);
					var loadWidget = function() {
						var a = new Ajax(jsFile.join(""), {
							"method": "get",
							"evalScripts": true,
							"onComplete": function() {
								Warp.loading.remove(widg.widget);
								oozeElm.widget = new Warp.widgets[widg.widget](oozeElm, widg.options);
								callb(callback, widg.element);
							}
						}).request();
					};
					if(Warp.Language.initialized) {
						loadWidget();
					} else {
						Warp.Language.startup(loadWidget);
					}
				}
			});
		};
		func.delay(0);
		return;
	},

	remote: function(sendObj, callback, path, failCB) {
		var ret = null;
		if(Warp.Trace.active) {
			var uniq = Warp.Trace.uniq;
			var key = uniq + "-> " + $time();

			ret = new Json.Remote(path ? path : "/handleajaj", {
				"onComplete": function(res) {
					var key = uniq + "<- " + $time();
					Warp.Trace.log[key] = {"response": $merge({}, res)};
					callback(res);
				},
				"onFailure": function(res) {
					if(failCB) {
						var key = uniq + "<-FAIL " + $time();
						Warp.Trace.log[key] = {"response": $merge({}, res)};
						failCB(res);
					}
				}
			}).send(sendObj);
			var scrubbed = Warp.Util.clone(sendObj);
			var sPass = null;
			var dPass = null;
			if(scrubbed["warp.system.login"]) {
				//TODO: figure out how/why the real request ever gets "PASSWORD"
				//for now, workaround with sPass and dPass here...
				sPass = scrubbed["warp.system.login"].pass;
				scrubbed["warp.system.login"].pass = "PASSWORD";
			}
			if(scrubbed["mplus.directory.login"]) {
				dPass = scrubbed["mplus.directory.login"].pass;
				scrubbed["mplus.directory.login"].pass = "PASSWORD";
			}

			Warp.Trace.uniq++;
			Warp.Trace.log[key] = {"request": scrubbed};

			if(scrubbed["warp.system.login"]) {
				scrubbed["warp.system.login"].pass = sPass;
			}
			if(scrubbed["mplus.directory.login"]) {
				scrubbed["mplus.directory.login"].pass = dPass;
			}

			Warp.Util.XHRs.push(ret);
			return ret;
		} else {
			ret =  new Json.Remote(path ? path : "/handleajaj", {
				"onComplete": callback,
				"onFailure": failCB || null
			}).send(sendObj);
			Warp.Util.XHRs.push(ret);
			return ret;
		}
	},

	Trace: {
		active: false,
		log: {},
		uniq: 0,

		start: function start() {
			Warp.Trace.active = true;
			Warp.Trace.log = {};
			Warp.Trace.uniq = 0;
		},
		stop: function stop() {
			Warp.Trace.active = false;
		},
		pause: function pause() {
			Warp.Trace.comment("Warp.Trace.pause: tracing paused");
			Warp.Trace.active = false;
		},
		resume: function resume() {
			Warp.Trace.active = true;
			Warp.Trace.comment("Warp.Trace.resume: tracing resumed");
		},
		comment: function comment(str) {
			var uniq = Warp.Trace.uniq;
			var key = uniq + ".. " + $time();
			Warp.Trace.uniq++;
			Warp.Trace.log[key] = {"comment": str};
		},
		report: function report(clear) {
			var log = $merge({}, Warp.Trace.log);
			if(clear) {
				Warp.Trace.log = {};
			}
			return log;
		}
	},

	resizeActive: false,
	globalResizeEventHandler: function (e) {
		if(Warp.resizeActive) {
			return;
		}
		Warp.resizeActive = true;
		$each($$('.hasResizeHandler'), function(element) {
			if($(element) && $(element).widget &&
			   $(element).widget.eventResize) {
				try {
//					alert("resizing " + element.className);
					$(element).widget.eventResize.bind($(element).widget)(e);
				} catch(err) {
//					alert($(element).className + " has no eventResize\n"+Json.toString($(element).widget));
				}
			}
		});
		Warp.resizeActive = false;
	},

	Util: {
		uniq: 0,
		timers: [],
		XHRs: [],

		// mootools claims that $merge() will copy without references,
		// but that has proven to be false.  so, here's a proper copier!
		clone: function (obj) {
			var ClonedObject = function(){};
			ClonedObject.prototype = obj;
			return new ClonedObject();
		},

		smallDate: function (d, skipTime) {
			var nd = null;
			if(d) {
				nd = new Date(d * 1000);
			} else {
				nd = new Date();
			}
			var ret = "";
			if(skipTime) {
				ret = Warp.lang("dateFormat");
				if(ret === "dateFormat") {
					ret = "yyyy-mm-dd";
				}
			} else {
				ret = Warp.lang("dateTimeFormat");
				if(ret === "dateTimeFormat") {
					ret = "yyyy-mm-dd 24H:MM";
				}
			}
			var month = nd.getMonth() + 1;
			var day = nd.getDate();
			var year = nd.getFullYear();
			var hour = nd.getHours();
			var min = nd.getMinutes();
			var ampm = hour >= 12 ? Warp.lang("PM") : Warp.lang("AM");

			if(day < 10) {
				day = "0" + day;
			}
			if(month < 10) {
				month = "0" + month;
			}
			ret = ret.replace("yyyy", year);
			ret = ret.replace("mm", month);
			ret = ret.replace("dd", day);
			if(!skipTime) {
				if(ret.contains("12H")) {
					hour = hour > 12 ? hour - 12 : hour;
				}
				if(hour < 10) {
					hour = "0" + hour;
				} else if(hour > 12 && ret.contains("AP")) {
					hour -= 12;
				}
				if(min < 10) {
					min = "0" + min;
				}
				if(hour == "00" && ret.contains("12H")) {
					hour = 12;
				}
				ret = ret.replace("12H", hour);
				ret = ret.replace("24H", hour);
				ret = ret.replace("MM", min);
				ret = ret.replace("AP", ampm);
			}
			return(ret);
		},

		// return a pretty string for data size, eg. "4.2 KB" or "15 bytes"
		// small will omit "bytes" (but not "KB" etc) and add no space
		// small will omit space and write 100bytes as 0.1KB
		byteSize: function(size, small) {
			var text = [];
			var sizeLabel = Warp.lang("bytes");
			if(size > 1024 || small) {
				size /= 1024;
				sizeLabel = Warp.lang("KB");
			}
			if(size > 1024) {
				size /= 1024;
				sizeLabel = Warp.lang("MB");
			}
			if(size > 1024) {
				size /= 1024;
				sizeLabel = Warp.lang("GB");
			}
			size = Math.round(size * 10) / 10;
			text.push(size);
			if(!small) {
				text.push(" ");
			}
			text.push(sizeLabel);
			return text.join("");
		},

		fixupData:  function (d, i) {
			var ret = [];

			$A(d).each( function( elm, index ) {
				ret.push(
					[d.length - index, elm[i]]
				);
			});
			return ret.reverse();
		},

		uniqueID: function uniqueID() {
			Warp.Util.uniq ++;
			return Warp.Util.uniq;
		},

		delay: function delay(func, delaytime, that, args) {
			var timer = func.delay(delaytime, that, args);
			//Warp.Util.timers.push(timer);  // see window.setTimeout
			return timer;
		},

		periodical: function periodical(func, delay, that) {
			var timer = func.periodical(delay, that);
			//Warp.Util.timers.push(timer);  // see window.setInterval
			return timer;
		},

		clearTimers: function clearTimers() {
			$each(Warp.Util.timers, function(timer) {
				try {
					$clear(timer);
				} catch(e) {
				}
			});
			Warp.Util.timers = [];
			return;
		},

		// kill any timers/XHRs.  call before removing DOM containing active
		// widgets/controls/EXT thingies
		stopEverything: function stopEverything() {
			$each(Warp.Util.XHRs, function(xhr) {
				if(xhr && xhr.cancel) {
					xhr.cancel();
				}
			});
			Warp.Util.XHRs = [];
			Warp.Util.clearTimers();
		},

		// memory cleanup for IE.  we were using in a custom setHTML().
		// disabled since it didn't solve bugs, and since it purges moo funcs.
		purge: function purge(d) {
			var a = d.attributes, i, l, n;
			if (a) {
				l = a.length;
				for (i = 0; i < l; i += 1) {
					n = a[i].name;
					if (typeof d[n] === "function") {
						d[n] = null;
					}
				}
			}
			a = d.childNodes;
			if (a) {
				l = a.length;
				for (i = 0; i < l; i += 1) {
					purge(d.childNodes[i]);
				}
			}
		},

		sameWidth: function sameWidth(elements, clearFirst, noRetry) {
			var width = 0;
			if(clearFirst) {
				$each(elements, function(elm) {
					$(elm).setStyle("width", null);
				});
			}
			var bail = false;
			$each(elements, function(elm) {
				try {
/*
					if($(elm).getSize().size.x > width) {
						width = $(elm).getSize().size.x;
					}
*/
					if(elm.clientWidth > width) {
						width = elm.clientWidth;
					}
				} catch(err) {
					//IE gets non-elements in here if display:none
					bail = true;
				}
			});
			if(bail) {
				return;
			} else if(!width && !noRetry) {
				// not visible yet, try again later
				Warp.Util.sameWidth.delay(100, this, [elements, clearFirst]);
			} else {
				$each(elements, function(elm) {
					$(elm).setStyle("width", width);
				});
			}
		},

		parseURI: function parseURI(str) {
			var uri = {
				"scheme": str.substring(0, str.indexOf(":")),
				"user": "",
				"pass": "",
				"host": "",
				"port": "",
				"path": "",
				"query": "",
				"hash": ""
			};
			var chop = function(string, character) {
				$each(character, function(c) {
					if(string.contains(c)) {
						string = string.substring(0, string.indexOf(c));
					}
				});
				return string;
			};
			try {

				if(str.indexOf("//") < str.indexOf("@")) {
					uri.user = str.substring(str.indexOf("//") + 2,
											 str.indexOf("@"));
					if(uri.user.contains(":")) {
						uri.pass = uri.user.substring(uri.user.indexOf(":") + 1);
						uri.user = uri.user.substring(0, uri.user.indexOf(":"));
					}
				}
				if(str.contains("@")) {
					uri.host = str.substring(str.indexOf("@") + 1);
				} else if(str.contains("//")) {
					uri.host = str.substring(str.indexOf("//") + 2);
				}
				uri.host = chop(uri.host, ["/", "?", "#"]);
				if(uri.host.contains(":")) {
					uri.port = uri.host.substring(uri.host.indexOf(":") + 1);
					uri.port = parseInt(uri.port, null);
					uri.host = uri.host.substring(0, uri.host.indexOf(":"));
				}
				if(str.substring(str.indexOf("//") + 2).contains("/")) {
					uri.path = str.substring(str.indexOf("//") + 2);
					uri.path = uri.path.substring(uri.path.indexOf("/") + 1);
					uri.path = chop(uri.path, ["?", "#"]);
				}
				if(str.contains("?")) {
					uri.query = str.substring(str.indexOf("?") + 1);
					uri.query = chop(uri.query, "#");
				} else if(!uri.path && str.contains(":")) {
					uri.path = str.substring(str.indexOf(":") + 1);
					uri.path = chop(uri.path, ["?", "#"]);
				}
				if(str.contains("#")) {
					uri.hash = str.substring(str.indexOf("#") + 1);
				}
			} catch(e) {
				alert(Json.toString(uri));
			}

			return {
				"scheme": decodeURIComponent(uri.scheme),
				"user": decodeURIComponent(uri.user),
				"pass": decodeURIComponent(uri.pass),
				"host": decodeURIComponent(uri.host),
				"port": decodeURIComponent(uri.port),
				"path": decodeURIComponent(uri.path),
				"query": uri.query,
				"hash": decodeURIComponent(uri.hash)
			};
		},

		parseQuery: function parseQuery(str, sep, arrOnly) {
			var ret = {};
			if(!sep) {
				sep = "&";
			}
			var arr = str.split(sep);
			if(arr.length && !arr[0]) {
				arr = [];
			}
			if(arrOnly) {
				var decoded = [];
				$each(arr, function(val) {
					decoded.push(decodeURIComponent(val));
				});
				return decoded;
			}

			$each(arr, function(part) {
				if(part.contains("=")) {
					var val = decodeURIComponent(part.split("=")[1]);
					ret[part.split("=")[0]] = val;
				} else {
					ret[part] = true;
				}
			});

			return ret;
		},

		splitEscaped: function splitEscaped(str, sep, esc) {
			if(!esc) {
				esc = "\\";
			}
			if(!sep) {
				sep = ".";
			}
			if(!str) {
				return [];
			}
			var arr = [];
			var part = [];
			str = str.split("");
			var escape = false;
			$each(str, function(c) {
				if(c == sep && !escape) {
					arr.push(part.join(""));
					part = [];
					return;
				}
				if(c == esc) {
					escape = true;
				} else {
					part.push(c);
					escape = false;
				}
			});
			if(part.length) {
				arr.push(part.join(""));
			}
			return arr;
		},

		stripHTML: function stripHTML(html) {
			if(!html) {
				return "";
			}
			var tmp = document.createElement("DIV");
			tmp.innerHTML = html;
			return tmp.textContent || tmp.innerText;
		},

		sanitizeHTML: function sanitizeHTML(html) {
			if(!html) {
				return "";
			}
			return html.replace(/<script[\s\S]+?<\/script>|(<[^>]+)\son\w+=(['"])[\s\S]+?\2/gi, "$1");
		},

		validateEmailAddressLocalPart: function validateEmailAddressLocalPart(v) {
			return (/^[A-Za-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+\/=?^_`{|}~-]+)*$/).test(v);
		},

		validateEmailAddress: function validateEmailAddress(v) {
			return (/^[A-Za-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\.)+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?$/).test(v);
		},

        validateIPRange: function validateIPRange(v) {
			var valid = (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(-(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){0,1}$/).test(v);
            if (valid) {
                var ips = v.split("-");
                if (ips.length == 2) {
                    var ipParts0 = ips[0].split(".");
                    var ipParts1 = ips[1].split(".");
                    if (ipParts0[0] > ipParts1[0]) {
                        valid = false;
                    } else if (ipParts0[0] == ipParts1[0]) {
                        if (ipParts0[1] > ipParts1[1]) {
                            valid = false;
                        } else if (ipParts0[1] == ipParts1[1]) {
                            if (ipParts0[2] > ipParts1[2]) {
                                valid = false;
                            } else if (ipParts0[2] == ipParts1[2]) {
                                if (ipParts0[3] >= ipParts1[3]) {
                                    valid = false;
                                }
                            }
                        }
                    }
                }
            }
            return valid;
        },

        X500ToPath: function X500ToPath(x500, root) {
            if (x500) {
                if (root && root.length > 0) {
                    var i = x500.toLowerCase().indexOf("." + root.toLowerCase());

                    if (i != -1) {
                        x500 = x500.substr(0, i);
                    }
                }

                var parts = x500.split('.');
                var path = '';

                /*
                    Deal with the escaped periods

                    Look from the end so that setting a part to null will not prevent finding
                    the next escaped period.
                */

                var i = null;
                for (i = parts.length - 2; i >= 0; i--) {
                    if (parts[i] && parts[i].charAt(parts[i].length - 1) == '\\') {
                        parts[i] = parts[i].substr(0, parts[i].length -1) + '.' + parts[i + 1];
                        parts[i + 1] = null;
                    }
                }

                for (i = (parts.length - 1); i >= 0; i--) {
                    if (parts[i]) {
                        path += '/' + parts[i];
                    }
                }

                if (path.length > 1) {
                    return(path.substr(1));
                }
            }

            return('');
        },

        "getRelativeDN": function(dn) {
            var rdn = "";
            var i = dn.lastIndexOf("\\");
            if (-1 === i) {
                i = dn.lastIndexOf("/");
            }
            rdn = dn.substr(i+1);
            return(rdn);
        }

	},

	//localization
	Language: {
		startup: function(callWhenDone) {
			if(Warp.Language.initialized === true) {
				return;
			}
			var path = "/strings.json?";
			if(Cookie.get("warp-language")) {
				path += "language=" + Cookie.get("warp-language") + "&";
			}
			path += "fallback-lang=en";
			var r = new Json.Remote(path, {
				method: "get",
				onComplete: function(response) {
					Warp.Language.strings = response || {};
					Warp.Language.initialized = true;
					if(typeof(callWhenDone) === "function") {
						callWhenDone();
					}
				}
			}).send();
			return;
		},
		initialized: false,
		strings: {}
	},

	lang: function(str) {
		//if there's a localized string, return it; fall back on passed string
		return Warp.Language.strings[str] || str;
	},

    /*
        For keeping system-wide options.
        Supported option types:
            - boolean (checkbox)
            - discreet (radio buttons)
            - string (single line text entry)
    */
    Options: {
        options: {},

        setOption: function (opt, type, value) {
            Warp.Options.options[opt] = {
                "type": type,
                "value": value
            };
        },

        getOption: function (opt) {
            option = Warp.Options.options[opt] || null;
            if(option) {
                return option.value || null;
            } else {
                return null;
            }
        }
    }
};

//handy GET access
var $GET = {};
$each($A(window.location.search.replace("?", "").split("&")), function(s) {
	$GET[s.split("=")[0]] = decodeURIComponent(s.split("=")[1]);
});

//Handy array extensions
Array.extend({
	pluck: function(property) {
		var results = [];
		this.each(function (value, index) {
			results.push(value[property]);
		});

		return results;
	},

	uniq: function () {
		var results = [];
		this.each(function (value, index) {
			if (!results.contains(value)) {
				results.push(value);
			}
		});

		return results;
	}
});

Element.extend({
	up: function(elements, index){
		elements = $$(elements);
		if(elements.contains(this)) {
			return this;
		}
		index = $pick(index, 1);
		var parent = this;
		while (parent.getParent && (parent = $(parent.getParent()))) {
			if (elements.contains(parent)) {
				index--;
			}
			if (!index) {
				return parent;
			}
		}
		return null;	
/* i suspect this might be just a hair faster than moo's, but i have no proof
	},
	setHTML: function(text){
		this.innerHTML = text || "";
		return this;
*/
	}
});

//We don't want mootools adding "json=" to the post data
//so we're reimplementing Json.Remote here
Json.Remote = XHR.extend({
	initialize: function(url, options){
		this.url = url;
		this.addEvent('onSuccess', this.onComplete);
		this.parent(options);
		this.setHeader('X-Request', 'JSON');
	},

	send: function(obj){
		return this.parent(this.url, Json.toString(obj));
	},

	onComplete: function(){
		this.fireEvent('onComplete', [Json.evaluate(this.response.text, this.options.secure)]);
	}
});

//mootools window.getWidth() and getHeight() return 0 on IE6
window.getWidth = function() {
	if(!window.innerWidth) {
		//IE
		if(document.documentElement.clientWidth !== 0) {
			//strict mode
			return document.documentElement.clientWidth;
		} else {
			//quirks mode
			return document.body.clientWidth;
		}
	} else {
		//w3c
		return window.innerWidth;
	}
};
window.getHeight = function() {
	if(!window.innerWidth) {
		if(document.documentElement.clientWidth !== 0) {
			return document.documentElement.clientHeight;
		} else {
			return document.body.clientHeight;
		}
	} else {
		return window.innerHeight;
	}
};

// override all timer functions to play nicer with other toolkits
window.origSetTimeout = window.setTimeout;
window.setTimeout = function(func, delaytime) {
	var timer = window.origSetTimeout(func, delaytime);
	Warp.Util.timers.push(timer);
	return timer;
};
window.origSetInterval = window.setInterval;
window.setInterval = function(func, delaytime) {
	var timer = window.origSetInterval(func, delaytime);
	Warp.Util.timers.push(timer);
	return timer;
};

// All post-load Warp initialization is done here
window.addEvent("load", function WarpDOM() { //"domready" damn IE!
	Warp.bodyClass();

	//Setup the lightbox widget so that others can use it
	var lightboxDiv = new Element("div", { id: "lightbox" });
	document.getElementsByTagName("BODY")[0].appendChild(lightboxDiv);

	//same goes for notice
/*
	var noticeDiv = new Element("div", { id: "notice" });
	document.getElementsByTagName("BODY")[0].appendChild(noticeDiv);
*/

	Warp.evolve([
		{ element: "lightbox", widget: "lightbox" },
//		{ element: "notice", widget: "notice" }
	]);

	window.addEvent("resize", Warp.globalResizeEventHandler);
/*
*/
});

// load Version from the server
Warp.remote({"warp.ajaj.version": {}}, function(res) {
	try {
		res = res["warp.ajaj.version"];
		var ver = res.major + "." + res.minor;
		if(res.revision) {
			ver += "-" + res.revision + "." + Warp.Util.smallDate(null, true);
		}
		Warp.Version = ver;
	} catch(e) {
		Warp.Version = "unknown." + Warp.Util.smallDate(null, true);
	}
});

