﻿/*
	Copyright (C) 2006 Ekina Ltd. All Rights Reserved.
	
	Tween class
	
	Usage:
	
	Tween constructor:
	
		Tween(object, property, func, begin, finish, duration, unit)
		
		object :	The object to tween, in the case of an HTML element where the tween will take place on
					the "left" property, the object would be element.style
		
		property :	A string representation of the property to tween
		
		begin :		The initial value of the property
		
		finish :	The final value of the property
		
		duration :	The amount of time in seconds the tween should take
		
		func :		[Optional] The tween type class (see below), this defaults to Tween.None
		
		unit :		[Optional] A string containing a postfix for the property value, for example, changing the "left"
					property of the style object of an HTML element, this will need to be "px". If this value
					is ignored, then it defaults to ""	
	
	
	Tween types
		Tween.None :		Performs a smooth tween over the specified duration
		
		Tween.Bounce :		Performs a bounce tween
		Tween.Elastic :		Performs an elastic tween
		Tween.Regular :		Performs a regular tween
		Tween.Strong :		Performs the same tween as the Regular tween but accelerates and decelerates quicker
		
		Each of the above tween types (excluding Tween.None) has the following tween directions
		
		In :				Uses the chosen tween effect at the start of the tween
		Out :				Uses the chosen tween effect at the end of the tween
		InOut :				Used the chosen tween effect at both the start and end of the tween
		
		With the exception of Tween.None, tween types must have the tween direction set, for example: 
			Tween.Elastic.Out
	
	Example:
	
	<html>
		<head>
			<title>Javascript tween example</title>
			<script src="_script/Effects.js" type="text/javascript"></script>
			<script type="text/javascript">
				function startTween(){
					new Tween(document.getElementById("op").style, "left", Tween.Bounce.Out, 10, 100, 2, "px");
				}
			</script>
			<style type="text/css">
				#op{position: absolute; left: 10px; top: 100px;}
			</style>
		</head>
		<body onload="startTween();">
			<div id="op">Moving Text!</div>
		</body>
	</html>
	
*/



	function Tween(object, property, begin, finish, duration, func, unit, scalar, args){
		this.scalar = scalar ? scalar : 1;
		this.element = object;
		this.property = property;
		this.begin = begin;
		this.finish = finish;
		this.ticks = duration * Tween.FPS;
		this.func = func ? func : Tween.None;	
		this.change = this.finish - this.begin;
		this.unit = unit ? unit : "";
		this.currentTick = 0;
		this.timer = null;
		this.tweenId = Tween.pushTween(this);
		this.args = args;
		
		//EVENTS
		this.onTweenFinished = null;
		this.onTweenStep = null;
		
		this.start();
	};

	Tween.FPS = 25;
	Tween.all = new Array();

	Tween.prototype.start = function(){
		this.setupTimer();
	};

	Tween.pushTween = function(tween){
		Tween.all.push(tween);
		return Tween.all.length-1;
	};

	Tween.prototype.stop = function(){
		if(this.timer){
			window.clearInterval(this.timer);
			this.timer = null;
		}
	};

	Tween.prototype.setupTimer = function(){
		this.timer = window.setInterval("Tween.step(" + this.tweenId + ")", 1000 / Tween.FPS);
	};

	Tween.step = function(id){
		var tween = Tween.all[id];
		tween.step();
	};

	Tween.prototype.step = function(){
		this.setTime(this.currentTick+1);
	};

	Tween.prototype.setTime = function(t){
		if(t > this.ticks){
			this.stop();
			this.fireEvent(this.onTweenFinished, this.args);
		}
		else{
			this.currentTick = t;
			this.update();
		}
	};

	Tween.prototype.update = function(){
		this.setPosition(this.getPosition());
		this.fireEvent(this.onTweenStep, this.args);
	};

	Tween.prototype.setPosition = function(pos){
		var value = pos * this.scalar;
		value = this.unit == "" ? parseFloat(value) : value + this.unit;
		this.element[this.property] = value;
	};

	Tween.prototype.getPosition = function(){
		return this.func(this.currentTick, this.begin, this.change, this.ticks);
	};

	Tween.prototype.fireEvent = function(evt, args){
		if(evt)
			evt(args);
	};

	Tween.None = function(t, b, c, d){
		return c * t / d + b;
	};

	Tween.Bounce = new Object();
	Tween.Bounce.In = function(t, b, c, d) {
		var s = 1.70158;
		return c * (t /= d) * t * ((s + 1) * t - s) + b;
	};
	Tween.Bounce.Out = function(t, b, c, d) {
		var s = 1.70158;
		return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
	};
	Tween.Bounce.InOut = function(t, b, c, d) {
		var s = 1.70158;
		if ((t /= d / 2) < 1) 
			return c / 2 * (t * t * (((s *= 1.525) + 1) * t - s)) + b;
		return c / 2 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2) + b;
	};

	Tween.Elastic = new Object();
	Tween.Elastic.In = function(t, b, c, d) {
		if (t == 0) 
			return b;  
		if ((t /= d) == 1) 
			return b + c;  
		if (!p) p = d *.3;
		return -(c * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - (p / 4)) * (2 * Math.PI) / p)) + b;
	};
	Tween.Elastic.Out = function(t, b, c, d) {
		if (t == 0) 
			return b;  
		if ((t /= d) == 1) 
			return b + c;  
		var p = d * .3;
		return (c * Math.pow(2, -10 * t) * Math.sin((t * d - (p / 4)) * (2 * Math.PI) / p) + c + b);
	};
	Tween.Elastic.InOut = function(t, b, c, d) {
		if (t == 0) 
			return b;  
		if ((t /= d / 2) == 2) 
			return b + c;
		var p = d * (.3 * 1.5);
		if (t < 1)
			return -.5 * (c * Math.pow(2, 10 * (t-=1)) * Math.sin((t * d - (p / 4)) * (2 * Math.PI) / p)) + b;
		return c * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - (p / 4)) * (2 * Math.PI) / p) * .5 + c + b;
	};

	Tween.Regular = new Object();
	Tween.Regular.In = function(t, b, c, d) {
		return c * (t /= d) * t + b;
	};
	Tween.Regular.Out = function(t, b, c, d) {
		return -c * (t /= d) * (t - 2) + b;
	};
	Tween.Regular.InOut = function(t, b, c, d) {
		if ((t /= d / 2) < 1)
			return c / 2 * t * t + b;
		return -c / 2 * ((--t) * (t - 2) - 1) + b;
	};

	Tween.Strong = new Object();
	Tween.Strong.In = function(t, b, c, d) {
		return c * (t /= d) * t * t * t * t + b;
	};
	Tween.Strong.Out = function (t, b, c, d) {
		return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
	};
	Tween.Strong.InOut = function (t, b, c, d) {
		if((t /= d / 2) < 1)
			return c / 2 * t * t * t * t * t + b;
		return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
	};



	/*
		Static helper methods
	*/

	/*
		Tween.alpha (obj, to, duration)
		
		obj :		The object to fade
		to :		The value to fade in/out to (the final opacity in other words :P)
		duration :	The length of time in seconds for the effect to take place
	*/
	Tween.alpha = function(obj, to, duration){
		if(obj.tween)
			obj.tween.stop();

		var currentOpacity = document.all ? obj.filters["DXImageTransform.Microsoft.Alpha"].opacity : obj.style.MozOpacity;
		var t;
		if(document.all)
			t = new Tween(obj.filters["DXImageTransform.Microsoft.Alpha"], "opacity", currentOpacity, to, duration);
		else
			t = new Tween(obj.style, "MozOpacity", currentOpacity * 100, to, duration, null, "", .01);
		
		obj.tween = t;
		
		return t;
	};
	
