/*
Interval - Provides missing setInterval and setTimeout functionality.
Copyright (c) 2006 Thomas Peri, http://www.tumuski.com/

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The Software shall be used for Good, not Evil.

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/**
 * Interval.js
 * 2006-11-12
 *
 * Some older browsers don't support the passing of a function
 * as the first argument.  This class should allow any browser
 * to use the (function, interval, args...) pattern.  It also
 * provides that functionality to timeouts.
 *
 * Parameters:
 *
 *   (Function) func            The function to call repeatedly.
 *
 *   (Integer)  interval|delay  The delay, in milliseconds, 
 *                              between each time func is called (Interval),
 *                              or before func is called (Timeout).
 *
 *   (Mixed)    args...         Any number of arguments, 
 *                              which will be passed to func.
 * Example:
 * 
 *   function myFunction (a, b, c) { ... }
 *   var howOften = 2000;
 *   var myInterval = new Interval(myFunction, howOften, 1, 2, 3);
 *   ...
 *   myInterval.clear();
 *
 */
var Interval, Timeout;
(function()
{
	var intervals = [];
	var checkInterval;
	var count = 0;
	
	// guilty until proven innocent
	var archaic = true;
	(function()
	{
		checkInterval = setInterval(
			function()
			{
				clearInterval(checkInterval);
				archaic = false;
			},
			0
		);
		// Just in case some wacky browser decides to convert the
		// function to a string and then declare it ad infinitum...
		setTimeout("Interval.clearCheckInterval()", 100);
	})();
	
	function nextAvailableIndex()
	{
		for (var i = 0; i < intervals.length; i++)
		{
			if (!intervals[i])
			{
				break;
			}
		}
		return i;
	}
	
	function pullArgs(a)
	{
		// 2 is the magic number for both interval and timeout args position
		var args = [];
		for (var arg = 2; arg < a.length; arg++)
		{
			args[args.length] = a[arg];
		}
		return args;
	}
	
	function stringArgs(a)
	{
		var s = [];
		for (var i = 0; i < a.length; i++)
		{
			s[s.length] = 'a['+i+']';
		}
		return 'f('+s.join(',')+');'
	}
	
	Interval = (function()
	{
		function Interval(func, interval, args)
		{
			var i, handle, running = true;
			count++;
			
			args = pullArgs(arguments);
			
			if (archaic)
			{
				i = nextAvailableIndex();
				intervals[i] =
				{
					func: func,
					args: args,
					code: stringArgs(args)
				};
				handle = setInterval("Interval.invoke("+i+");", interval);
			}
			else
			{
				handle = setInterval(
					function()
					{
						func.apply(null, args);
					},
					interval
				);
			}
			
			this.clear = function()
			{
				if (running)
				{
					running = false;
					count--;
					this.clear = function(){};
					clearInterval(handle);
					if (archaic)
					{
						intervals[i] = null;
						if (count === 0)
						{
							intervals = [];
						}
					}
				}
			};
		}
		
		/**
		 * For internal use only.
		 */
		Interval.invoke = function(i)
		{
			var o = intervals[i];
			var f = o.func;
			var a = o.args;
			eval(o.code);
		};
		
		/**
		 * For internal use only.
		 */
		Interval.clearCheckInterval = function()
		{
			clearInterval(checkInterval);
		};
			
		return Interval;
	})();
	
	Timeout = function(func, delay, args)
	{
		args = pullArgs(arguments);
	
		var handle = new Interval(
			function()
			{
				// to do:
				// 
			
			
				handle.clear();
				if (archaic)
				{
					var f = func;
					var a = args;
					eval(stringArgs(a));
				}
				else
				{
					func.apply(null, args);
				}
			},
			delay
		);
		
		this.clear = function()
		{
			handle.clear();
		};
	};
	
})();


