/**
 * Tween Class
 * @class benignware.transitions.Tween
 */
(function(){
	// import classes
	var Class = benignware.core.Class;
	var Event = Class.require("benignware.events.Event");
	var EventDispatcher = Class.require("benignware.events.EventDispatcher");
	// define super
	var __super;
	/**
	 * Constructs a new form-element.
	 * @constructor
	 */
	function Tween(duration, easeFunction, begin, finish) {
		__super.call(this);
		this.time = 0;
		this.easeFunction = easeFunction;
		this.begin = typeof(begin) == "number" ? begin : 0;
		this.finish = typeof(finish) == "number" ? finish : 1;
		this.duration = typeof(duration) == "number" ? duration : 1;
	}
	
	Class.registerClass("benignware.transitions.Tween", Tween);

	Tween = Class(EventDispatcher, Tween);
	__super = Class.getSuper(Tween);
	
	// constants
	Tween.INTERVAL_MS = 40;
	Tween.FORWARD = 1;
	Tween.REVERSE = -1;
	
	// events
	Tween.MOTION_CHANGE = "motionChange";
	Tween.MOTION_FINISH = "motionFinish";
	Tween.MOTION_START = "motionStart";
	Tween.MOTION_STOP = "motionStop";
	
	
	Tween.prototype.__isPlaying = false;
	Tween.prototype.__intervalId = null;
	
	Tween.prototype.easeFunction = null;
	Tween.prototype.duration = 0;
	Tween.prototype.begin = 0;
	Tween.prototype.finish = 0;
	
	Tween.prototype.time = 0;
	Tween.prototype.direction = Tween.FORWARD;
	
	Tween.prototype.__interval = Tween.INTERVAL_MS;
	
	function dispatchMotionEvent(type) {
		var motionEvent = new Event(type);
		this.dispatchEvent(motionEvent);
	}
	
	Tween.prototype.play = function() {
		if (!this.__isPlaying) {
			var target = this;
			this.__isPlaying = true;
			this.__intervalId = window.setInterval(function(event){
				// change
				var time = target.time;
				var t = time;
				var diff = (target.__interval / 1000) * target.direction;
				time+= diff;
				
				if (time > target.duration) {
					time = target.duration;
					
				}
				if (time < 0) {
					time = 0;
				}
				target.time = time;
				
				target.update();
				dispatchMotionEvent.call(target, Tween.MOTION_CHANGE);
				if (target.direction == Tween.FORWARD && target.time == target.duration || target.direction == Tween.REVERSE && target.time == 0) {
					dispatchMotionEvent.call(target, Tween.MOTION_FINISH);
					target.stop();
				}
			}, target.__interval);
		}
	}
	
	Tween.prototype.start = function() {
		if (this.__isPlaying) {
			this.stop();
		}
		this.time = this.direction == Tween.REVERSE ? this.duration : 0;
		this.play();
		dispatchMotionEvent.call(this, Tween.MOTION_START);
		dispatchMotionEvent.call(this, Tween.MOTION_CHANGE);
	}
	
	Tween.prototype.stop = function() {
		this.__isPlaying = false;
		if (this.__intervalId) {
			window.clearInterval(this.__intervalId);
		}
		dispatchMotionEvent.call(this, Tween.MOTION_STOP);
	}
	
	Tween.prototype.rewind = function() {
		//this.time = this.direction == Tween.REVERSE ? this.duration : 0;
		this.time = 0;
	}
	
	Tween.prototype.fforward = function() {
		this.time = this.duration;
	}
	
	Tween.prototype.forward = function() {
		this.direction = Tween.FORWARD;
		this.play();
	}
	
	Tween.prototype.reverse = function() {
		this.direction = Tween.REVERSE;
		this.play();
	}
	
	Tween.prototype.yoyo = function() {
		var b = this.begin;
		var f = this.finish;
		this.begin = f;
		this.finish = b;
		this.play();
	}
	
	Tween.prototype.update = function() {
	}
	
	Tween.prototype.getPosition = function() {
		var change = this.finish - this.begin;
		if (typeof(this.easeFunction) == "function") {
			return this.easeFunction(this.time, this.begin, change, this.duration);
		} else {
			return change * this.time / this.duration + this.begin;
		}
	}
	
	Tween.prototype.isPlaying = function() {
		return this.__isPlaying;
	}

	return Tween;
})();
/**
 * Robert Penner easing equations
 * http://www.robertpenner.com/easing/
 */
