/*
 * DNAnimation
 * A simple frame-based animation system
 *
 * @author Jack Weinert (CodeMonkz)
 */
function DNFrame(type,duration,omitReset)
{
	// GetType -----------------------------------------------------------------
	// Return the type of this frame.
	//
	// @return
	// null - no type set
	// otherwise - type of this frame
	// ----------------------------------------------------------------- GetType
	this.GetType = function()
	{
		return this.type;
	};
	
	// GetDuration -------------------------------------------------------------
	// Return the duration of this frame in milliseconds.
	//
	// @return
	// duration of this frame
	// ------------------------------------------------------------- GetDuration
	this.GetDuration = function()
	{
		return this.duration;
	};
	
	// IsResetOmitted ----------------------------------------------------------
	// Check if this frame should reset at end or not.
	//
	// @return
	// false - frame should not reset changes
	// true - frame should restore changes
	// ---------------------------------------------------------- IsResetOmitted
	this.IsResetOmitted = function()
	{
		return this.omitReset;
	};
	
	// OmitReset ---------------------------------------------------------------
	// Enable or disable the omitting of a reset at the end of this frame.
	//
	// @param
	// omitReset - true = omit reset
	//		otherwise = do reset
	// --------------------------------------------------------------- OmitReset
	this.OmitReset = function(omitReset)
	{
		if (omitReset)
		{
			if (omitReset === true)
			{
				this.omitReset = true;
				return;
			}
		}
		this.omitReset = false;
	};  
	
	// GetProgress -------------------------------------------------------------
	// Return the progress of this frame at a given time.
	//
	// @param
	// time - time in milli seconds
	//
	// @return
	// 0.0 - direct at the beginning
	// (0.0,1.0) - progress during the frame
	// 1.0 - direct at the end
	// ------------------------------------------------------------- GetProgress
	this.GetProgress = function(time)
	{
		if ((time <= 0) && (this.GetDuration() > 0))
		{
			return 0.0;
		}
		else if (time < this.duration)
		{
			return ((1.0 * time) / this.duration);
		}
		else
		{
			return 1.0;
		}
	};

	// SetDuration -------------------------------------------------------------
	// Set the duration of this frame.
	//
	// @param
	// duration - duration of the frame in milli seconds
	// ------------------------------------------------------------- SetDuration
	this.SetDuration = function(duration)
	{
		this.duration = duration;
	};
	
	// Prepare -----------------------------------------------------------------
	// This function will be called directly before the begin of the frame. 
	// ----------------------------------------------------------------- Prepare
	this.Prepare = function(element,animator)
	{
		if (this.IsResetOmitted() === false)
		{
			animator.Store(element,this.Store(element));
		}
		
		if (this.PrepareCallback)
		{
			this.PrepareCallback(element,animator);
		}
	};
	
	// Store -------------------------------------------------------------------
	// This function will be called when the element state should saved before
	// ANY modification will made. Override this function in derivated frames.
	//
	// @param
	// element - reference element
	//
	// @return
	// null - no parameters to store
	// otherwise - parameters that should stored
	// ------------------------------------------------------------------- Store
	this.Store = function(element)
	{
		return null;
	};
	
	// Final -------------------------------------------------------------------
	// This function will be called at the end of the frame. If a final callback
	// is set (via SetFinalCallback()) it will be called before the element will
	// reset to its initial state. The reset is controlled with OmitReset() and
	// checked with IsResetOmitted().
	//
	// @param
	// element - element
	// animator - 
	// ------------------------------------------------------------------- Final
	this.Final = function(element,animator)
	{
		if (this.FinalCallback)
		{
			this.FinalCallback(element,animator);
		}
		
		if (this.IsResetOmitted() === false)
		{
			this.Restore(element,animator.Restore(element));
		}
	};
	
	// Restore -----------------------------------------------------------------
	// This function will be called to restore the state of an element before
	// ANY modifications was made. Override this function in derivated frames.
	//
	// @param
	// element - reference element
	// parameters - stored parameters; result of Store()
	// ----------------------------------------------------------------- Restore
	this.Restore = function(element,parameters)
	{
		// empty
	};
	
	// ApplyToElement ----------------------------------------------------------
	// Apply the current state to an element.
	//
	// @param
	// element - destination element
	// animator - animator of this element
	// ---------------------------------------------------------- ApplyToElement
	this.ApplyToElement = function(element,animator)
	{
		var progress = this.GetProgress(animator.GetFrameTime(element));
		if ((progress >= 0.0) && (progress < 1.0))
		{
			// handle and set state depending on progress
		}
		else if (progress == 1.0)
		{
			// handle end state seperate to omit rounding/time errors
			// set frame end state
		}
	};

	this.type = type;
	this.PrepareCallback = null;
	this.FinalCallback = null;
	this.SetDuration(duration);
	this.OmitReset(omitReset);
}

