(function($){
	$.fn.slideDownFadeIn = function(fn){
		$(this).css("opacity",0).slideDown(400, function(){
			if (fn) fn();
		}).fadeTo(300, 1).dequeue();
	}
	$.fn.slideUpFadeOut = function(fn){
		$(this).css("opacity",1).slideUp(400, function(){
			if (fn) fn();
		}).fadeTo(300, 0).dequeue();
	}
})($);


//ajax
var Ajax = {
	showErrors: false,
	handlers: [],
	queue: [],
	
	bindHandler: function(name, fn){ Ajax.handlers[name]=fn; },
	unbindHandler: function(name, fn){ Ajax.handlers[name]=null; },
	
	createObject: function(call, params, id){
		//when this ajax is done, shift the queue and do the next if necessary.
		var ajaxObj = {};
		ajaxObj.id = id;
		ajaxObj.params = params;
		ajaxObj.errors = [];
		ajaxObj.handler = null;
		ajaxObj.go = function(){ 
			if (typeof this.params == "object"){
				var str="ajaxcall=" + call;
				for (var key in this.params){
					str += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(this.params[key]);
				}
				this.params = str;
			}else{
				this.params = "ajaxcall=" + call + "&" + this.params;
			}
			Ajax.enqueue(this); 
		}
		if (Ajax.showErrors){
			ajaxObj.onComplete = function(){
				for (var i=0; i<this.errors.length; i++) { 
					//if (this.errors[i].exception) throw this.errors[i].exception;
					//else 
					alert("Error (Ajax.showErrors is on):\n" + this.errors[i].message); 
				};
			}
		};
		return ajaxObj;
	},
	
	//creates ajaxObj and enqueues it.
	enqueue: function(ajaxObj){
		if (ajaxObj.id){
			//dont add to queue if duplicate is found.
			for (var i=0;i<Ajax.queue.length;i++){
				if (Ajax.queue[i].id == ajaxObj.id) return;
			}
		}
		
		//push onto queue, start ajax if necessary.
		Ajax.queue.push(ajaxObj);
		if (Ajax.queue.length==1) {
			Ajax.onStart();
			Ajax.doAjax(ajaxObj);
		}
	},
	
	//creates xhr, adds to ajaxObj, sends it.
	doAjax: function(ajaxObj){
		var xhr; 
		if (window.XMLHttpRequest){//Mozilla, Safari,...
			xhr = new XMLHttpRequest();
			if (xhr.overrideMimeType) xhr.overrideMimeType('text/xml');
		}else if (window.ActiveXObject){//IE
			try {xhr = new ActiveXObject("Msxml2.XMLHTTP");} catch (e) {
				try {xhr = new ActiveXObject("Microsoft.XMLHTTP");} catch (e){}
			}
		}
		ajaxObj.xhr = xhr;
		
		xhr.open('POST', '/ajax.php', true);
		xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		xhr.setRequestHeader("Content-length", ajaxObj.params.length);
		xhr.setRequestHeader("Connection", "close");
		xhr.onreadystatechange = function(){
			if (xhr.readyState == 4) { 
				if (xhr.status==200) { Ajax.handleAjax(ajaxObj); }
				//else{ crap. }
			}
		};
		xhr.send(ajaxObj.params);
	},
	
	handleAjax: function(ajaxObj){
		var responseText = ajaxObj.xhr.responseText;
		
		//load response object.
		try{
			eval("var response = " + responseText + ";");
		}catch(e){
			ajaxObj.errors.push({
				"exception" : e,
				"message" : "Invalid response received from server (not a JSON object, or incorrect formatting)\n" + responseText + ""
			});
			var response = {};
		}
		
		//handle it with explicit handler. todo: try catch errors here.
		if (ajaxObj.handler) ajaxObj.handler(response.custom || {});

		//handle with our framework
		var commands = response.commands || [];
		for (var i=0; i<commands.length; i++){
			var command = commands[i];
			var type = command.type;
			if (!Ajax.handlers[command.type]) {
				ajaxObj.errors.push({
					"message" : "No ajax handler of type: " + type
				});
				continue;
			}
			
			try {
				Ajax.handlers[type](command.params);
			}catch (e){
				ajaxObj.errors.push({
					"exception" : e,
					"message" : "Error parsing command of type: " + type
				});
				throw e;
			}
		}
		if (ajaxObj.onComplete) ajaxObj.onComplete();
		
		Ajax.queue.shift();
		if (Ajax.queue[0]) Ajax.doAjax(Ajax.queue[0]);
		else Ajax.onStop();
	},
	
	contentHooks: [],
	addContentHook: function(hook, execute){ 
		this.contentHooks.push(hook); 
		if (execute) $(function(){ hook(document.body); });
	},
	onNewContent: function(parent){
		for(var i=0; i<this.contentHooks.length; i++) this.contentHooks[i](parent);
	},
	
	onStart: function(){},
	onStop: function(){},
	
	parseForm: function(form){
		var getValue = function(e){
			if (e.type=="text" || e.type=="hidden" ||
			e.type=="password" || e.type=="textarea" ||
			e.type=="select-one") return e.value;
			else if (e.type=="checkbox" && e.checked) return e.value;
			else if (e.type=="radio" && e.checked) return e.value;
			else return false;
		}
	
		var data = [];
		for (var i=0; i<form.elements.length; i++){//for each element
			var e = form.elements[i];
			if (!e.name) continue;
			var val = getValue(e);
			if (val===false) continue;
			data.push(e.name + "=" + encodeURIComponent(val));
		}
		return data.join('&');
	}
};

