/**
 * new Animation(frames, [width, height])
 * 
 * Defines an animation object. `frames` is an array of image URIs. `width`
 * and `height` are the size of the animation in pixels. `width` and `height`
 * are optional and can be autodetected after the animation is loaded.
 * 
 * Example:
 * var anim = new Animation(["frames/sage0.png","frames/sage1.png","frames/sage2.png"]);
 */
function Animation(frames, width, height) {
	this.frames = frames;
	this.element = document.createElement("div");
	this.element.style.position = "relative";
	this.loading_text = document.createTextNode("Loading...");
	this.element.appendChild(this.loading_text);
	if(typeof width == "undefined" || typeof height == "undefined") {
		this.autodetect_size = true;
	} else {
		this.autodetect_size = false;
		this._set_size(width, height);
	}
	this.low_z_index = "-1";
	this.high_z_index = "10";
}

/**
 * Animation.get_element()
 * 
 * Returns the DOM element of the animation.
 * 
 * Example:
 * var anim = new Animation(["frames/sage0.png","frames/sage1.png","frames/sage2.png"]);
 * document.getElementById("target_cell").appendChild(anim.get_element());
 */
Animation.prototype.get_element = function() {
	return this.element;
};

/**
 * Animation.load([callback])
 * 
 * Loads all the images from their URIs. `callback` is an optional parameter 
 * to define a function that is called when the images are finished loading.
 * 
 * Example:
 * var anim = new Animation(["frames/sage0.png","frames/sage1.png","frames/sage2.png"]);
 * anim.load(function() {
 * 	alert("Animation is ready!");
 * });
 */
Animation.prototype.load = function(callback) {
	if(typeof callback == "undefined") {
		callback = function() {};
	}
	this.images = new Array();
	var self = this;
	this.frame_load_counter = 0;
	this.load_callback = callback;
	for(var i = 0; i < this.frames.length; i += 1) {
		this.images[i] = new Image();
		this.images[i].onload = function() {
			self._frame_loaded();
		}
		this.images[i].src = this.frames[i];
		this.images[i].style.zIndex = this.low_z_index;
		this.images[i].style.display = "none";
		this.images[i].style.position = "absolute";
		this.images[i].style.top = "0";
		this.images[i].style.left = "0";
		this.element.appendChild(this.images[i]);
	}
}

/**
 * Animation.start([options])
 * 
 * Plays the animation. `options` is an optional parameter that provides
 * additional configuration of the animtaion. The available options are
 * "delay" and "iterations". "delay" is the number of milliseconds between
 * each frame (default 20). "iterations" is the number of times the
 * animation repeats (default 0). Set "iterations" to 0 for an endless
 * animation.
 * 
 * Example:
 * var anim = new Animation(["frames/sage0.png","frames/sage1.png","frames/sage2.png"]);
 * document.getElementById("target_cell").appendChild(anim.get_element());
 * anim.load(function() {
 * 	anim.start({delay: 50, iterations: 4});
 * });
 */
Animation.prototype.start = function(options) {
	var defaultOptions = {delay: 20, iterations: 0};
	if(typeof options != "undefined") {
		for(key in options) {
			defaultOptions[key] = options[key];
		}
	}
	this.current_frame = 0;
	this.images[0].style.zIndex = this.high_z_index;
	this.images[0].style.display = "block";
	for(var i = 1; i < this.images.length; i += 1) {
		this.images[i].style.display = "block";
	}
	this.stop_at = defaultOptions.iterations*this.images.length;
	this.delay = defaultOptions.delay;
	this.pause();
};

/**
 * Animation.pause()
 * 
 * Toggles whether or not the animation is paused.
 * 
 * Example:
 * var anim = new Animation(["frames/sage0.png","frames/sage1.png","frames/sage2.png"]);
 * document.getElementById("target_cell").appendChild(anim.get_element());
 * anim.load(function() {
 * 	anim.start();
 * });
 * window.setTimeout(function() {
 * 	anim.pause();
 * }, 1000);
 */
Animation.prototype.pause = function() {
	if(typeof this.interval == "undefined") {
		var self = this;
		this.interval = window.setInterval(function() {
			self._update();
		}, this.delay);
	} else {
		window.clearInterval(this.interval);
		delete this.interval;
	}
}

/**
 * Updates the top (visible) image.
 */
Animation.prototype._update = function() {
	if(this.stop_at != 0 && this.current_frame == this.stop_at) {
		window.clearInterval(this.interval);
	} else {
		this.images[this.current_frame%this.images.length].style.zIndex = this.low_z_index;
		this.current_frame += 1;
		if(this.stop_at == 0) {
			this.current_frame %= this.images.length;
		}
		this.images[this.current_frame%this.images.length].style.zIndex = this.high_z_index;
	}
}

/**
 * Callback for loading frames.
 */
Animation.prototype._frame_loaded = function() {
	this.frame_load_counter += 1;
	if(this.frame_load_counter == this.frames.length) {
		delete this.frames;
		if(this.autodetect_size) {
			var max_width = 0;
			var max_height = 0;
			for(var i = 0; i < this.images.length; i += 1) {
				if(this.images[i].width > max_width) {
					max_width = this.images[i].width;
				}
				if(this.images[i].height > max_height) {
					max_height = this.images[i].height;
				}
			}
			this._set_size(max_width, max_height);
		}
		delete this.autodetect_size;
		this.element.removeChild(this.loading_text);
		delete this.loading_text;
		this.load_callback();
	}
}

/**
 * Sets the size of the animation.
 */
Animation.prototype._set_size = function(width, height) {
	this.element.style.width = width+"px";
	this.element.style.height = height+"px";
}
