AnimationService = {
	INTERVAL : 30,																// Default delay between steps
	STEP : 150,																	// Default pixels to move each step
	animations : new Object(),													// Used to reference a given animation by id
	addAnimation : function(id, obj) {
		obj.id = id;
		this.animations[id] = obj;
		return obj;
	},
	startById : function(id) {
		if (this.animations[id]) {
			this.animations[id].start();
		}
	},
	stopById : function(id) {
		if (this.animations[id]) {
			this.animations[id].stop();
		}
	},
	runScene : function(scene, cb) {											// Runs an array of Animations and executes a callback when finished.
		var completed = new Array();
		if (scene.length) {
			for (var n = 0; n < scene.length; n++) {
				scene[n].sceneIndex = n;
				completed[n] = false;
				scene[n].complete = function() {
					completed[this.sceneIndex] = true;
					this.sceneIndex = 0;
					allDone = true;
					for (var j = 0; j < completed.length; j++) {
						if (!completed[j]) {
							allDone = false;
						}
					}
					if (allDone) {
						cb();
					}
				}
				scene[n].start();
			}
		} else {
			cb();
		}
	}
}

moveByAnimation = function(element) {
	this.element = element;
	this.interval = AnimationService.INTERVAL;
	this.step = AnimationService.STEP;
	this.running = false;
	this.intervalId = null;
	this.startTime = null;
	this.sceneIndex = 0;
	this.id = null;

	this.byX = 0;
	this.byY = 0;
	
	this.startX = getX(element);
	this.startY = getY(element);
	
	this.start = function() {
		if (this.intervalId == null) {
			this.beforeStart();
			this.running = true;
			
			this.startX = getX(this.element);
			this.startY = getY(this.element);

			var xDist = this.step * ((this.byX > 0) ? 1 : -1);
			var yDist = this.step * ((this.byY > 0) ? 1 : -1);
			
			var self = this;
			this.intervalId = setInterval(function() {

					var difX = (self.startX + self.byX) - getX(self.element);
					var difY = (self.startY + self.byY) - getY(self.element);
					
					// debug("this.byY: " + self.byY + " difY: " + difY + " yDist: " + yDist + " getY: " + getY(self.element));
					if (difX != 0 && self.byX != 0) {
						if ((difX < 0 && difX <= xDist) || (difX > 0 && xDist <= difX)) {
							moveByX(self.element, xDist);
						} else {
							moveByX(self.element, difX);
						}
					}
					if (difY != 0 && self.byY != 0) {
						if ((difY < 0 && difY <= yDist) || (difY > 0 && yDist <= difY)) {
							moveByY(self.element, yDist);
						} else {
							moveByY(self.element, difY);
						}
					}
					
					if (difX == 0 && difY == 0) {
						self.stop();
						self.complete();
					}
				},
				this.interval
			);
		
		} else {
			throw new Error("moveByAnimation already started for " + this.element.id);
		}
	}
	this.stop = function() {
		if (this.intervalId != null) {
			clearInterval(this.intervalId);
			this.intervalId = null;
		}
		this.running = false;
	}
	this.complete = function() {}
	this.beforeStart = function() {
		this.startTime = new Date().getTime();
	}
}

resizeByAnimation = function(element) {
	this.element = element;
	this.interval = AnimationService.INTERVAL;
	this.step = AnimationService.STEP;
	this.running = false;
	this.intervalId = null;
	this.startTime = null;
	this.sceneIndex = 0;
	this.id = null;

	this.byX = 0;
	this.byY = 0;
	
	this.startSize = getSize(this.element);
	
	this.start = function() {
		// debug("start: " + this.element.id);
		if (this.intervalId == null) {
			this.beforeStart();
			this.running = true;
			
			this.startSize = getSize(this.element);

			var xDist = this.step * ((this.byX > 0) ? 1 : -1);
			var yDist = this.step * ((this.byY > 0) ? 1 : -1);
			
			var self = this;
			this.intervalId = setInterval(function() {
					var size = getSize(self.element)
					var difX = (self.startSize.width + self.byX) - size.width;
					var difY = (self.startSize.height + self.byY) - size.height;
					
					
					// debug("difY: " + difY + " yDist: " + yDist + " size.height: " + size.height);
					
					if (difX != 0 && self.byX != 0) {
						if ((difX < 0 && difX <= xDist) || (difX > 0 && xDist <= difX)) {
							resizeToX(self.element, xDist + size.width);
						} else {
							resizeToX(self.element, difX + size.width);
						}
					}
					if (difY != 0 && self.byY != 0) {
						if ((difY < 0 && difY <= yDist) || (difY > 0 && yDist <= difY)) {
							resizeToY(self.element, yDist + size.height);
						} else {
							resizeToY(self.element, difY + size.height);
						}
					}
					
					if (difX == 0 && difY == 0) {
						// debug("Complete: " + self.element.id);
						self.stop();
						self.complete();
					}
				},
				this.interval
			);
		
		} else {
			throw new Error("resizeByAnimation already started for " + this.element.id);
		}
	}
	this.stop = function() {
		if (this.intervalId != null) {
			clearInterval(this.intervalId);
			this.intervalId = null;
		}
		this.running = false;
	}
	this.complete = function() {}
	this.beforeStart = function() {
		this.startTime = new Date().getTime();
	}
}

fadeAnimation = function(element) {
	this.element = element;
	this.interval = AnimationService.INTERVAL;
	this.step = AnimationService.STEP;
	this.running = false;
	this.intervalId = null;
	this.startTime = null;
	this.sceneIndex = 0;
	this.id = null;

	this.toOpacity = 0;
	
	this.startOpacity = getOpacity(this.element);
	
	this.start = function() {
		//debug("start: " + this.element.id);
		if (this.intervalId == null) {
			this.beforeStart();
			this.running = true;
			
			if (this.toOpacity < 0) {
				this.toOpacity = 0;
			}
			
			this.startOpacity = getOpacity(this.element);
			
			var dist = this.toOpacity > this.startOpacity ? 1 : -1;
			
			//debug("Start: " + this.startOpacity + " To: " + this.toOpacity + " dist: " + dist);
			var self = this;
			this.intervalId = setInterval(function() {
					var currentOpacity = getOpacity(self.element)
					var dif = currentOpacity + self.step * dist;
					
					// debug("Current: " + currentOpacity + " dif: " + dif);
					if ((dist > 0 && dif <= self.toOpacity) || (dist < 0 && dif >= self.toOpacity)) {
						setOpacity(self.element, dif);
					} else {
						setOpacity(self.element, self.toOpacity);
					}
					
					if (currentOpacity == self.toOpacity) {
						//debug("Complete: " + self.element.id);
						self.stop();
						self.complete();
					}
				},
				this.interval
			);
		
		} else {
			throw new Error("fadeAnimation already started for " + this.element.id);
		}
	}
	this.stop = function() {
		if (this.intervalId != null) {
			clearInterval(this.intervalId);
			this.intervalId = null;
		}
		this.running = false;
	}
	this.complete = function() {}
	this.beforeStart = function() {
		this.startTime = new Date().getTime();
	}
}