(function(){
	
	var Class = benignware.core.Class;
	
	function Regular() {
	}
	
	Class.registerClass("benignware.transitions.easing.Regular", Regular);
	
	Regular.easeIn = function(t, b, c, d) {
		return c * (t /= d) * t + b;
	}
	
	Regular.easeOut = function(t, b, c, d) {
		return -c * (t /= d) * (t - 2) + b;
	}
	
	Regular.easeInOut = function(t, b, c, d) {
		if ((t /= d / 2) < 1)
			return c / 2 * t * t + b;

		return -c / 2 * ((--t) * (t - 2) - 1) + b;
	}
	
	return Regular;
})();
/**
 * Robert Penner easing equations
 * http://www.robertpenner.com/easing/
 */
(function(){
	
	var Class = benignware.core.Class;
	
	function Back() {
	}
	
	Class.registerClass("benignware.transitions.easing.Back", Back);
	
	Back.easeIn = function(t, b, c, d, s) {
		if (typeof(s) != "number")
			s = 1.70158;
		
		return c * (t /= d) * t * ((s + 1) * t - s) + b;
	}
	
	Back.easeOut = function(t, b, c, d, s) {
		if (typeof(s) != "number")
			s = 1.70158;
		
		return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
	}
	
	Back.easeInOut = function(t, b, c, d, s) {
		if (typeof(s) != "number")
			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;
	}
	
	return Back;
})();
/**
 * Robert Penner actionscript easing equations
 * http://www.robertpenner.com/easing/
 */
(function(){
	
	var Class = benignware.core.Class;
	
	function Elastic() {
	}
	
	Class.registerClass("benignware.transitions.easing.Elastic", Elastic);
	
	Elastic.easeIn = function(t, b, c, d, a, p) {
		if (t == 0)
			return b;
		
		if ((t /= d) == 1)
			return b + c;
		
		if (typeof(p) != "number")
			p = d * 0.3;
		
		var s;
		if (typeof(a) != "number" || a < Math.abs(c)) {
			a = c;
			s = p / 4;
		} else {
			s = p / (2 * Math.PI) * Math.asin(c / a);
		}

		return -(a * Math.pow(2, 10 * (t -= 1)) *
				 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
	}
	
	Elastic.easeOut = function(t, b, c, d, a, p) {
		if (t == 0)
			return b;
			
		if ((t /= d) == 1)
			return b + c;
		
		if (typeof(p) != "number")
			p = d * 0.3;

		var s;
		if (typeof(a) != "number" || a < Math.abs(c))
		{
			a = c;
			s = p / 4;
		}
		else
		{
			s = p / (2 * Math.PI) * Math.asin(c / a);
		}

		return a * Math.pow(2, -10 * t) *
			   Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
	}
	
	Elastic.easeInOut = function(t, b, c, d, a, p) {
		if (t == 0)
			return b;
			
		if ((t /= d / 2) == 2)
			return b + c;
			
		if (typeof(p) != "number")
			p = d * (0.3 * 1.5);

		var s;
		if (typeof(a) != "number" || a < Math.abs(c))
		{
			a = c;
			s = p / 4;
		}
		else
		{
			s = p / (2 * Math.PI) * Math.asin(c / a);
		}

		if (t < 1)
		{
			return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) *
				   Math.sin((t * d - s) * (2 * Math.PI) /p)) + b;
		}
		
		return a * Math.pow(2, -10 * (t -= 1)) *
			   Math.sin((t * d - s) * (2 * Math.PI) / p ) * 0.5 + c + b;
	}
	
	return Elastic;
})();
/**
 * Robert Penner easing equations
 * http://www.robertpenner.com/easing/
 */
(function(){
	
	var Class = benignware.core.Class;
	
	function Strong() {
	}
	
	Class.registerClass("benignware.transitions.easing.Strong", Strong);
	
	Strong.easeIn = function(t, b, c, d) {
		return c * (t /= d) * t * t * t * t + b;
	}
	
	Strong.easeOut = function(t, b, c, d) {
		return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
	}
	
	Strong.easeInOut = 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;
	}
	
	return Strong;
})();
/**
 * Transition Class
 * @class benignware.transitions.Transition
 */