/*
 * jQuery Color Animations
 * Copyright 2007 John Resig
 * Released under the MIT and GPL licenses.
 */
(function(jQuery){

	// We override the animation for all of these color styles
	jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){
		jQuery.fx.step[attr] = function(fx){
			if ( fx.state == 0 ) {
				fx.start = getColor( fx.elem, attr );
				fx.end = getRGB( fx.end );
			}

			fx.elem.style[attr] = "rgb(" + [
				Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
			].join(",") + ")";
		}
	});

	// Color Conversion functions from highlightFade
	// By Blair Mitchelmore
	// http://jquery.offput.ca/highlightFade/

	// Parse strings looking for color tuples [255,255,255]
	function getRGB(color) {
		var result;

		// Check if we're already dealing with an array of colors
		if ( color && color.constructor == Array && color.length == 3 )
			return color;

		// Look for rgb(num,num,num)
		if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
			return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];

		// Look for rgb(num%,num%,num%)
		if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
			return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];

		// Look for #a0b1c2
		if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
			return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];

		// Look for #fff
		if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
			return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];

		// Otherwise, we're most likely dealing with a named color
		return colors[jQuery.trim(color).toLowerCase()];
	}
	
	function getColor(elem, attr) {
		var color;

		do {
			color = jQuery.curCSS(elem, attr);

			// Keep going until we find an element that has color, or we hit the body
			if ( color != '' && color != 'transparent' || jQuery.nodeName(elem, "body") )
				break; 

			attr = "backgroundColor";
		} while ( elem = elem.parentNode );

		return getRGB(color);
	};
	
	// Some named colors to work with
	// From Interface by Stefan Petre
	// http://interface.eyecon.ro/

	var colors = {
		aqua:[0,255,255],
		azure:[240,255,255],
		beige:[245,245,220],
		black:[0,0,0],
		blue:[0,0,255],
		brown:[165,42,42],
		cyan:[0,255,255],
		darkblue:[0,0,139],
		darkcyan:[0,139,139],
		darkgrey:[169,169,169],
		darkgreen:[0,100,0],
		darkkhaki:[189,183,107],
		darkmagenta:[139,0,139],
		darkolivegreen:[85,107,47],
		darkorange:[255,140,0],
		darkorchid:[153,50,204],
		darkred:[139,0,0],
		darksalmon:[233,150,122],
		darkviolet:[148,0,211],
		fuchsia:[255,0,255],
		gold:[255,215,0],
		green:[0,128,0],
		indigo:[75,0,130],
		khaki:[240,230,140],
		lightblue:[173,216,230],
		lightcyan:[224,255,255],
		lightgreen:[144,238,144],
		lightgrey:[211,211,211],
		lightpink:[255,182,193],
		lightyellow:[255,255,224],
		lime:[0,255,0],
		magenta:[255,0,255],
		maroon:[128,0,0],
		navy:[0,0,128],
		olive:[128,128,0],
		orange:[255,165,0],
		pink:[255,192,203],
		purple:[128,0,128],
		violet:[128,0,128],
		red:[255,0,0],
		silver:[192,192,192],
		white:[255,255,255],
		yellow:[255,255,0]
	};
	
})(jQuery);

