/* domready events { */
function $domready(func,priority) {
	if (!$domready._list) $domready._list=[];
	if ($domready._loaded) func.delay(1);
	if (priority===undefined) priority=5;
	$domready._list.push({func:func,priority:priority});
}
$domready.loadAll=function () {
	$domready._loaded=true;
	if (!$domready._list) return;

	$domready._list.sort(function (a,b) {
		return a.priority-b.priority;
	});

	$domready._list.each(function (o) {
		o.func.call(window);
	});
	delete $domready._list;
};

function $DL() { $domready.apply(this,arguments); }

window.addEvent("domready",$domready.loadAll);
/* } domready events */

function addNamespace(ns) {
	if (!ns) return null;
	var levels=ns.split(".");
	var root=window;
	for (var i=0;i<levels.length;i++) {
		if (root[levels[i]]==undefined) root[levels[i]]={};
		root=root[levels[i]];
	}
	return root;
}

// TODO: make a function to add key and get new url without redirecting
// TODO: inherit Hash?
var QueryManager=new Class({
	data:null,
	// data - a key value collection
	initialize:function (data) {
		this.data=data;
	},
	add:function (keyValueCollection) {
		if (!(keyValueCollection instanceof Hash)) keyValueCollection=new Hash(keyValueCollection);

		this.data.extend(keyValueCollection);

		this.data.each(function (value,key) {
			if (key===null) this.data.erase(key);
		},this);

		this._redirect();
	},
	remove:function (names) {
		for (var i=0;i<names.length;i++) this.data.erase(names[i]);
	},
	get:function (key) {
		return this.data.get(key);
	},
	_redirect:function () {
		location.href=this.getUrl();
	},
	// abstract function
	getUrl:function () { throw new Error("not implemented"); }
});

var QueryStringManager=new Class({
	Extends:QueryManager,
	
	initialize:function () {
		var data=new Hash();
		location.search.substr(1).replace(/(.*?)=(.*?)(?:&|$)/g,function (match,key,value) {
			data.set(key,decodeURIComponent(value));
		});
		this.parent(data);
	},
	remove:function (names) {
		this.parent(names);
		return this;
	},
	getUrl:function () {
		return "?"+this.data.toQueryString();
	}
});

/* UrlQuery Manager */
var UrlQueryManager=new Class({
	Extends:QueryManager,

	initialize:function () {
		var data=new Hash();
		if (UrlQueryManager.query) UrlQueryManager.query.replace(/(.*?)(?:=(.*?))?(?:&|\/|$)/g,function (match,key,value) {
			if (key) data.set(key,value ? decodeURIComponent(value) : null);
		});
		this.parent(data);
	},
	get:function (key) {
		if (typeof(key)=="number") return this.data.getKeys()[key];
		return this.parent(key);
	},
	getUrl:function () {
		var extLess=UrlQueryManager.useExtensionlessUrlRewriting;
		var qsPrefix=extLess ? "/" : "?",
			delimeter=extLess ? "/" : "&";

		var urlQuery=[];
		this.data.each(function (value,key) {
			$splat(value).each(function(val) {
				if (val) val=val.toString().trim();
				if (!val && extLess) urlQuery.push(key); // only key
				else urlQuery.push(key+"="+encodeURIComponent(val)); // key and value
			});
		});
		
		return UrlQueryManager.pageUrl+qsPrefix+urlQuery.join(delimeter);
	}
});

// UQ.add({a:1})

var QS,UQ;
$domready(function () {
	QS=new QueryStringManager();
	UQ=new UrlQueryManager();
},2);