(function(){
	// import classes
	var Class = benignware.core.Class;
	var Event = Class.require("benignware.events.Event");
	var Delegate = Class.require("benignware.utils.Delegate");
	var EventDispatcher = Class.require("benignware.events.EventDispatcher");
	var Tween = Class.require("benignware.transitions.Tween");
	//
	var Regular = Class.require("benignware.transitions.easing.Regular");
	// define super
	var __super;
	/**
	 * Constructs a new form-element.
	 * @constructor
	 */
	function Transition(element, duration, scene, easeFunction) {
		__super.call(this);
		this.time = 0;
		this.scene = scene ? scene : Transition.IN; 
		this.easeFunction = easeFunction ? easeFunction : Regular.easeOut;
		this.element = element;
		this.duration = typeof(duration) != "undefined" ? duration : 1;
		var tween = new Tween();
		tween.begin = 0;
		tween.finish = 1;
		tween.duration = this.duration;
		// events
		tween.addEventListener(Tween.MOTION_START, Delegate.create(this, function(event) {
			this.dispatchEvent(new Event(Transition.TRANSITION_START, false, false));
			this.dispatchEvent(new Event(Transition.MOTION_START, false, false));
		}), false);
		tween.addEventListener(Tween.MOTION_STOP, Delegate.create(this, function(event) {
			this.dispatchEvent(new Event(Transition.MOTION_STOP, false, false));
		}), false);
		tween.addEventListener(Tween.MOTION_CHANGE, Delegate.create(this, function(event) {
			if (this.getElement()) {
				this.update();
			}
			this.dispatchEvent(new Event(Transition.MOTION_CHANGE, false, false));
		}), false);
		tween.addEventListener(Tween.MOTION_FINISH, Delegate.create(this, function(event) {
			this.dispatchEvent(new Event(Transition.MOTION_FINISH, false, false));
			this.dispatchEvent(new Event(Transition.TRANSITION_END, false, false));
		}), false);
		
		this.__tween = tween;
	}
	
	Class.registerClass("benignware.transitions.Transition", Transition);

	Transition = Class(EventDispatcher, Transition);
	__super = Class.getSuper(Transition);
	
	// constants
	Transition.IN = 1;
	Transition.OUT = -1;
	
	Transition.FORWARD = 1;
	Transition.REVERSE = -1;
	
	// events
	Transition.MOTION_START = "motionStart";
	Transition.MOTION_CHANGE = "motionChange";
	Transition.MOTION_STOP = "motionStop";
	Transition.MOTION_FINISH = "motionFinish";
	
	Transition.TRANSITION_START = "transitionStart";
	Transition.TRANSITION_END = "transitionEnd";
	
	
	Transition.prototype.element = null;
	
	Transition.prototype.params = {};
	
	Transition.prototype.duration = 1;
	
	Transition.prototype.easeInFunction = null;
	Transition.prototype.easeOutFunction = null;
	
	Transition.prototype.scene = Transition.IN;
	Transition.prototype.direction = Transition.FORWARD;
	
	Transition.prototype.setElement = function(element) {
		this.element = element;
	}
	
	Transition.prototype.getElement = function() {
		return this.element;
	}
	
	Transition.prototype.start = function() {
		initTween.call(this);
		if (this.element) {
			this.updateTarget();
		}
		this.__tween.start();
	}
	
	function initTween() {
		this.__tween.duration = this.duration;
		this.__tween.direction = this.direction;
		var easeFunction = null;
		if (this.scene == Transition.IN) {
			easeFunction = this.easeInFunction ? this.easeInFunction : this.easeFunction;
		} else {
			easeFunction = this.easeOutFunction ? this.easeOutFunction : this.easeFunction;
		}
		this.__tween.easeFunction = easeFunction;
	}
	
	Transition.prototype.stop = function() {
		initTween.call(this);
		this.__tween.stop();
	}
	
	
	/*
	Transition.prototype.play = function() {
		initTween.call(this);
		this.__tween.play();
	}
	
	
	Transition.prototype.forward = function() {
		initTween.call(this);
		this.__tween.forward();
	}
	
	Transition.prototype.reverse = function() {
		initTween.call(this);
		this.__tween.reverse();
	}
	
	Transition.prototype.yoyo = function() {
		initTween.call(this);
		this.__tween.yoyo();
	}
	*/
	
	Transition.prototype.updateTarget = function() {
		this.update();
	}
	
	Transition.prototype.isPlaying = function() {
		return this.__tween.isPlaying();
	}
	
	Transition.prototype.update = function() {
		var p = this.__tween.getPosition();
//		console.log("p");
	}

	return Transition;
})();
/**
 * Transition Class
 * @class benignware.Fades.Fade
 */