// DNWaitFrame -----------------------------------------------------------------
// A wait frame just wait.
//
// @param
// duration - duration time
// ----------------------------------------------------------------- DNWaitFrame
function DNWaitFrame(duration)
{
	this.constructor('WAIT',duration,true);
	
	// GetWaitingTime ------------------------------------------------------
	// Return the time that should be waited before this frame is finished
	// in playback. This function is only an alias for GetDuration().
	//
	// @return
	// waiting time
	// ------------------------------------------------------ GetWaitingTime
	this.GetWaitingTime = function()
	{
		return this.GetDuration();
	};
}
DNWaitFrame.prototype = new DNFrame();

// DNSetClassFrame -------------------------------------------------------------
// Set a style class that will also be active after this frame.
//
// @param
// className - name of the style class
// ------------------------------------------------------------- DNSetClassFrame
function DNSetClassFrame(className)
{
	this.constructor('SETCLASS',0,true);
	
	// GetClassName --------------------------------------------------------
	// Return the name of the style class that will set with this frame.
	//
	// @return
	// null - no style class set
	// -------------------------------------------------------- GetClassName
	this.GetClassName = function()
	{
		return this.className;
	};
	
	// SetClassName --------------------------------------------------------
	// Set the style class that should set with this frame.
	//
	// @param
	// className - name of the style class
	// -------------------------------------------------------- SetClassName
	this.SetClassName = function(className)
	{
		if (className)
		{
			this.className = className;
			return;
		}
		else
		{
			this.className = null;
		}
	};
	
	// ApplyToElement ------------------------------------------------------
	// Apply the style class to an element.
	// ------------------------------------------------------ ApplyToElement
	this.ApplyToElement = function(element,animator)
	{
		// var progress = this.GetProgress(animator.GetFrameTime(element));
		if (this.className)
		{
			HTML.AppendElementClass(element,this.className);
		}
	};
	
	this.SetClassName(className);
}
DNSetClassFrame.prototype = new DNFrame();

function DNRemoveClassFrame(className)
{
	this.constructor('REMOVECLASS',0,true);
	
	// GetClassName --------------------------------------------------------
	// Return the name of the style class that will removed with this frame.
	//
	// @return
	// name of the style class
	// -------------------------------------------------------- GetClassName
	this.GetClassName = function()
	{
		return this.className;
	};
	
	// SetClassName --------------------------------------------------------
	// Set the name of the style class that will removed with this frame.
	//
	// @param
	// className - name of the style class
	// -------------------------------------------------------- SetClassName
	this.SetClassName = function(className)
	{
		if (className)
		{
			this.className = className;
			return;
		}
		else
		{
			this.className = null;
		}
	};
	
	// ApplyToElement ------------------------------------------------------
	//
	// ------------------------------------------------------ ApplyToElement
	this.ApplyToElement = function(element,elapsedTime)
	{
		if (this.className)
		{
			HTML.RemoveElementClass(element,this.className);
		}
	};
	
	this.SetClassName(className);
}
DNRemoveClassFrame.prototype = new DNFrame();

