// define various motion functions here
// Motion functions have x/y scale 0-1
function sigmoid(x) {
	return 1 / ( 1 + Math.exp(6-x * 12) );
}
function dampedSHM(x) {
	return 1 - Math.exp(-4*x)*Math.cos(10*x);
}
function sine(x) {
	return Math.sin(Math.PI*x);
}
function motionExp(x) {
	return 1 - Math.exp(-6*x);
}
function linear(x) { return x; }

var defaultLength = 20;

function Action( start, end, frames ) {
	this.motionFunc = sigmoid;
	
	this.start = start;
	this.end = end;
	this.length = frames;
	this.moveList = Array();
	this.suffix = "";
	
	this.init = function () {
		var displace = this.end-this.start;
		
		for (var i = 0; i < this.length; i++) {
			this.moveList[i] = displace * this.motionFunc(i / this.length) + this.start;
		}
	}
	
	this.get = function (frame) { 
		if (frame < 0)
			return this.start + this.suffix;
		if (frame >= this.length)
			return this.end + this.suffix;
		else
			return Math.round(this.moveList[frame]) + this.suffix;
	}
	this.setSuffix = function ( suf ) { this.suffix = suf; }
	this.init();
	
	this.toString = function () {
		return this.start + " to " + this.end + " in " + this.length + " steps: " + this.moveList[1];
	}
}
function ActionColor( start, end, frames) {
	this.start = parseColor(start);
	this.end = parseColor(end);
	this.length = frames;
	this.actions = Array();
	
	this.init = function () {
		for (var i = 0; i < 3; i++)
			this.actions[i] = new Action(this.start[i], this.end[i], this.length);
	}
	
	this.get = function (frame) {
		if (frame < 0)
			return printColor(this.start);
		else if (frame >= this.length)
			return printColor(this.end);
		else {
			return "rgb("+this.actions[0].get(frame)+","+this.actions[1].get(frame)+","+this.actions[2].get(frame)+")";
		}
	}
	
	this.init();
}
function Animation( obj ) {
	if (typeof(obj) == "object") 
		this.obj = obj;
	else
		this.obj = document.getElementById(obj);
	
	this.actions = Array();
	this.length = 0;
	this.timerID = -1;
	
	this.getAttribute = function ( attribute ) { 
		if (typeof(this.obj.style[attribute]) != "undefined")
			if (attribute != "color" && attribute != "backgroundColor")
				return parseInt(this.obj.style[attribute]); 
			else 
				return this.obj.style[attribute];
		else throw new Exception("Invalid initial attribute; use setAttribute to set initial! "+ attribute);
	}
	
	this.setAttribute = function ( attribute , value ) {
		if (typeof(this.obj.style.filter)!="undefined" && attribute == "opacity") {
			this.obj.style.filter = "alpha(opacity="+value*100+")";
		} else {
			this.obj.style[attribute] = value;
		}
	}
	this.setMovement = function ( attribute, endKey, length ) {
		if (typeof(length) == "undefined") 
			length = defaultLength;
		if (this.length < length)
			this.length = length;
		if (attribute == "color" || attribute == "backgroundColor") {
			this.actions[attribute] = new ActionColor(this.getAttribute(attribute), endKey, length);
		} else {
			var endval = parseInt(endKey);
			var suffix = "";
			if (typeof(endKey) == "string") 
				suffix = endKey.replace(endval, "");
			
			this.actions[attribute] = new Action(this.getAttribute(attribute), endval, length);
			this.actions[attribute].setSuffix(suffix);
		}
	}
	this.setFrame = function (frame) {
		for (var i in this.actions) {
			this.setAttribute(i, this.actions[i].get(frame));
		}
	}
	this.setEndFunc = function (func) { this.endFunc = func; }
	this.start = function () {
		window.clearTimeout(this.timerID);
		var thisObj = this;
		
		var func = function(frame) {
			thisObj.setFrame(frame);
			if (frame < thisObj.length)
				thisObj.timerID = window.setTimeout(function () { func(frame+1) }, 0);
			else 
				if (typeof(thisObj.endFunc) == "function")
					thisObj.endFunc();
		}
		func(0);
	}
	
}

parseColor = function (color) {
	var colorArr = Array();
	if (color.substr(0,1) == "#")
		color = color.substr(1);
	
	if (color.length == 6) {
		colorArr[0] = parseInt(color.substr(0,2), 16);
		colorArr[1] = parseInt(color.substr(2,2), 16);
		colorArr[2] = parseInt(color.substr(4,2), 16);
	} else if ( color.length == 3 ) {
		colorArr[0] = parseInt(color.substr(0,1)+color.substr(0,1), 16);
		colorArr[0] = parseInt(color.substr(1,1)+color.substr(1,1), 16);
		colorArr[0] = parseInt(color.substr(2,1)+color.substr(2,1), 16);
	} else if ( color.substr(0,3) == "rgb") {
		color = color.substr(4, color.length-5);
		colorArr = color.split(",");
		for (i in colorArr)
			colorArr[i] = parseInt(colorArr[i]);
	} else {
		throw new Exception("Invalid color");
	}
	return colorArr;
}
printColor = function (color) {
	return "rgb("+color[0]+","+color[1]+","+color[2]+")";
}

function Exception(msg) {
	this.message = msg;
	this.toString = function () {
		return this.message;
	}
}
