/**
 * handleEffects
 *
 **********
 *
 * Sørger for at køre effekterne.
 */
function handleEffects(){
	// Udregn timestamp
	var time=new Date().getTime();

	// Gennemgå alle effekter
	var i=effects.length; var j=i;
	if(i>0)do{effects[j-i] && effects[j-i].loop(time);}while(--i);
}
effects=[];
setInterval(handleEffects,15);

/**
 * Effect
 *
 **********
 *
 * Håndterer animationer og effekter, der skal køres glidende.
 *
 **********
 *
 * Parametre:
 * handler (function)					Funktion der skal håndtere effekten.
 * settings (array)						Indstillingerne for effekten:
 *										- duration (int): sekunder effekten skal vare
 *										- ease (boolean): skal der eases ind?
 */
function Effect(handler,settings){
	// Indlæs indstillinger
	this.handler=handler;							// Gem handler-funktionen
	this.duration=(settings.duration||1)*1000;		// Hvor længe skal den vare i millisekunder
	this.ease=settings.ease||false;					// Skal der eases?

	// Klargør variabler
	this.pos=0;										// Vi starter ved position 0
	this.last=new Date().getTime();
	this.first=this.last;

	// Tilføj til effect-handleren
	this.effectID=effects.length;
	effects[this.effectID]=this;
}

/**
 * loop
 *
 **********
 *
 * Loopes mens effekten er aktiv, og udregner status.
 *
 **********
 *
 * Parametre:
 * time (int)							Indeholder det nuværende timestamp.
 */
Effect.prototype.loop=function(time){
	// Udregn status for hvor langt animationen er nået uden easeing
	if(!this.ease){
		this.pos+=(time-this.last)/this.duration;
		var pos=this.pos;

	// Udregn status for hvor langt animationen er nået med easeing
	}else{
		var pos=1-Math.min(1,(time-this.first)/this.duration);
		this.pos=1-Math.pow(pos,3);
		var pos=this.pos;
	}

	// Gem det aktuelle timestamp
	this.last=time;

	// Kør handler-funktionen
	if(pos<1){
		this.handler(pos);

	// Afslut animationen
	}else{
		// Kør handleren med 100%
		this.handler(1);

		// Afbryd intervallet
		delete effects[this.effectID];

		// Ryd hukommelsen
		this.handler=null; this.duration=null; this.ease=null; this.totalFrames=null; this.currentFrame=null; this.start=null; this.effectID=null;
	}
}

/**
 * DragDrop
 *
 **********
 *
 * Håndterer drag'n'drop af elementer.
 *
 **********
 *
 * Parametre:
 * e (eventinfo)						Informationer om brugerens inputs.
 * handlers (array)						Angiv en liste over handler-funktioner.
 *										- drag: Køres ved mousemove.
 *										- drop: Køres ved mouseup.
 */
function DragDrop(e,handlers){
	// Indlæs brugerens inputs
	var e=e||window.event;

	// Klargør variabler
	this.handlers=handlers;

	// Håndter drag'n'drop
	if(document.attachEvent){
		document.attachEvent('onmousemove',DragDrop.prototype.drag);
		document.attachEvent('onmouseup',DragDrop.prototype.drop);
	}else{
		document.addEventListener('mousemove',DragDrop.prototype.drag,false);
		document.addEventListener('mouseup',DragDrop.prototype.drop,false);
	}

	// Registrer hvor brugeren klikkede (FF)
	if(e.pageX || e.pageY){
		this.x=e.pageX;
		this.y=e.pageY;

	// ... (IE)
	}else{
		this.x=e.clientX+document.body.scrollLeft-document.body.clientLeft;
		this.y=e.clientY+document.body.scrollTop-document.body.clientTop;
	}

	// Gem informationerne i browserens hukommelse
	dragObject=this;

	// Fortæl browseren, at den ikke skal håndtere drag'n'drop
	stopEvent(e);
}

/**
 * drag
 *
 **********
 *
 * Håndterer mousemove-eventet, når der drag'n'droppes.
 *
 **********
 *
 * Parametre:
 * e (eventinfo)						Indeholder informationer om brugerens input.
 */
DragDrop.prototype.drag=function(e){
	// Registrer musens bevægelse
	if(e.pageX || e.pageY){
		var x=e.pageX-dragObject.x;
		var y=e.pageY-dragObject.y;

	// ... (IE)
	}else{
		var x=e.clientX+document.body.scrollLeft-document.body.clientLeft-dragObject.x;
		var y=e.clientY+document.body.scrollTop-document.body.clientTop-dragObject.y;
	}

	// Send informationerne om musens bevægelse tilbage til handleren
	dragObject.handlers.drag(dragObject.handlers.element,x,y);

	// Fortæl browseren, at den ikke skal håndtere drag'n'drop
	stopEvent(e);
}

/**
 * drop
 *
 **********
 *
 * Håndterer mouseup-eventet, når der drag'n'droppes.
 *
 **********
 *
 * Parametre:
 * e (eventinfo)						Indeholder informationer om brugerens input.
 */
DragDrop.prototype.drop=function(e){
	// Registrer musens bevægelse
	if(e.pageX || e.pageY){
		var x=e.pageX-dragObject.x;
		var y=e.pageY-dragObject.y;

	// ... (IE)
	}else{
		var x=e.clientX+document.body.scrollLeft-document.body.clientLeft-dragObject.x;
		var y=e.clientY+document.body.scrollTop-document.body.clientTop-dragObject.y;
	}

	// Send informationerne om musens bevægelse tilbage til handleren
	dragObject.handlers.drop(dragObject.handlers.element,x,y);

	// Afbryd drag'n'drop-håndtering
	if(document.detachEvent){
		document.detachEvent('onmousemove',DragDrop.prototype.drag);
		document.detachEvent('onmouseup',DragDrop.prototype.drop);
	}else{
		document.removeEventListener('mousemove',DragDrop.prototype.drag,false);
		document.removeEventListener('mouseup',DragDrop.prototype.drop,false);
	}

	// Ryd browserens hukommelse
	dragObject=null;

	// Fortæl browseren, at den ikke skal håndtere drag'n'drop
	stopEvent(e);
}

/**
 * stopEvent
 *
 **********
 *
 * Afbryder eksekveringen af et event på kryds af browsere.
 *
 **********
 *
 * Parametre:
 * e (eventinfo)						Informationer om brugerens input.
 */
function stopEvent(e){
	// Stop eventet på alle tænkelige måder
	if(e.preventDefault) e.preventDefault();
	if(e.stopPropagation) e.stopPropagation();
	if(e.stop) e.stop();
	if(document.all&&e.keyCode) try{e.keyCode=0;}catch(e){}
	e.cancelBubble=true;
	e.returnValue=false;
}