// DNClassFrame ----------------------------------------------------------------
// Set a style class for the time of this frame.
//
// @param
// duration - duration time
// omitReset - false = after the frame is played the style class will removed
//	true = the style class will kept setted after the frame is played
// className - name of the style class
// ---------------------------------------------------------------- DNClassFrame
function DNClassFrame(duration,omitReset,className)
{
	this.constructor('CLASS',duration,omitReset);
	
	// GetClass ------------------------------------------------------------
	// Return the style class name.
	//
	// @return
	// style class name
	// ------------------------------------------------------------ GetClass
	this.GetClass = function()
	{
		return this.className;
	};
	
	// SetClass ------------------------------------------------------------
	// Set the name of the style class.
	//
	// @param
	// className - name of the style class
	// ------------------------------------------------------------ SetClass
	this.SetClass = function(className)
	{
		this.className = className;
	};
	
	// Store ---------------------------------------------------------------
	// Return all data of a html element that should stored to restore it
	// after the playback of this frame
	//
	// @param
	// element - reference element
	//
	// @return
	// collected data
	// --------------------------------------------------------------- Store
	this.Store = function(element)
	{
		var parameters = [];
		var className = this.GetClass();
		if (className)
		{
			if (HTML.HasElementClass(element,className) == true)
			{
				parameters[className] = true;
			}
			else
			{
				parameters[className] = false;
			}
		}
		
		return parameters;
	};
	
	// Restore -------------------------------------------------------------
	// Restore the data of a html element that was previously stored with
	// Store().
	//
	// @param
	// element - reference element
	// parameters - data that was returned by Store()
	// ------------------------------------------------------------- Restore
	this.Restore = function(element,parameters)
	{
		if (parameters)
		{
			var className = this.GetClass();
			if (parameters[className] === true)
			{
				HTML.AppendElementClass(element,className);
			}
			else if (parameters[className] === false)
			{
				HTML.RemoveElementClass(element,className);
			}
		}
	};
	
	// ApplyToElement ------------------------------------------------------
	// Apply the style class to a html element.
	// ------------------------------------------------------ ApplyToElement
	this.ApplyToElement = function(element,animator)
	{
		var progress = this.GetProgress(animator.GetFrameTime(element));
		if ((progress >= 0.0) && (progress < 1.0))
		{
			HTML.AppendElementClass(element,this.className);
		}
		else if (progress == 1.0)
		{
			if (this.IsResetOmitted() !== true)
			{
				HTML.RemoveElementClass(element,this.className);
			}
			else
			{
				//alert('Setting '+this.className+' class to '+element);
				HTML.AppendElementClass(element,this.className);
			}
		}
	};
	
	this.SetClass(className);
}
DNClassFrame.prototype = new DNFrame();

// DNStyleFrame ----------------------------------------------------------------
// Set an independent style during this frame.
//
// @param
// duration - duration time
// omitReset - false = restore previous setting
//	true = keep style setting after this frame is finished in playback
// styleName - name of the style
// value - value
// ---------------------------------------------------------------- DNStyleFrame
function DNStyleFrame(duration,omitReset,styleName,value)
{
	this.constructor('STYLE',duration,omitReset);
	
	// SetStyle ------------------------------------------------------------
	// Set the style of this frame
	//
	// @param
	// style - style name
	// ------------------------------------------------------------ SetStyle
	this.SetStyle = function(style)
	{
		this.styleName = style;
	};
	
	// SetValue ------------------------------------------------------------
	// Set the value of the style that will be set during this frame.
	//
	// @param
	// value - value
	// ------------------------------------------------------------ SetValue
	this.SetValue = function(value)
	{
		this.styleValue = value;
	};
	
	// Store ---------------------------------------------------------------
	// Store data of the element before it will be modified.
	// --------------------------------------------------------------- Store
	this.Store = function(element)
	{
		var parameters = [];
		var styleName = this.GetStyle();
		if (styleName)
		{
			if (element.style[styleName] !== null)
			{
				parameters[styleName] = element.style[styleName];
			}
			else
			{
				parameters[styleName] = '';
			}
		}
		
		return parameters;
	};
	
	// Restore -------------------------------------------------------------
	// Restore data of the element after this frame was played.
	// ------------------------------------------------------------- Restore
	this.Restore = function(element,parameters)
	{
		var styleName = this.GetStyle();
		if (styleName)
		{
			if (parameters[styleName] !== null)
			{
				element.style[styleName] = parameters[styleName];
			}
		}
	}
	
	// ApplyToElement ------------------------------------------------------
	// Apply the modification to an element
	// ------------------------------------------------------ ApplyToElement
	this.ApplyToElement = function(element,animator)
	{
		var progress = this.GetProgress(animator.GetFrameTime(element));		
		if ((progress >= 0.0) && (progress < 1.0))
		{
			element.style[this.styleName] = this.styleValue;
		}
		else if (progress == 1.0)
		{
			if (this.IsResetOmitted() !== true)
			{
				element.style[this.styleName] = '';
				//alert('removed: ' + this.styleName + ':' + this.styleValue);
			}
			else
			{
				element.style[this.styleName] = this.styleValue;
				//alert('stay: ' + this.styleName + ':' + this.styleValue);
			}
		}
	};
	
	this.SetStyle(styleName);
	this.SetValue(value);
}
DNStyleFrame.prototype = new DNFrame();

