/*
Format
 Animation.start({
	target : this.style,
	parameter : "object",
	startValue : 0.5,
	finishValue : 0.1,
	onInit : preFunction,
	onStop : postFunction,
	onIterate : iterateHandler,
	approximation : 0.1,
	speed : 0.5
	})
*/

function tt(sString)
	{
		document.body.innerHTML+='<PRE>'+sString+'<PRE>';
	}

Animation = (function()
		{
			var
				pAnimationData = {
					playing : [],
					active : [],
					index : 0
				}

			return {
				objectIsAnimated : function(oObject)
					{
						for(var i=0, L=pAnimationData.playing.length; i<L; i++)
							{
								if (pAnimationData.playing[i].getTarget() === oObject)
									return pAnimationData.playing[i];
							}
						return null;
					},

				isPlaying : function(oIndex)
					{
						if (typeof (oIndex) === 'object')
							{
								for(var i=0, L=pAnimationData.playing.length; i<L; i++)
									if (pAnimationData.playing[i] === oObject)
										return pAnimationData.playing[i];
							}
						else
							{
								for(var i=0, L=pAnimationData.playing.length; i<L; i++)
									if (pAnimationData.playing[i].getId() == oObject)
										return pAnimationData.playing[i];
							}
						return null;
					},

				start : function()
					{
						function AnimationInstance(oInitData)
							{
								this.autoStart = oInitData.autoStart === false ? false : true;
								this.isSync = oInitData.isSync === false ? false : true;
								var
									that = this,
									pOnIterate = typeof(oInitData.onIterate) == 'function' ? oInitData.onIterate : null,
									poIterator = typeof(oInitData.itrator) == 'function' ? oInitData.itrator : null,
									pOnStop = typeof(oInitData.onStop) == 'function' ? oInitData.onStop : null,
									pOnInit = typeof(oInitData.onInit) == 'function' ? oInitData.onInit : null,
									poTarget = typeof(oInitData.target) == 'object' ? oInitData.target : null,
									psTargetId = typeof(oInitData.target) == 'string' ? oInitData.target : null,
									pnEase = typeof(oInitData.easing) == 'number' ? oInitData.easing : 0.5,
									pnMotionTime =  typeof(oInitData.time) == 'number' ? oInitData.time * 1000 : 1000, //seconds
									psPostfix = oInitData.postfix ? oInitData.postfix : '',

									poProperty = oInitData.property,
									poStyleProperty = oInitData.styleProperty,
									poStartValue = typeof(oInitData.startValue) == 'number' ? oInitData.startValue : 0,
									poFinishValue = typeof(oInitData.finishValue) == 'number' ? oInitData.finishValue : 100,
									poData = oInitData.data,
									pnId = oInitData.id ? oInitData.id : pAnimationData.index++,

									pnTiming = 28,
									pnFrames = 0,
									pbFinished = false,
									pbPlaying = false,
									
									pnChainId = 0,
									pnDirection = 1,
									pnIteration = 0,
									poTimeout = 0,
									pnValue = 0,
									pnDelta = 0,
				
									poNext = null,
									pbStopAfterFinish = true,
									poPrevious = null;

									if (!(poTarget || psTargetId))
										{
											poProperty = null;
											poStyleProperty = null;
										}

								this.reset = function()
									{
										pnIteration = 0;
										pbFinished = false;
										pbPlaying = false;
										pnValue = poStartValue;
										pnDelta = poFinishValue - poStartValue;
										pnFrames = pnMotionTime / pnTiming;
										pnDirection = pnDelta <= 0 ? -1 : 1;
										if (pnDelta && (pnDelta * pnDirection) < 0)
											pnDelta *= -1;
										pApplyValue();
									}

								this.play = function()
									{
										
										if (!pbPlaying || pbFinished)
											{
												that.reset();
												pbPlaying = true;
												pAnimationData.playing.push(that);
												if (pOnInit)
													pOnInit(that);
											}
										if (!pbFinished)
											pResume();
									}
								
								this.stop = function()
									{
										pFinish();
									}
								
								function pIterate()
									{
										pnIteration++;
										if (pnIteration > pnFrames)
											{
												pFinish();
												if (poNext && !pbStopAfterFinish)
													poNext.play();
												return false;
											}

										if (poIterator)
											{
												poIterator(that);
											}
										else
											{
												var
													t = pnIteration / pnFrames,
													q4 = t*t*t,
													q2 = q4*3 + t*t*(-6) + t*3,
													q3 = q4*(-3) + t*t*3,
													qx = q2 * pnEase + q3 * pnEase + q4;
													pnValue = poStartValue + qx * pnDelta;
													if (pOnIterate)
														pOnIterate(that, pnValue);
													pApplyValue();
											}
									}

								function pResume()
									{
										poTimeout = setInterval(pIterate, pnTiming);
									}

								function pApplyValue()
									{
										if (psTargetId)
											poTarget = document.getElementById(psTargetId);
										if (poTarget)
											{
												if (poProperty)
													poTarget[poProperty] = pnValue + (psPostfix ? psPostfix : '');
												else
													if (poStyleProperty)
														poTarget.style[poStyleProperty] = pnValue + (psPostfix ? psPostfix : '');
											}
									}

								function pFinish()
									{
										pbFinished = true;
										pnValue = poFinishValue;
										that.pause();
										if (poIterator)
											poIterator(that);
										else
											pApplyValue();
										if (pOnStop)
											pOnStop(that);
									}
				
								this.append = function(oAnimation)
									{
										oAnimation.autoStart = false;
										poNext = oAnimation;
										pbStopAfterFinish = false;
										oAnimation.setPrevious(that);
									}
				
								
								this.pause = function()
									{
										if (pbPlaying)
											{
												pbPlaying = false;
												clearInterval(poTimeout);
												for(var i=0, L=pAnimationData.playing.length; i<L; i++)
													if (pAnimationData.playing[i] === that)
														{
															pAnimationData.playing.splice(i, 1);
															break;
														}
											}
									}
								
								this.getIteration = function()
									{
										return pnIteration;
									}
								
								this.getId = function()
									{
										return pnId;
									}

								this.getChainId = function()
									{
										return pnChainId;
									}
								
								this.setPrevious = function(oAnimation)
									{
										pnChainId = oAnimation.getChainId()+1;
										poPrevious = oAnimation;
									}
				
								this.getValue = function()
									{
										return pnValue;
									}
								
								this.getStatus = function()
									{
										if (pbFinished)
											return 'finished';
										if (pbPlaying)
											return 'playing';
										return 'paused';
									}
								
								this.getTarget = function()
									{
										return poTarget ? poTarget : (psTargetId ? document.getElementById(psTargetId) : null);
									}
								
								this.getData = function()
									{
										return poData ? poData : null;
									}

								this.clearData = function()
									{
										poNext = null;
										if (poPrevious)
											poPrevious.clearData();
										poPrevious = null;
									}
							}
							
						/* initializing animation */
						var
							oStartAnimation = null,
							oCurrentAnimation = null,
							oTemp = null;

						for (var i=0; i < arguments.length; i++)
							{
								var oItem = arguments[i];
								if (oStartAnimation)
									oItem.autoStart = false;
								oTemp = new AnimationInstance(oItem);
								if (oCurrentAnimation)
									oCurrentAnimation.append(oTemp);
								oCurrentAnimation = oTemp;
								if (!oStartAnimation)
									oStartAnimation = oTemp;
							}
						oCurrentAnimation = null;
						
						if (oStartAnimation.autoStart && oStartAnimation.isSync)
							{
								var oObjAnim = this.objectIsAnimated(oStartAnimation.getTarget());
								if (oObjAnim)
									oObjAnim.stop();
								oStartAnimation.play();
							}

						return oStartAnimation;
					}
				}
		})();
