var keys = new Array();
var times = new Array();
//Created so that onkeydown would loop until the key is up

function catchKeyEvent(func) {
	if (document.addEventListener) {
		document.addEventListener("keydown",function (event) {var e = event || window.event;var code = e.charCode || e.keyCode;keys[code] = true;run(func,event,200);}, false);
		document.addEventListener("keyup",function (event) {var e = event || window.event;var code = e.charCode || e.keyCode;keys[code] = false; clearTimeout(times[code]);}, false);
	} else if (document.attachEvent) {
		document.attachEvent("onkeydown",function (event) {var e = event || window.event;var code = e.charCode || e.keyCode;keys[code] = true;run(func,event,200);});
		document.attachEvent("onkeyup",function (event) {var e = event || window.event;var code = e.charCode || e.keyCode;keys[code] = false; clearTimeout(times[code]);}, false);
	} else {
		document.onkeydown=function (event) {var e = event || window.event;var code = e.charCode || e.keyCode;keys[code] = true;run(func,event,200);};
		document.onkeyup=function (event) {var e = event || window.event;var code = e.charCode || e.keyCode;keys[code] = false; clearTimeout(times[code]);};
	}
}
function run(func,event,time) {	
	var e = event || window.event;
	var code = e.charCode || e.keyCode;
	if (keys[code] != true) return;
	if (!func(event)) return;
	var left = time - 20;
	if (left < 20) left = 20;
	times[code] = setTimeout(function () {run(func,event,left);},left);
}
//Find Pos
//Finds Position of object
function findPos(obj) {
	//Dummy
}
//Physics Fun
//Invokes physics on the elements within this object. Everything will fall.
function Phys(obj) {
	//Dummy
	//alert(obj.offsetTop+":"+obj.offsetLeft+":"+obj.offsetWidth+":"+obj.offsetHeight);
}
//Collision
function Circle(x,y,r) {
	this.x = x;
	this.y = y;
	this.r = r;
	this.toString = function() {
		return "[x="+this.x+",y="+this.y+",r="+this.r+"]";
	}
	this.move = function(x,y) {
		this.x += x;
		this.y += y;
	}
}
function Rect(x,y,w,h) {
	this.x = x;
	this.y = y;
	this.h = h;
	this.w = w;
	this.x1 = x-w/2;//BL
	this.y1 = y-h/2;//BL
	this.x2 = x+w/2;//TR
	this.y2 = y+h/2;//TR
	this.toString = function() {
		return "[x="+this.x+",y="+this.y+",w="+this.w+",h="+this.h+"]";
	}
	var me = this;
	this.move = function(x,y) {
		this.x += x;
		this.y += y;
		this.x1 += x;
		this.y1 += y;
		this.x2 += x;
		this.y2 += y;
	}
}
var sep = new Array();//The stack that holds all objects to push apart
//A value is pushed onto the stack when the collision checkers are called and there is a collision.
function Separate(obj1,obj2,x1,y1,x2,y2) {//Separates the two collided objects
	this.obj1 = obj1;
	this.obj2 = obj2;
	this.x1 = x1;
	this.y1 = y1;
	this.x2 = x2;
	this.y2 = y2;
	//this.pos = sep.length;
	sep.push(this);
	//alert(x1+":"+y1+":"+x2+":"+y2);
	this.separate = function () {
		this.obj1.move(this.x1,this.y1);
		this.obj2.move(this.x2,this.y2);
		this.remove();
	}
	this.moveFirst = function () {
		this.obj1.move(this.x1-this.x2,this.y1-this.y2);
		this.remove();
	}
	this.moveSecond = function () {
		this.obj2.move(this.x2-this.x1,this.y2-this.y1);
		this.remove();
	}
	this.remove = function() {
		//sep.pop(this.pos);
		//sep.splice(this.pos,1);
		for (var a = 0;a < sep.length;a++){
			if (sep[a] == this) {
				sep.splice(a,1);
				break;
			}
		}
	}
	this.toString = function() {
		return "("+this.obj1+","+this.obj2+")";
	}
}
function collisionRR(s1,s2) {
	if (s1.x1 < s2.x2 && s1.x2 > s2.x1 && s1.y1 < s2.y2 && s1.y2 > s2.y1) {
		var xmove = s1.w/2+s2.w/2-Math.abs(s1.x-s2.x);
		var ymove = s1.h/2+s2.h/2-Math.abs(s1.y-s2.y);
		if (xmove < ymove) {
			if (s1.x < s2.x) {
				new Separate(s1,s2,-xmove/2,0,xmove/2,0);
			} else {
				new Separate(s1,s2,xmove/2,0,-xmove/2,0);
			}
		} else {
			if (s1.y < s2.y) {
				new Separate(s1,s2,0,-ymove/2,0,ymove/2);
			} else {
				new Separate(s1,s2,0,ymove/2,0,-ymove/2);
			}
		}
		return true;
	} else {
		return false;
	}
}
function collisionRC(s,c) {	
	//alert(s.x1+":"+s.x2+":"+s.y1+":"+s.y2+":"+s+":"+c);
	if (!(s.x1-c.r < c.x && s.x2+c.r > c.x && s.y1-c.r < c.y && s.y2+c.r > c.y)) {
		return false;
	}
	if (s.x1 < c.x && s.x2 > c.x && s.y1 < c.y && s.y2 > c.y) {// Inside
		var xmove = s.w/2+c.r-Math.abs(s.x-c.x);
		var ymove = s.h/2+c.r-Math.abs(s.y-c.y);
		if (xmove < ymove) {
			if (s.x < c.x) {
				new Separate(s,c,-xmove/2,0,xmove/2,0);
			} else {
				new Separate(s,c,xmove/2,0,-xmove/2,0);
			}
		} else {
			if (s.y < c.y) {
				new Separate(s,c,0,-ymove/2,0,ymove/2);
			} else {
				new Separate(s,c,0,ymove/2,0,-ymove/2);
			}
		}
		return true;
	} else if (s.x1 < c.x && s.x2 > c.x && s.y1-c.r < c.y && s.y2+c.r > c.y) {//On Verticle Edge
		var down = c.y-(s.y1-c.r);
		var up = (s.y2+c.r)-c.y;
		if (down < up)
			new Separate(s,c,0,down/2,0,-down/2);
		else
			new Separate(s,c,0,-up/2,0,up/2);
		return true;
	} else if (s.x1-c.r < c.x && s.x2+c.r > c.x && s.y1 < c.y && s.y2 > c.y) {//On Horizontal Edge
		var down = c.x-(s.x1-c.r);
		var up = (s.x2+c.r)-c.x;
		if (down < up)
			new Separate(s,c,down/2,0,-down/2,0);
		else
			new Separate(s,c,-up/2,0,up/2,0);
		return true;
	} else {// At a corner
		//var count = sep.length;
		var c1 = new Circle(s.x2,s.y2,0);
		var c2 = new Circle(s.x1,s.y2,0);
		var c3 = new Circle(s.x2,s.y1,0);
		var c4 = new Circle(s.x1,s.y1,0);
		if (collisionCC(c1,c) || collisionCC(c2,c) || collisionCC(c3,c) || collisionCC(c4,c)) {//Make sure it isn't in the outer corner area.
			//while (sep.length > count) sep.pop();//The Collisions Added objects
			//Keep Object so user can move the circle when needed.
			sep[sep.length-1].obj1 = s;//Change it to the rectangle. We don't want to move a corner circle.
			return true;//It's ok
		}
	}
	return false;
}
function collisionCC(c1,c2) {
	var dist = Math.sqrt(Math.pow(c1.x - c2.x,2) + Math.pow(c1.y - c2.y,2));
	var least = c1.r + c2.r;
	var move = least - dist;
	var angle = Math.atan2(c2.y - c1.y,c2.x - c1.x);
	if (dist < least) {
		//alert(angle/Math.PI*180);
		new Separate(c1,c2,Math.cos(Math.PI+angle)*move,Math.sin(Math.PI+angle)*move,Math.cos(angle)*move,Math.sin(angle)*move);
		return true;
	} else {
		return false;
	}
}
function collision(obj1,obj2) {
	if (getType(obj1) == "Circle" && getType(obj2) == "Circle") {
		return collisionCC(obj1,obj2);
	} else if (getType(obj1) == "Rect" && getType(obj2) == "Rect") {
		return collisionRR(obj1,obj2);
	} else if (getType(obj1) == "Circle" && getType(obj2) == "Rect") {
		return collisionRC(obj2,obj1);
	} else if (getType(obj1) == "Rect" && getType(obj2) == "Circle") {
		return collisionRC(obj1,obj2);
	}
	return null;
}
//Gets type
function getType(obj) {
	var text = obj.constructor.toString();
	text = text.replace(/function /,"");
	text = text.replace(/\((.|\n)*/,"");
	return text;
}
//Creates a xmlhttp object for data requests
/*var xmlhttp = false;
if (window.XMLHttpRequest) {
	xmlhttp = new XMLHttpRequest();
	if (xmlhttp.overrideMimeType) xmlhttp.overrideMimeType('text/xml');
} else if (window.ActiveXObject) {
	xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}*/
