var ImageRotator = function(imageRotatorDiv, linkUl, options) 
{	
    var me            = this;
    me._options 	  = options;
    me._width         = options.width;
    me._height        = options.height;
    me._changeTimeout = options.changeTimeout;

    me._imageRotatorDiv = imageRotatorDiv;
    me._imageLinks      = jQuery(linkUl).find("a");

    me._selectedLink = jQuery(linkUl).find(".current a")[0];
    me._paths        = me._getPaths();

    me._currentIndex = options.startIndex != null ? options.startIndex : -1;
    me._playInterval = null;
	    
    (function init() 
    {    	      
        me._imageRotatorDiv.style.position = "relative";
        me._setLinkEvents();
		        
        me._preloadImages(function() 
        {
            me._images = me._getImages(me._paths);
            if (me._images.length > 1)
                me.start(options.startImmediately);
        });
    })();
};

ImageRotator.prototype.getCurrentSlide = function() { return this._currentSlide; };
ImageRotator.prototype.getCurrentIndex = function() { return this._currentIndex; };

ImageRotator.prototype.setSlide = function(index) 
{
    if (index != this._currentIndex)
        this._loadSlide(index);
};

// Stop the ImageRotator. If timeout is not null, stop if for the amount of time
// specified by timeout
ImageRotator.prototype.stop = function(timeout) 
{
    clearInterval(this._playInterval);

    if (timeout)
        setTimeout(this.start, timeout);

    this.playing = false;
};

// Start playing the ImageRotator. Immediately is true if the show should immediately start.
ImageRotator.prototype.start = function(immediately) 
{
    var me = this;
    this._playInterval = setInterval(function() { me._loadNext() }, this._changeTimeout);

    if (immediately)
        this._loadNext(true);

    this.playing = true
};

// Reverses the image links
ImageRotator.prototype._reverseLinks = function() 
{
    var links = [];
    for (var i = this._imageLinks.length - 1; i >= 0; i--)
        links.push(this._imageLinks[i]);

    this._imageLinks = links;
}

ImageRotator.prototype._setLinkEvents = function() 
{
    var me = this;
    for (var i = 0; i < me._imageLinks.length; i++)
        jQuery(me._imageLinks[i]).click((function(index) 
        {
            return function(e) 
            {
            	e.preventDefault();
            	
                me._selectLink(this);

                me.stop();
                me.setSlide(index);
                return false;
            }
        })(i));
};

ImageRotator.prototype._selectLink = function(link) 
{
    if (this._selectedLink)
        jQuery(this._selectedLink.parentNode).removeClass("current");
        
    jQuery(link.parentNode).addClass("current");
    this._selectedLink = link;
}

// Returns an array of image paths
ImageRotator.prototype._getPaths = function() 
{
    var paths = [];
    for (var i = 0; i < this._imageLinks.length; i++)
        paths.push(this._imageLinks[i].href);

    return paths;
}

// Preloads the larger images that haven't been loaded yet
ImageRotator.prototype._preloadImages = function(callback) 
{
    for (var i = 0; i < this._paths.length; i++)
        if (i == 0)
        	this._preloadImage(i, callback);
	    else
	        this._preloadImage(i);
}

ImageRotator.prototype._preloadImage = function(index, callback) 
{		
    var image = new Image();
    image.src = this._paths[index];
	    
	var onloadFunc = function() 
    {    	
        image = null;
        if (callback)
            callback();
    };
    
    if (image.complete)
    	onloadFunc();
    else
    	image.onload = onloadFunc;
}

// Load the next slide
ImageRotator.prototype._loadNext = function(immediately) 
{
    var index = this._getNextIndex();

    this._loadSlide(index, immediately);
    this._selectLink(this._imageLinks[index]);
}

// Load a slide for the index
ImageRotator.prototype._loadSlide = function(index, immediately) 
{
    if (this._currentSlide)
        this._unload(this._currentSlide);

    this._currentIndex = index;
    this._currentSlide = this._getSlide(index);
    this._imageRotatorDiv.appendChild(this._currentSlide);

    if (immediately)
        jQuery(this._currentSlide).show();
    else
        jQuery(this._currentSlide).fadeIn(1000);
}

// Fade the slide out and remove it from the DOM
ImageRotator.prototype._unload = function(slide) { jQuery(slide).fadeOut(1000, function() { jQuery(slide).remove() }); }

// Get the next index that should be displayed (returns to zero)
ImageRotator.prototype._getNextIndex = function() { return this._currentIndex + 1 < this._images.length ? this._currentIndex + 1 : 0; }

// Gets an array of images from an array of image paths	
ImageRotator.prototype._getImages = function(paths) 
{
    var images = [];
    for (var i = 0; i < paths.length; i++)
        images.push(this._getImage(paths[i]));

    return images;
}

// Get an image for the image path
ImageRotator.prototype._getImage = function(path) 
{
    var image    = new Image();
    image.src    = path;

    return image
}

// Get the slide for the index
ImageRotator.prototype._getSlide = function(index) 
{
    var slide             = document.createElement("div");
    slide.style.display  = "none";
    slide.style.height   = this._height + "px";
    slide.style.width    = this._width + "px";
    slide.style.position = "absolute";
    slide.style.top		 = this._options.topOffset || 0;
    slide.style.left	 = this._options.leftOffset || 0;
    slide.style.cursor   = "pointer";
    slide.image          = this._images[index];
    slide.appendChild(slide.image);

    return slide;
}