// DNStyleValueFrame -----------------------------------------------------------
// @param
// duration - duration of the frame
// option - name of the option that should changed
// fromValue - start value
// toValue - end value
// suffix - value suffix, can be 'px', '%', 
// iType - interpolation type
// ----------------------------------------------------------- DNStyleValueFrame
function DNStyleValueFrame(duration,omitReset,optionName,fromValue,toValue,suffix,iType)
{
	this.constructor('STYLEVALUE',duration,omitReset);
		
	// 
	this.SetOptionName = function(optionName)
	{
		this.optionName = optionName;
	};
	
	this.SetStartValue = function(value)
	{
		this.startValue = value;
	};
	
	this.SetEndValue = function(value)
	{
		this.endValue = value;
	};
	
	this.SetValueSuffix = function(suffix)
	{
		this.valueSuffix = suffix;
	};
	
	this.SetInterpolationType = function(iType)
	{
		this.iType = iType;
	};
	
	// Store ---------------------------------------------------------------
	// Store data of the element before it will be modified.
	// --------------------------------------------------------------- Store
	this.Store = function(element)
	{
		var parameters = [];
		var styleName = this.optionName;
		if (styleName)
		{
			if (element.style[styleName] != null)
			{
				parameters[styleName] = element.style[styleName];
			}
			else
			{
				parameters[styleName] = '';
			}
		}
		
		return parameters;
	};
	
	// Restore -------------------------------------------------------------
	// Restore data of the element after this frame was played.
	// ------------------------------------------------------------- Restore
	this.Restore = function(element,parameters)
	{
		if (parameters)
		{
			var styleName = this.optionName;
			if (parameters[styleName] !== null)
			{
				element.style[styleName] = parameters[styleName];
			}
		}
	};
	
	// ApplyToElement ------------------------------------------------------
	// Apply the modification to an element
	// ------------------------------------------------------ ApplyToElement
	this.ApplyToElement = function(element,animator)
	{
		var progress = this.GetProgress(animator.GetFrameTime(element));
		var value;
		if (this.iType == 'LINEAR')
		{
			value = ((this.endValue - this.startValue) * progress) + this.startValue;
		}
		else if (this.iType == 'SQUARE')
		{
			value = ((this.endValue - this.startValue) * (progress * progress)) + this.startValue;
		}
		
		var writeOption = true;
		if (progress == 1.0)
		{
			if (this.IsResetOmitted() !== true)
			{
				element.style[this.optionName] = '';
				writeOption = false;
			}
		}
		
		if (this.valueSuffix == 'px')
		{
			value += 0.5;
			value = DN_ValueToFixed(value);
		}
		else if (this.valueSuffix == '%')
		{
			value = DN_ValueToFixed(value,2);
		}		
		if (value)
		{
			value = value.toString() + this.valueSuffix;
		}
		
		if ((writeOption === true) && (value))
		{
			element.style[this.optionName] = value;
			//alert(value);
		}
	};
	
	this.SetOptionName(optionName);
	this.SetStartValue(fromValue);
	this.SetEndValue(toValue);
	this.SetValueSuffix(suffix);
	this.SetInterpolationType(iType);
}
DNStyleValueFrame.prototype = new DNFrame();