function h(o,funcs,showFuncContent) {
	if (o==null) return "[null]";
	var s=[];
	for (var i in o) {
		switch ($type(o[i])) {
			case "function":
				if (funcs) s.push(i+"\t\t"+(showFuncContent ? o[i] : o[i].toString().trim().substr(0,o[i].toString().search(/\r|\n|\{/))));
				break;
			case "array": s.push(i+"\t\t["+o[i].length+"]");
				break;
			default: s.push(i+"\t\t"+o[i]);
		}
	}
	return "\r\n"+s.join("\r\n")+"\r\n";
}
function r() { alert($A(arguments).join("\n")); };


// default failure for ajax requests
function $ajaxFailure(xh) {
	//r.apply(null,arguments);
	var err="";
	if (/<title>(.*?)<\/title>/.test(xh.responseText)) err=RegExp.$1;
	err=err.replace(/<.*?>/g,"");
	alert("Ajax Error: "+err);
}

function getAjaxDate(dateString) {
	var date=null;
	if (/Date\((\d+)\)/.test(dateString)) date=new Date(+RegExp.$1);
	return date;
}

function $waitUntil(waitUntil,onComplete,delay,timeout) {
	switch ($type(waitUntil)) {
		case "string":
			if (waitUntil.contains(",")) waitUntil=waitUntil.split(",");
			else waitUntil=[waitUntil];
			$waitUntil(waitUntil,onComplete,delay);
			return;
		case "array":
			var variableNames=waitUntil;
			waitUntil=function () {
				// check for all types, if one of them is undefined, return false
				for (var i=0;i<variableNames.length;i++) {
					var name=variableNames[i];
					if (name.contains(".")) {
						var parts=name.split(".");
						var temp=window;
						// if one of the parts of the object is still undefined, return false
						for (var j=0;j<parts.length;j++) {
							temp=temp[parts[j]];
							if (!temp) return false;
						}
					}
					if (window[name]==undefined) return false;
				}
				return true;
			};
			$waitUntil(waitUntil,onComplete,delay);
			return;
		case "function":
			break;
		default:
			throw new Error("Argument "+waitUntil+" is invalid for $waitUntil");
	}

	if (waitUntil()) {
		onComplete();
		return;
	}

	var timeoutPointer;
	var intervalPointer=function () {
		if (!waitUntil()) return;
		intervalPointer=$clear(intervalPointer);
		if (timeoutPointer) timeoutPointer=$clear(timeoutPointer);
		onComplete();
	}.periodical(delay || 100);
	// if after timeout ms function doesn't return true, abort
	if (timeout) timeoutPointer=function () {
		dbug.log("$waitUntil timed out.",waitUntil);
		intervalPointer=$clear(intervalPointer);
	}.delay(timeout);
}

/*
var glob=0;

$waitUntil(
	function () {
		console.log('glob');
		return glob==1;
	},
	function () {
		alert('glob!');
	},
	100
);
(function () { glob=1; }).delay(2000);
*/

// all external links opened in new window by default
// if you want to override this default behavior, put event on a link and stop propagation
/*$domready(function () {
	$(document.body).delegateEvent("click","a",function (e) {
		if (this.rel=="External" || this.hasClass("external") || !this.href.indexOf(Config.siteUrl)==0) {
			open(this.href);
			e.stop();
		}
	});
});*/

/* fix selects and labels on ie6 */
if (Browser.Engine.trident4) {
	$$("select").addEvents({
		focusin:function (e) { this.store("tempIndex",this.selectedIndex); },
		focus:function (e) { this.selectedIndex=this.retrieve("tempIndex"); }
	});
}

/*<debug>*/
(function () {
	if (!Browser.Engine.gecko) return;
	var _emptyTags=["img","br","input","meta","link","param","hr"];
	HTMLElement.prototype.__defineGetter__("outerHTML",function () {
		var attrs=this.attributes;
		var tag=this.tagName.toLowerCase();
		var str="<"+tag;
		for (var i=0;i<attrs.length;i++) str+=" "+attrs[i].name+"=\""+attrs[i].value+"\"";
		if (_emptyTags.indexOf(tag)) return str+"/>";
		return str+">"+this.innerHTML+"</"+tag+">";
	});
})();
/*</debug>*/