(function(){
	// import classes
	var Class = benignware.core.Class;
	var Event = Class.require("benignware.events.Event");
	var EventDispatcher = Class.require("benignware.events.EventDispatcher");
	var Transition = Class.require("benignware.transitions.Transition");
	// define super
	var __super;
	/**
	 * Constructs a new form-element.
	 * @constructor
	 */
	function Fade(element, duration, scene, easeFunction) {
		this.duration = 1;
		__super.apply(this, arguments);
	}
	
	Class.registerClass("benignware.transitions.Fade", Fade);

	Fade = Class(Transition, Fade);
	__super = Class.getSuper(Fade);

	Fade.prototype.update = function() {
		this.__tween.duration = this.duration;
		var p = this.__tween.getPosition();
		var value;
		switch(this.scene) {
			case Transition.OUT:
				value = 1 - p;
				break;
			default:
				value = p;
		}
		this.element.style.opacity = value;
		this.element.style.filter = "alpha(opacity=" + (value * 100) + ")";
	}

	return Fade;
})();
/**
 * Transition Class
 * @class benignware.Flys.Fly
 */
(function(){
	// import classes
	var Class = benignware.core.Class;
	var Delegate = Class.require("benignware.utils.Delegate");
	var Element = Class.require("benignware.core.Element");
	var Event = Class.require("benignware.events.Event");
	var EventDispatcher = Class.require("benignware.events.EventDispatcher");
	//
	var Transition = Class.require("benignware.transitions.Transition");
	var Fade = Class.require("benignware.transitions.Fade");
	var Back = Class.require("benignware.transitions.easing.Back");
	var Regular = Class.require("benignware.transitions.easing.Regular");
	// define super
	var __super;
	/**
	 * Constructs a new form-element.
	 * @constructor
	 */
	function Fly(element) {
		__super.apply(this, arguments);
		this.easeFunction = Regular.easeInOut;
		this.params['fade'] = true;
	}
	
	Class.registerClass("benignware.transitions.Fly", Fly);

	Fly = Class(Fade, Fly);
	__super = Class.getSuper(Fly);
	
	Fly.prototype.easeFunction = null;
	
	Fly.prototype.start = function() {
		__super.start.call(this);	}
	
	/*
	Fly.prototype.stop = function() {
		if (this.isPlaying()) {
			__super.stop.call(this);
		}
	}
	*/
	
	
	
	Fly.prototype.updateTarget = function() {
		
		var element = this.getElement();
		if (element) {
			if (element.offsetParent) {
				element.style.position = "absolute";
				var w = element.offsetParent.offsetWidth;
				var h = element.offsetParent.offsetHeight;
				
				this.__destRelCenterX = (element.offsetLeft + element.offsetWidth / 2) / w;
				this.__destRelCenterY = (element.offsetTop + element.offsetHeight / 2) / h;
				
				this.update();
			}
		}
	}

	Fly.prototype.update = function() {
		var element = this.getElement();

		if (!element) {
			return;
		}

		element.style.position = "absolute";
		
		this.__tween.duration = this.duration;
		var p = this.__tween.getPosition();
		
		var w, h, destX, destY;
		if (element.offsetParent) {
			w = element.offsetParent.offsetWidth;
			h = element.offsetParent.offsetHeight;
			destX = (this.__destRelCenterX * w) - element.offsetWidth / 2;
			destY = (this.__destRelCenterY * h) - element.offsetHeight / 2;
			
		} else {
			return;
		}

		var x;
		
		switch (this.scene) {
			case Transition.OUT:
				x = destX + (w - destX) * p;
				break;
			default: 
				var x1 = -element.offsetWidth;
				x = x1 + (destX - x1) * p;
				break;
		}
		
		element.style.left = x + "px";
	}

	return Fly;
})();

