/**
 * @description Класс анимации, работающий с SquirrelFish
 */
Tween = new Class({
			Implements : [Events, Chain, Options],
			options : {
				/**
				 * @description Событие начала анимации
				 * @type Function
				 */
				onStart : $empty,
				/**
				 * @description Событие окончания анимации
				 * @type Function
				 */
				onComplete : $empty,
				/**
				 * @description Кадров в секунду
				 * @type Number
				 */
				fps : 50,
				/**
				 * @description Длительность анимации
				 * @type Number
				 */
				duration : 500
			},
			/**
			 * @description Конструктор класса.
			 * @param {Element[]}
			 *            elms Массив элементов, к которым будет применен эффект
			 *            анимации
			 * @param {Object}
			 *            options Объект с опциями
			 * @return {Object}
			 */
			initialize : function(elms, options) {
				// добавляем элементы
				if ($type.array(elms)) {
					this.elements = elms;
				}
				if ($type.string(elms)) {
					this.elements = $$(elms);
				}
				$each(this.elements, function(elm) {
							if (elm.getStyle('position') == 'static') {
								// ставим абсолютное позиционирование, если его
								// еще нет
								elm.setStyle('position', 'absolute');
							}
						});
				// setting up options
				this.setOptions(options);
				// this is for chaining
				return this;
			},
			/**
			 * @description For example: var tween = new Tween($$('.elms'));
			 *              tween.start({ '0': { property: 'top', anim: [0, 150] }
			 *              }); This example means: we should animate
			 *              CSS-property top from 0 pixels to 150 pixel for the
			 *              first element of $$('.elms');
			 * @param {Object}
			 *            obj Object which indicates what elemnt should be
			 *            animated and how
			 * @return {Object}
			 */
			start : function(obj) {
				this.animation = $H(obj);
				this.startTimer();
				this.fireEvent('start');
				return this;
			},
			startTimer : function() {
				if (this.timer) {
					return false;
				}
				this.time = $time();
				this.timer = this.step.periodical(Math.round(1000
								/ this.options.fps), this);
				return true;
			},
			stopTimer : function() {
				if (!this.timer) {
					return false;
				}
				this.time = $time() - this.time;
				this.timer = $clear(this.timer);
				return true;
			},
			step : function() {
				var time = $time();
				if (time < this.time + this.options.duration) {
					var delta = this.transition((time - this.time)
							/ this.options.duration);
					this.animation.each(function(obj, elm) {
								this.set(elm, obj.property, this.compute(obj,
												delta));
							}, this);

				} else {
					this.animation.each(function(obj, elm) {
								this.set(elm, obj.property, this
												.compute(obj, 1));
							}, this);
					this.complete();
				}
			},
			complete : function() {
				if (this.stopTimer()) {
					this.animation = null;
					this.fireEvent('complete');
					this.callChain.delay(100, this);
				}
				return this;
			},
			transition : function(p) {
				return 1 - Math.sin((1 - p) * Math.PI / 2);
			},
			compute : function(obj, delta) {
				return (obj.anim[1] - obj.anim[0]) * delta + obj.anim[0];
			},
			set : function(elm, property, n) {
				this.elements[elm].setStyle(property, n);
			}
		});