// The Mouse Movie namespace
var MouseMovie = 
{
	// A timeline with a stack of mouse position frames
	TimeLine : function ()
	{
		// --- Public variables ---
		this.Frames = new Array();
		this.FirstFrame;
		this.LastFrame;
		
		// Add a frame to the stack of frame with the options passed 
		this.addFrame = function (options) 
						{ 
							// Create a new frame
							var NewFrame = new MouseMovie.Frame({XPosition: options.XPosition, YPosition: options.YPosition});
							
							// Set the previous frame for the new frame and the next frame for the last frame
							if (this.Frames.length > 0)
							{
								var PreviousFrame = this.Frames[this.Frames.length - 1];
								NewFrame.PreviousFrame = PreviousFrame;
								PreviousFrame.NextFrame = NewFrame;
							}
							// If this is the first frame in the stack, set the FirstFrame property
							else
								this.FirstFrame = NewFrame;
							
							// Add the new frame to the stack
							this.Frames.push(NewFrame); 
							this.LastFrame = NewFrame;
						}
		
		// Override the toString() function
		this.toString =	function ()
						{
							var serializedTimeline = "";
							$A(this.Frames).each( function(frame){serializedTimeline += "[ " + frame + " ] "; })
							return serializedTimeline;
						}	
	},
	
	// An individual mouse position frame
	Frame : function (options)
	{
		// Public
		this.TimeStamp = Date();
		this.XPosition = 0;
		this.YPosition = 0;
		this.NextFrame;
		this.PreviousFrame;
		
		// Override the toString() function
		this.toString =	function ()
						{
							var serializedFrame;
							serializedFrame = "X Position: " + this.XPosition + ", ";
							serializedFrame += "Y Position: " + this.YPosition + ", ";
							serializedFrame += "TimeStamp: " + this.TimeStamp;
							return serializedFrame;
						}
		
		// Initialize with any options passed to the constructor
		if (options)
		{
			if (options.XPosition)
				this.XPosition = options.XPosition;
			if (options.YPosition)
				this.YPosition = options.YPosition;
			if (options.PreviousFrame)
				this.PreviousFrame = options.PreviousFrame;
			if (options.NextFrame)
				this.NextFrame = options.NextFrame;
		}
	},
	
	// A tracker for tracking the mouse as it moves
	// The tracker can take in an external timeline or use an internal one if the user provides none
	Tracker : function (ThisTimeLine)
	{
		// Get the TimeLine passed to the tracker
		// or create a new TimeLine
		if (ThisTimeLine)
			var _TimeLine = ThisTimeLine;
		else
			var _TimeLine = new MouseMovie.TimeLine();
		
		// Make the TimeLine public	
		this.TimeLine = _TimeLine;
		
		// Is the tracker running or not?
		this.Running = false;
		
		// Functions for starting and stopping the mouse tracker
		this.start = function () {Event.observe(window, "mousemove",  _trackMouse); this.Running = true; };	  
		this.stop = function () { Event.stopObserving(window, "mousemove", _trackMouse); this.Running = false; };
		
		// The function that tracks the mouse and adds a frame for each position of the mouse  
		function _trackMouse(e)
		{
			_TimeLine.addFrame({ XPosition: Event.pointerX(e), YPosition: Event.pointerY(e)});
		}
	},
	
	// Function that animates the timeline that is passed to it
	Animate : function (options)
	{
		// Set the speed to the option passed or to a default
		var _speed = options.Speed || 10;
		
		// Get the cursor from the options
		if (options.Cursor)
			var _cursor = options.Cursor;
		
		// If a cursor was passed to the animator, create a new cursor
		else
		{
			// Create a new cursor and style it
			var newCursor = document.createElement("div");
			newCursor.style.background = "green";
			newCursor.style.height = "10px";
			newCursor.style.width = "10px";
			newCursor.style.position = "absolute";
			newCursor.style.top = 0;
			newCursor.style.left = 0;
			
			// Add the cursor to the body
			var body = document.getElementsByTagName("body")[0];
			body.appendChild(newCursor);
			
			_cursor = newCursor;
		}
		
		
		// Start moving the cursor
		_moveCursor(options.TimeLine.FirstFrame);
	
		function _moveCursor(CurrentFrame)
		{
			_cursor.style.top = CurrentFrame.YPosition + "px";
			_cursor.style.left = CurrentFrame.XPosition + "px";
			
			if(CurrentFrame.NextFrame)
			{
				setTimeout(_moveCursor,_speed,CurrentFrame.NextFrame);
				return true;
			}
			else
				return false;
		}
	},
	
	// Function that traces the path of the mouse animation
	Trace : function (TimeLine)
	{
		// Loops through the frames and draws a point for each frame
		var FrameArray = $A(TimeLine.Frames);
		FrameArray.each(
							function(CurrentFrame)
							{
								// Create a new cursor and style it
								var newPoint = document.createElement("div");
								newPoint.style.background = "green";
								newPoint.style.height = "5px";
								newPoint.style.width = "5px";
								newPoint.style.position = "absolute";
								newPoint.style.top = CurrentFrame.YPosition + "px";
								newPoint.style.left = CurrentFrame.XPosition + "px";
								
								// Add the cursor to the body
								var body = document.getElementsByTagName("body")[0];
								body.appendChild(newPoint);
							}
						)
	
	}
}
