﻿Function.prototype.bind = function(o) {
    /// <summary>binds an object to a function allowing user to define the this value</summary>
    /// <param name="o">object to be used as this</param>
    /// <returns>returns a new function object</returns>
    var t = this;
    return function() { return t.apply(o, arguments); };
};
Function.prototype.delay = function(delay, bind /*, arg1, arg2, ... */) {
    /// <summary>executes a function after a number of milliseconds with a bind object and paramaters =)</summary>
    /// <param name="delay">number of miliseconds to wait before execution</param>
    /// <param name="bind">the this object to be used within the calling function</param>
    /// <returns>returns the timer reference</returns>
    var self = this, timer, args = new Array();
    for (var i = 2, l = arguments.length; i < l; i++) args.push(arguments[i]);
    var func = function() { clearTimeout(timer); self.apply(bind || self, args || []); };
    timer = setTimeout(func, delay);
    return timer;
};
Function.prototype.repeat = function(delay, bind /*, arg1, arg2, ... */) {
    /// <summary>repeatedly executes a function after a number of milliseconds with a bind object and paramaters =)</summary>
    /// <param name="delay">number of miliseconds to wait before execution</param>
    /// <param name="bind">the this object to be used within the calling function</param>
    /// <returns>function containing a clear option</returns>
    var self = this, interval, args = new Array();
    for (var i = 2, l = arguments.length; i < l; i++) args.push(arguments[i]);
    var func = function() { self.apply(bind || self, args || []); };
    interval = setInterval(func, delay);
	return interval;
};

var Carousels = {

	items : new Array(),
	ready : false,
	delay : 3500,

	init : function()
	{
		var aCarousel = support.getElsByAttVal(document,'div','class','carousel');

		for (var i=0; i<aCarousel.length; i++)
		{
			// build all carousels
			Carousels.items[aCarousel[i].id] = Carousels.create(aCarousel[i]);

			// select first item
			Carousels.select(aCarousel[i].id,0);

			// start the carousel
			Carousels.start.repeat(500,null,aCarousel[i].id);
		}
		
		// should only start moving once the page is fully loaded (images etc)
		addLoadEvent(function(){Carousels.ready=true;});
	},
   
   create : function(el)
   {
		this.framePerSecond = 50;
		this.transTime = 300;
		this.view = el;
		this.id = el.id;
		this.loadinterval = null;
		this.interval = null;
		this.frames = support.getElsByAttVal(el,'div','class','frame');
		this.frameW = parseInt(this.frames[0].offsetWidth);
		this.frameH = parseInt(this.frames[0].offsetHeight);
		this.index = 0;
		this.paused = false;
		this.controls = new Array();
       
		if (this.frames.length>0)
		{
			// controls container
			var controlsDiv = support.createEl(el,'div',{'class':'controls'},{'width':this.frameW+'px'});

			// render previous control
			var prev = support.createEl(controlsDiv,'a',{'href':'#','cid':el.id,'class':'prev'},"","«");
				prev.onclick = function()
				{
					Carousels.previous(this.cid);
					return false;
				}

			for (var x=0; x<this.frames.length; x++)
			{
				// build navigation number for each frame
				var a = support.createEl(controlsDiv,'a',{'href':'#','cid':el.id,'num':(x)},"",(x+1));
					a.onclick = function()
					{
						Carousels.select(this.cid, this.num);
						return false;
					}
					
				// add to controls collection
				this.controls.push(a);
				
				// hide all none showing frames
				this.frames[x].style.display = (x===this.index) ? "block":"none";
			}

			// render next control
			var next = support.createEl(controlsDiv,'a',{'href':'#','cid':el.id,'class':'next'},"","»");
				next.onclick = function()
				{
					Carousels.next(this.cid);
					return false;
				}

			// stop on mouse over carousel
			this.view.onmouseover = function()
			{
				Carousels.items[this.id].paused = true;
			}
			
			// restarton mouseout of carousel
			this.view.onmouseout = function()
			{
				Carousels.items[this.id].paused = false;
			}
		}
	   
		return this;
   },

	/* mark current page link as selected */
	select : function(id, num)
	{
		var c = Carousels.items[id];
		if (c)
		{
			for (var x=0; x<c.frames.length; x++)
			{
				// hide all none showing frames
				c.frames[x].style.display = (x==num) ? "block":"none";
				c.controls[x].className = (x==num) ? "active":"";
			}
			c.index=num;
		}
	},
	
	/* moves 1 pane at a time to reveal the next pane */
	shift : function()
	{
		if (!this.paused)
		{
			var n = ((this.index+1)>=this.frames.length) ? 0 : this.index+1;
			Carousels.select(this.id, n);
		}
	},
	
	stop : function(id)
	{
        var c = Carousels.items[id];
        if ((c) && (c.interval))
        {
			window.clearInterval(c.interval);
        }
	},
	
	start : function(id)
	{
		if (Carousels.ready)
		{
			var c = Carousels.items[id];
			if ((c) && (!c.interval))
			{
				if (c.loadinterval) c.loadinterval.clear();
				c.interval = Carousels.shift.repeat(Carousels.delay,c);
			}
		}
	},
	
	/* move to the previous frame */
	previous : function(id)
	{
		var c = Carousels.items[id];
		if (c)
		{
			var n = (c.index-1<0) ? 0 : c.index-1;
			Carousels.select(id, n);
		}
		return false;
	},
   
	/* move to the next frame */
	next : function(id)
	{
		var c = Carousels.items[id];
		if (c)
		{
			var n = (c.index+1>=c.frames.length) ? c.frames.length-1 : c.index+1;
			Carousels.select(id, n);
		}
		return false;
	}
};

if (window.DomLoaded) { DomLoaded.load(Carousels.init)} 