/* DB_Interval extends the setInterval method of Javascript */

DB_Interval = function (func, interval, max) 
{
	/* Log Start */
	log('DB_Interval(func='+ func+',interval='+ interval+', max='+max);
	/* Log End */
	this.count = 0;
	this.max = max || 0;
	this.interval = interval; /* # in ms */
	this.interval_func;
	this.func = func;

	var tb = DB_Thunder.Base;

	this.start = function ()
	{
		if (!this.interval_func)
		{
			var _func = tb.bind(this.next, this);
			this.interval_func = window.setInterval(_func, this.interval);
		}
	}
	this.stop = function ()
	{
		if (this.interval_func)
		{
			window.clearInterval(this.interval_func);
			this.interval_func = null;
		}
	}
	this.next = function()
	{
		this.count += 1;
		if (this.max && this.count > this.max)
		{
			this.stop();
		}
		else 
		{
			this.func();
		}
	},
	this.reset = function()
	{
		this.stop();
		this.start();
	}

	// Setup the function that will be called by setInterval
	var _func = tb.bind(this.next, this);
}

DB_View = function (article_viewers, article_tabs, article_objects, fmap)
{
	this.NAME = 'DB_View';
	// These hold the rotator_contents' uh content
	this.article_viewers = article_viewers;
	this.article_tabs = article_tabs;
	this.article_objects = article_objects;
	this.fmap = fmap;
	this.current_article = 0;//current_article is 0 based

	var ar = DB_Thunder.Article_Rotator;
	// Render Article Tabs
	for (var i=0; i < this.article_tabs.length; i++)
	{
		var oTab = this.article_tabs[i];
		var oArticle = this.article_objects[i];
		ar.render_object(oArticle, oTab, this.fmap);
	}
}

DB_View.prototype = {
	get_content : function (index)
	{
		var i = index % this.article_objects.length;
		return this.article_objects[i];
	},
	get_viewer : function (index)
	{
		var i = index % this.article_viewers.length;
		return this.article_viewers[i];
	},
	/* Set which article_tab is active */
	set_article_tab : function (index)
	{
		// fast path, no article tabs
		if (this.article_tabs.length <= 0)
			{ return; }

		var td = DB_Thunder.DOM;

		for (i=0; i < this.article_tabs.length; i++)
		{
			var oTab = this.article_tabs[i];
			if (this.current_article == i)
			{
				td.addClassName(oTab,"active");
			}
			else
			{
				td.removeClassName(oTab,"active"); 
			}
		}
	},
	loop_to : function (article_index)
	{
		/* Guard aganst crazy inputs. article_index wraps */
               
		while (article_index >= this.article_objects.length)
		{
			article_index -= this.article_objects.length;
		}
		while (article_index < 0)
		{
			article_index += this.article_objects.length;
		}

		var ar = DB_Thunder.Article_Rotator;
		this.current_article = article_index;
		for (var i = 0; i < this.article_viewers.length; i++)
		{
			ar.render_object( this.get_content(article_index+i), this.get_viewer(i) );
		}
		this.set_article_tab(article_index);
		/* Log Start */
		log('loop_to called on',this.NAME,'current_article:',this.current_article
			,'number of articles', this.article_objects.length);
		/* Log End */
	},
	next : function ()
	{
			this.loop_to(this.current_article + 1);
	},
	back : function ()
	{
			this.loop_to(this.current_article - 1);
	}
};
			

/*
	DB_Rotator Constructor
*/
DB_Rotator = function (fmap, view, controls, interval)
{
	this.NAME = 'DB_Rotator';
	// Setup variables
	this.rotation_interval = 10000;
	this.rotation_on = false;
	this.no_load = false;
	this.timeout_func;
	this.loop_handlers = [];
	this.fmap = fmap;
	this.controls = {};

	var tm = DB_Thunder.DOM;
	var ar = DB_Thunder.Article_Rotator;

	if (!view)
	{
		view = DB_View;
	}

	if (typeof(interval) != 'undefined')
	{
		this.rotation_interval = interval;
	}

	var article_viewers = tm.getElementsByTagAndClass(document, "*", "article_viewer");
	var article_tabs = tm.getElementsByTagAndClass(document, "*", "article_tab");
	var article_contents = tm.getElementsByTagAndClass(document, '*', 'article_content');
	var article_objects = [];

	// No points in going further if we have no article contents
	if (article_contents.length <= 0 )
	{
		this.start = DB_Thunder.Base.noop;
		return null;
	}

	if (typeof(controls) == 'string')
	{
		controls = document.getElementById(controls);
	}

	for (var i=0; i < article_contents.length; i++)
	{
		article_objects.push(ar.create_db_object(article_contents[i]));
	}

	// Instantiate a view
	this.view = new view(article_viewers, article_tabs, article_objects, fmap);

	this.activate_controls(controls);

	// Setup interval object
	var _func = bind( function () {
		this.rotation_loop();
	}, this);
	this.interval_object = new DB_Interval(_func, this.rotation_interval);

	// Setup article Tabs
	log("setup_article_tabs this = ",this);
	var tb = DB_Thunder.Base;
	var ar = DB_Thunder.Article_Rotator;
	for (var i=0; i < article_tabs.length; i++)
	{
		var article_tab_click = tb.bind(
			function (index) { this.loop_to(index);},
			this,
			i);

		var oTab = article_tabs[i];
		EventUtil.addEventHandler(oTab, "click", article_tab_click); 
	}
	// Populate once
	this.loop_to(0);
};