function DNComplexStyleValuesFrame(duration,omitReset,optionName,optionValueFormat,fromValues,toValues,iType)
{
	this.constructor('COMPLEXSTYLEVALUE',duration,omitReset);
	
	this.SetOptionName = function(optionName)
	{
		this.optionName = optionName;
	};
	
	this.SetOptionValueFormat = function(optionValueFormat)
	{
		this.optionValueFormat = optionValueFormat;
	};
	
	this.SetInterpolationType = function(iType)
	{
		this.iType = iType;
	};
	
	this.SetStartValues = function(startValues)
	{
		this.startValues = startValues;
	};
	
	this.SetEndValues = function(endValues)
	{
		this.endValues = endValues;
	};

	// Store ---------------------------------------------------------------
	// Store data of the element before it will be modified.
	// --------------------------------------------------------------- Store
	this.Store = function(element)
	{
		var parameters = [];
		var styleName = this.optionName;
		if (styleName)
		{
			if (element.style[styleName] != null)
			{
				parameters[styleName] = element.style[styleName];
			}
			else
			{
				parameters[styleName] = '';
			}
		}
		
		return parameters;
	};
	
	// Restore -------------------------------------------------------------
	// Restore data of the element after this frame was played.
	// ------------------------------------------------------------- Restore
	this.Restore = function(element,parameters)
	{
		if (parameters)
		{
			var styleName = this.optionName;
			if (parameters[styleName] !== null)
			{
				element.style[styleName] = parameters[styleName];
			}
		}
	};

	
	this.ApplyToElement = function(element,animator)
	{
		var progress = this.GetProgress(animator.GetFrameTime(element));
		var values = [];
		for (var i in this.startValues)
		{
			var startValue = this.startValues[i]['value'];
			var endValue = this.endValues[i]['value'];
			var value;
			if (this.iType == 'LINEAR')
			{
				value = ((endValue - startValue) * progress) + startValue;
			}
			else if (this.iType == 'SQUARE')
			{
				value = ((endValue - startValue) * (progress * progress)) + startValue;
			}
			
			//value = value.toString(10) + this.startValues[i]['suffix'];
			values.push(value);
		}
		
		var optionValue = String.sprintf(this.optionValueFormat,values);
		
		element.style[this.optionName] = optionValue;
	};
	
	this.SetOptionName(optionName);
	this.SetOptionValueFormat(optionValueFormat);
	this.SetStartValues(fromValues);
	this.SetEndValues(toValues);
	this.SetInterpolationType(iType);
}
DNComplexStyleValuesFrame.prototype = new DNFrame();

