/**
 * 
 */
function JSAnimation(length, interval, callback) {
	this.length   = length   || 1;
	this.interval = interval || 1000;
	this.callback = callback || function () {};
	this.delta    = 1;
	this.isLoop   = false;
	this.moveStartCallback = function () {};
	this.moveStopCallback  = function () {};
	this.moveBeginCallback = function () {};
	this.moveEndCallback   = function () {};

	this.isGoAhead = true;
	this.retryTime = 200;

	this.end   = 0;
	this.index = 0;
	this.tid;
	this.status;
	if (this.length > 1) this.initialize();
}

JSAnimation.prototype.setProperties = function (props) {
	for (var key in props) {
		if (typeof this[key] != "undefined") this[key] = props[key];
		else throw new Error("Invalid Property [" + key + "]");
	}
	if (this.length > 1) this.initialize();
	return this;
};
JSAnimation.prototype.setConfig = function (confs) {
	for (var key in confs) {
		if (typeof this[key] != "undefined") this[key] = confs[key];
	}
	if (this.length > 1) this.initialize();
};

JSAnimation.prototype.initialize = function () {
	this.end    = this.length - 1;
	this.tid    = null;
	this.setStatus(false);
};

JSAnimation.prototype.setLength = function (length) {
	this.length   = length   || 1;
	if (this.length > 1) this.initialize();
};

JSAnimation.prototype.setMoveStartCallback = function (callBack) {
	this.moveStartCallback = callBack;
	return this;
};

JSAnimation.prototype.setMoveStopCallback = function (callBack) {
	this.moveStopCallback = callBack;
	return this;
};

JSAnimation.prototype.setMoveEndCallback = function (callBack) {
	this.moveEndCallback = callBack;
	return this;
};

JSAnimation.prototype.setStatus = function (status) {
	var lastStatus = this.status;
	this.status = status;
	if (lastStatus && ! status) {
		if (this.moveStopCallback) this.moveStopCallback();
	}
	if (! lastStatus && status) {
		if (this.moveStartCallback) this.moveStartCallback();
	}
	return this;
};

JSAnimation.prototype.setValue = function (v) {
	this.index = v;
//	this.callback(this.index);
};

JSAnimation.prototype.setInvertValue = function (v) {
	this.index = (this.length - 1) - v;
};

JSAnimation.prototype.getValue = function (v) {
	return this.index;
};

JSAnimation.prototype.getInvertValue = function (v) {
	return (this.length - 1) - this.index;
};

JSAnimation.prototype.isFirst = function () {
	return this.index == 0;
};

JSAnimation.prototype.isLast = function () {
	return this.index == this.end;
};

JSAnimation.prototype.isMove = function () {
	return this.status;
};

JSAnimation.prototype.next = function () {
	this.step(1);
};

JSAnimation.prototype.prev = function () {
	this.step(-1);
};

JSAnimation.prototype.step = function (n) {
	this.index += n;
	if (this.index < 0 || this.index > this.end) {
		this.index -= n;
		return;
	}
	this.callback(this.index);
};

JSAnimation.prototype.move = function () {
	if (this.tid) clearTimeout(this.tid);
	if (this.delta == 0) return;
//console.log("JSAnimation#move:" + this.isGoAhead);
	if (this.index > this.end || this.index < 0) {
		if (this.isLoop) this.index = this.delta > 0 ? 0 : this.end;
		else this.setStatus(false);
	}
	if (! this.status) {
		this.tid = null;
//		this.index -= this.delta;
		return;
	}
	this.callback(this.index);
	if (this.index == 0        && this.moveBeginCallback) this.moveBeginCallback();
	if (this.index == this.end && this.moveEndCallback)   this.moveEndCallback();
	if (this.isGoAhead) {
		this.setNextStep(this.interval);
	} else {
		this.setRetryStep(this.retryTime);
	}
};

JSAnimation.prototype.retry = function () {
	if (this.tid) clearTimeout(this.tid);
	if (this.delta == 0) return;
//console.log("JSAnimation#retry:" + this.isGoAhead);
	if (this.isGoAhead) {
		this.setNextStep(this.interval);
	} else {
		this.setRetryStep(this.retryTime);
	}
};


JSAnimation.prototype.setRetryStep = function (interval) {
//console.log("JSAnimation#setRetryStep:" + this.isGoAhead);
	var that = this;
	this.tid = setTimeout(function () {that.retry()}, interval);
};

JSAnimation.prototype.setNextStep = function (interval) {
//console.log("JSAnimation#setNextStep:" + this.isGoAhead);
	var that = this;
	this.tid = setTimeout(function () {that.move()}, interval);
	this.index += this.delta;
};

JSAnimation.prototype.forwards = function () {
	if (this.length <= 1) return;
	if (this.delta < 0) this.reverse();
	this.setStatus(true);
	this.move();
};

JSAnimation.prototype.backwards = function () {
	if (this.length <= 1) return;
	if (this.delta > 0) this.reverse();
	this.setStatus(true);
	this.move();
};

JSAnimation.prototype.stop = function () {
	this.setStatus(false);
};

JSAnimation.prototype.first = function () {
	this.index = 0;
	this.callback(this.index);
};

JSAnimation.prototype.last = function () {
	this.index = this.end;
	this.callback(this.index);
};

JSAnimation.prototype.loop = function () {
	this.isLoop = ! this.isLoop;
};

JSAnimation.prototype.reverse = function () {
	this.delta = 0 - this.delta;
};

JSAnimation.prototype.addOnloadListener = function (value) {
	var that = this;
	var listener = function () {
		that.create(value);
		Event.stopObserving(window, 'load', listener, false);
	};
	Event.observe(window, 'load', listener, false);
	return this;
};