/*
	DB_Rotator Methods
*/
DB_Rotator.prototype = {
	set_interval : function (interval)
	{ /* change interval of rotator */
		this.rotation_interval = interval;
		this.interval_object.interval = interval;
	},
	get_interval : function ()
	{
		return this.rotation_interval;
	},
	loop_to : function (index)
	{/* Place loophandlers in here */

		this.callLoopHandlers();

		if (typeof(index) == 'string')
		{
			if (index == 'next')
				this.view.next();
			if (index == 'back')
				this.view.back();
		}
		if (typeof(index) == 'number')
		{
			this.view.loop_to(index);
		}
		this.set_active_number();
		this.interval_object.reset();
	},
	next : function ()
	{
		/* Log Start */
		log('next called on', this.NAME);
		/* Log End */
		this.loop_to("next");
	},
	back : function ()
	{
		/* Log Start */
		log('back called on', this.NAME);
		/* Log End */
		this.loop_to("back");
	},
	stop : function ()
	{
		/* Log Start */
		log('stop called on', this.NAME);
		/* Log End */
		this.rotation_on = false;
		this.interval_object.stop();
	},
	rotation_loop : function ()
	{
		log("rotation_loop this =",this.NAME);
		if (this.rotation_on) 
		{
			this.next();
		}
		else 
		{
			this.timeout_func = null;
		}
	},
	start : function ()
	{
		this.rotation_on = true;
		this.interval_object.start();
	},
	attachLoopHandler : function (func)
	{
		if (func)
		{
			this.loop_handlers.push(func);
		}
	},
	callLoopHandlers : function ()
	{
		for (var i=0; i < this.loop_handlers.length; i++)
		{
			var func = this.loop_handlers[i];
			func();
		}
	},
	activate_numbers : function (controller)
	{
		var numbers = getElementsByTagAndClass(controller, "*", "number");

		this.controls["numbers"] = [];
		if (numbers.length > 0)
		{
			var self = this;

			for (var i=0; i < numbers.length; i++)
			{
				var oNumber = numbers[i];
				this.controls["numbers"].push(oNumber);
				var _mousedown_handler = function (num)
				{
					return function () {
						self.loop_to(num);
					}
				}
				oNumber.onmousedown = _mousedown_handler(i);
			}
		}
		else
		{// Change the set_active_number func to a noop. Probably better way to do this
			this.set_active_number = DB_Thunder.Base.noop;
		}

	},
	attachEventToClass : function (controller, cls, func)
	{
		var aObjects = getElementsByTagAndClass(controller, "*", cls);
		if (aObjects)
		{
			for (var i=0; i < aObjects.length; i++)
			{
				var obj = aObjects[i];
				obj.onmousedown = func;
			}
		}
		/* Log Start */
		log('attachEventToClass(','#'+controller.id, ','+cls, ','+func,') called',aObjects.length,'times');
		/* Log End */
	},
	activate_controls : function (controller/* DOM obj */)
	{
		if (!controller)
		{
			/* Log Start */
			log("Controls not found",'#'+controller);
			/* Log End */

			this.set_active_number = DB_Thunder.Base.noop;
			return false;
		}
		/* Log Start */
		log("activate_controls(#"+controller.id+")",'this = ',this.contructor);
		/* Log End */

		var tb = DB_Thunder.Base;

		var next = bind(this.next,this);
		var back = bind(this.back,this);
		var stop = bind(this.stop,this);
		var start = bind(this.start,this);

		// Get elements with className number, which represents active articles
		this.activate_numbers(controller);

		var _attachEventToClass = tb.partial(this.attachEventToClass, controller);
		_attachEventToClass("backward", back);
		_attachEventToClass("forward", next);
		_attachEventToClass("stop", stop);
		_attachEventToClass("start", start);
	},
	set_active_number : function (article_index)
	{
		if (typeof(article_index) != 'number')
		{
			article_index = this.view.current_article;
		}
		/* Log Start */
		var debug_string = '';
		for (var k in this.controls)
		{
			debug_string += k + ': ' + this.controls[k];
		}
		log('set_active_number('+article_index+') debug_string = ',debug_string);
		log(this.controls["numbers"].length);
		/* Log End */
		for (var i=0; i < this.controls["numbers"].length; i++)
		{
			var oNumber = this.controls["numbers"][i]
			if (i == article_index)
			{
				log (oNumber.innerHTML);
				addClassName(oNumber,"active");
			}
			else
			{
				removeClassName(oNumber,"active"); 
			}
		}
	}
}