function DNAnimation(baseElement)
{
	this.StartCallback = null;
	this.EndCallback = null;
	this.frames = [];
	
	// GetBaseElement ----------------------------------------------------------
	// Return the base element of this animation.
	//
	// @return
	// null - no base element set
	// ---------------------------------------------------------- GetBaseElement
	this.GetBaseElement = function()
	{
		return this.baseElement;
	};
	
	// IsRunning ---------------------------------------------------------------
	// Check if this animation is currently running or not.
	//
	// @return
	// false - animation is not running
	// true - animation is running
	// --------------------------------------------------------------- IsRunning
	this.IsRunning = function()
	{
		return this.isRunning;
	};
	
	// IsFinished --------------------------------------------------------------
	// Check if this animation is finished or not.
	//
	// @return
	// false - animation is not finished.
	// true - animation is finished.
	// -------------------------------------------------------------- IsFinished
	this.IsFinished = function()
	{
		return this.isFinished;
	};
	
	// GetDuration -------------------------------------------------------------
	// Return the overall duration time of this animation.
	//
	// @return
	// overall duration time
	// ------------------------------------------------------------- GetDuration
	this.GetDuration = function()
	{
		var duration = 0;
		for (var i in this.frames)
		{
			duration += Number(this.frames[i].GetDuration());
		}
		
		return duration;
	};
	
	// StartAnimation ----------------------------------------------------------
	// @return
	// null - starting animation failed, no frames exists or no base element set
	// false - animation not started because its already running
	// true - animation started 
	// ---------------------------------------------------------- StartAnimation
	this.StartAnimation = function()
	{
		if ( (!this.baseElement) ||
			(this.frames.length == 0) )
		{
			return null;
		}
		
		if (this.IsRunning() == false)
		{
			this.frameTime = 0;
			this.frame = this.frames[0];
			this.frameIndex = 0;
			this.isRunning = true;
			return true;
		}
		
		return false;
	};
	
	// SetBaseElement ----------------------------------------------------------
	// Set the base element of this animation.
	//
	// @param
	// baseElement - base element of this animation
	//
	// @return
	// false - given base element is not set
	// true - base element is set
	// ---------------------------------------------------------- SetBaseElement
	this.SetBaseElement = function(baseElement)
	{
		if (baseElement)
		{
			if (this.IsRunning() === false)
			{
				this.baseElement = baseElement;
				return true;
			}
		}
		return false;
	};
	
	// GetFrameCount -----------------------------------------------------------
	// Return the number of frames in this animation.
	//
	// @return
	// number of frames
	// ----------------------------------------------------------- GetFrameCount
	this.GetFrameCount = function()
	{
		return this.frames.length;
	};
	
	// GetFrame ----------------------------------------------------------------
	// Return a single frame of this animation.
	//
	// @param
	// frameIndex - index of the frame; valid range is [0,GetFrameCount())
	//
	// @return
	// null - frame index out of range
	// otherwise - frame
	// ---------------------------------------------------------------- GetFrame
	this.GetFrame = function(frameIndex)
	{
		if (frameIndex < this.frames.length)
		{
			return this.frames[frameIndex];
		}
		
		return null;
	};
	
	// AppendFrame -------------------------------------------------------------
	// Append a frame to this animation.
	//
	// @param
	// frame - frame that should append
	//
	// @return
	// false - appending failed
	// true - successful appended frame
	// ------------------------------------------------------------- AppendFrame
	this.AppendFrame = function(frame)
	{
		if ( (frame) &&
			(this.IsRunning() === false) )
		{
			this.frames.push(frame);
			return true;
		}
		return false;
	};
	
	this.GetFrameTime = function(element)
	{
		return this.frameTime;
	};
	
	this.Store = function(element,parameters)
	{
		this.frameParameters = parameters;
	};
	
	this.Restore = function(element)
	{
		return this.frameParameters;
	};
	
	// Update ------------------------------------------------------------------
	//
	// @return
	// false - animation is finished and need no more Update() calls
	// true - animation still need more Update() calls
	// ------------------------------------------------------------------ Update
	this.Update = function(elapsedTime)
	{
		if (this.IsRunning())
		{
			while ((this.IsFinished() === false) && (elapsedTime > 0))
			{
				var frameDuration = this.frame.GetDuration();
				if ((this.frameTime + elapsedTime) < frameDuration)
				{
					this.frameTime += elapsedTime;
					elapsedTime = 0;
					
					this.frame.ApplyToElement(this.baseElement,this);
				}
				else
				{
					elapsedTime -= (frameDuration - this.frameTime);
					this.frameTime = frameDuration;
					this.frame.ApplyToElement(this.baseElement,this);
					this.frame.Final(this.baseElement,this);
					
					if (this.frameIndex < (this.frames.length - 1))
					{
						// frame end reached
						this.frameTime = 0;
						this.frameIndex++;
						
						this.frame = this.frames[this.frameIndex];
						this.frame.Prepare(this.baseElement,this);
						
						if (elapsedTime == 0)
						{
							this.frame.ApplyToElement(this.baseElement,this);
						}
					}
					else
					{
						// animation end reached
						elapsedTime = 0;
						this.isFinished = true;
					}
				}
			}
		
			return ((this.IsFinished()) ? (false) : (true));
		}
		else
		{
			// not started, so request more Update() calls		
			return true;
		}
	};
	
	this.isRunning = false;
	this.isFinished = false;
	this.SetBaseElement(baseElement);
}

