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

Written by:
 Owen J. Swerkstrom
 Joshua C. Faul
 Micah N. Gorrell

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 {
			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: [],

	evolve: function(widgetList, callback) {
		var that = this;
		if(!callback) {
			callback = function(element) {};
		}
		// a-synchronize this function
		var func = function() {
			$each(widgetList, function(widg) {
				var oozeElm = $(widg.element);

				if(Warp.widgets[widg.widget]) {
					// we have the widget code, no need to load
					oozeElm.widget = new Warp.widgets[widg.widget](oozeElm, widg.options);
					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);
							callback(widg.element);
						} else {
							check.delay(100);
						}
					};
					check.delay(100);
				} 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);
							}
						}).request();
					};
					if(Warp.Language.initialized) {
						loadWidget();
					} else {
						Warp.Language.startup(loadWidget);
					}
				}
			});
		};
		func.delay(0);
		return;
	},

	remote: function(sendObj, callback, path) {
		return new Json.Remote(path ? path : "/handleajaj", {
			"onComplete": callback
// sometimes null's out response in safari... "secure": true
// likely a bug in mootools
		}).send(sendObj);
	},

	globalResizeEventHandler: function (e) {
		$each($$('.hasResizeHandler'), function(element) {
			if($(element) && $(element).widget && $(element).widget.element) {
				$(element).widget.eventResize(null);
			}
		});
		return;
	},

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

		smallDate: function (d, skipTime) {
			var nd = new Date(d * 1000);
			var ret = "";
			if(skipTime) {
				ret = "yyyy-mm-dd";
				ret = Warp.lang("dateFormat");
			} else {
				ret = "yyyy-mm-dd 24H:MM";
				ret = Warp.lang("dateTimeFormat");
			}
			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);
			return timer;
		},

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

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

		// 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) {
			var width = 0;
			$each(elements, function(elm) {
				if(elm.getSize().size.x > width) {
					width = elm.getSize().size.x
				}
			});
			$each(elements, function(elm) {
				elm.setStyle("width", width);
			});
		},

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

	//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(string) {
		//if there's a localized string, return it; fall back on passed string
		return Warp.Language.strings[string] || string;
	}
};

//handy GET access
var $GET = {};
$each($A(window.location.search.replace("?", "").split("&")), function(s) {
	$GET[s.split("=")[0]] = unescape(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;
	}
};

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

	window.addEvent("resize", Warp.globalResizeEventHandler);

	//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" }
	]);
});

// 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.Version = ver;
	} catch(e) {
		Warp.Version = "unknown";
	}
});