//essentially is main.js
(function($){
	//returns a transparent cover the size of the window
	$.getCover = function(){
		if ($("#Cover").length==0){
			var cover = $("<div id='Cover'></div>")
				.css({
					position: "absolute",
					display: "none",
					opacity: .3,
					background: "black",
					top: 0,
					left: 0,
					width: "100%"
				})
				.appendTo(document.body);	
			
			cover.height(Math.max($(window).height(), $(document.body).height()));
		}
		return $("#Cover");
	}
	
	$.getSelection = function(){
		if (window.getSelection){
			return window.getSelection().toString();
		}else if (document.getSelection){
			return document.getSelection();
		}else if (document.selection){
			return document.selection.createRange().text;
		}
	}
	
	$.addEvent = function(obj, eventname, userfn){
		//the true body.
		var truebody = (document.compatMode && document.compatMode!="BackCompat") ? document.documentElement : document.body;
			
		//wrap userfunction so that event is fixed and "this" keyword carries over
		var fn = function(e){
			//fixed_e = $.event.fix(e || window.event); //too slow in IE.
			var e = e || window.event;
			var fixed_e = {};
			fixed_e.pageX = document.all ? e.clientX + truebody.scrollLeft : e.pageX;
			fixed_e.pageY = document.all ? e.clientY + truebody.scrollTop : e.pageY;
			fixed_e.X = (e.offsetX ? e.offsetX : e.layerX) || 0;
			fixed_e.Y = (e.offsetY ? e.offsetY : e.layerY) || 0;
			fixed_e.source = e.target ? e.target : e.srcElement;
			userfn.call(obj, fixed_e);
		}

		//return the handle
		var handle = {};
		handle.remove = function(){
			if (document.removeEventListener) obj.removeEventListener(eventname, fn, false);
			else obj.detachEvent('on'+eventname, fn);
		}
		handle.attach = function(){
			if (document.addEventListener) obj.addEventListener(eventname, fn, false);
			else obj.attachEvent('on'+eventname, fn);		
		}
		handle.trigger = function(){ userfn.call(obj); }
		handle.attach();
		return handle;
	}
	$.fn.addEvent = function(eventname, fn){ return this.each(function(){ $.addEvent(this, eventname, fn); }); }
	
	
	var shield = null;
	$.stopShield = function(){};
	$.startShield = function(){
		//instantiate and/or position shield
		if (!shield){
			shield = document.createElement("div");
			shield.style.position = "absolute"; shield.style.left=shield.style.top="0px";
			shield.style.width = "100%"; shield.style.zIndex = "9999999";
			if ($.browser.msie) shield.style.background = "url(about:blank)";
			document.body.appendChild(shield);
		}
		var truebody = (document.compatMode && document.compatMode!="BackCompat") ? document.documentElement : document.body;
		shield.style.height=truebody.scrollHeight+"px";
		shield.style.display='block';
		
		$.stopShield = function(){
			setTimeout(function(){ shield.style.display='none'; }, 10); //FF select fix
			$.stopShield = function(){};
		}
	}
	
	$.resetSelect = function(){}
	$.stopSelect = function(){
		var old_moz = document.body.style.MozUserSelect;
		var old_unselect = document.body.style.unselectable;
		var old_selectstart = document.body.onselectstart;
		document.body.style.MozUserSelect = "none";
		document.body.style.unselectable = "on"; 
		document.body.onselectstart = function(){ return false; };

		$.resetSelect = function(){
			document.body.style.MozUserSelect = old_moz;
			document.body.style.unselectable = old_unselect; 
			document.body.onselectstart = old_selectstart;			
		}
	}

	$.fn.setDrag = function(params){
		var offset = params.offset || 0;
		var user_start = params.start || function(){};
		var user_move = params.move || function(){};
		var user_end = params.end || function(){};
		var doubleMove = params.doubleMove || false;
		var shield = params.shield || false;
			
		return this.each(function(){
			var me = this;
			me.style.MozUserSelect = "none";
			me.style.unselectable = "on"; 
			me.onselectstart = function(){ return false; };

			var initialized, h_start, h_preMove, h1, h2;
			var start = function(e){
				h_start.remove();
				
				var start_x = e.pageX, start_y = e.pageY, h1, h2;
				var preMove = function(e){
					var dist = Math.sqrt(Math.pow((e.pageX - start_x),2) + Math.pow((e.pageY - start_y),2));
					if (dist >= offset){
						h_preMove.remove();
						$.stopSelect();
						if (shield) $.startShield();
						h1 = $.addEvent(document, "mousemove", function(e){ user_move.call(me, e); });
						if (doubleMove) h2 = $.addEvent(document, "mousemove", function(e){ user_move.call(me, e); });
						initialized = true;
						user_start.call(me, e);
						user_move.call(me, e);
					}
				}
				var h_preMove = $.addEvent(document, "mousemove", preMove);
		
				var end = function(e){
					h_preMove.remove();
					$(document).unbind("mouseup", end);
					if (initialized) {
						$.resetSelect();
						if (shield) $.stopShield();
						initialized = false;
						h1.remove();
						if (doubleMove) h2.remove();
						user_end.call(me, e);
					}
					h_start.attach();
				}
				$(document).bind("mouseup", end);
			}
			
			h_start = $.addEvent(me, "mousedown", start);
		});
	};
})($);