function DNAnimationServer(timePerCycle)
{
	this.animations = [];
	this.frameCount = 0;
	
	this.GetTimePerCycle = function()
	{
		return this.timePerCycle;
	};
	
	this.IsAnimationPlaying = function()
	{
		return ((this.animations.length > 0) ? (true) : (false));
	};
	
	this.SetTimePerCycle = function(timePerCycle)
	{
		this.timePerCycle = timePerCycle;
	};
	
	this.AppendAnimation = function(animation)
	{
		if (animation)
		{
			this.animations.push(animation);
			return true;
		}
		return false;
	};
	
	this.SetTimer = function()
	{
		window.setTimeout('DNAniServer.Update('+ this.timePerCycle +');',this.timePerCycle);
	};

	this.Update = function(elapsedTime)
	{
		var nextAnimations = [];
		var animation = this.animations.shift();
		while (animation)
		{
			if (animation.Update(elapsedTime))
			{
				nextAnimations.push(animation);
			}
			
			animation = this.animations.shift();
		}
		this.animations = nextAnimations;
		
		this.SetTimer();
		
		// debug
		this.frameCount++;
		var stateDiv = HTML.GetElementByID('aniServerState');
		if (stateDiv)
		{
			stateDiv.innerHTML = 'Frames: '+this.frameCount+' AnimationCount: '+this.animations.length;
		}
	};
	
	this.SetTimePerCycle(timePerCycle);
	this.SetTimer();
}

var DNAniServer = ((!DNAniServer) ? (new DNAnimationServer(50)) : (DNAniServer));

function sprintf()
{
	if (sprintf.arguments.length >= 1)
	{
		var strfmt = sprintf.arguments[0];
		
		if (sprintf.arguments.length < 2)
		{
			return sprintf.arguments[0];
		}
		
		var args = new Array();
		if ((sprintf.arguments.length == 2) && (typeof(sprintf.arguments[1]) == 'object'))
		{
			args = sprintf.arguments[1];
		}
		else
		{
			for (var i=1;i < sprintf.arguments.length;i++)
			{
				args.push(sprintf.arguments[i]);
			}
		}
		
		for (var i in args)
		{
			switch (typeof(args[i]))
			{
			case 'string':
				strfmt = strfmt.replace(/%s/,args[i]);
				break;
			case 'number':
				strfmt = strfmt.replace(/%d/,args[i]);
				break;
			case 'boolean':
				strfmt = strfmt.replace(/%b/,((args[i] === true) ? ('true') : ('false')));
				break;
			default:
				// skip argument
				break;
			}
		}
		
		return strfmt;
	}
	return null;
}

if (!(String.sprintf))
{
	String.sprintf = sprintf;
}

// TESTING ---------------------------------------------------------------------
function DN_TestAni(element)
{
	var ani = new DNAnimation(element);
	ani.AppendFrame(new DNClassFrame(0,false,'DN_hide'));
	ani.AppendFrame(new DNStyleFrame(1000,false,'color','#ff00ff'));
	ani.AppendFrame(new DNStyleFrame(0,false,'height','100px'));
	ani.AppendFrame(new DNStyleFrame(0,true,'color','#ff00ff'));
	ani.AppendFrame(new DNStyleValueFrame(1000,false,'height',20,300,'px','SQUARE'));
	ani.AppendFrame(new DNStyleValueFrame(1000,false,'height',300,20,'px','SQUARE'));
	ani.AppendFrame(new DNStyleFrame(0,false,'height','100px'));
	ani.AppendFrame(new DNStyleFrame(0,false,'color',''));	
	ani.StartAnimation();
	DNAniServer.AppendAnimation(ani);
}
// --------------------------------------------------------------------- TESTING

