/*
 A javascript class that can display a single image along with pagination numbers to move through a gallery.

 Construct:
    SingleLargeImageGallery(paginationSize, flags, galleryEffects);

 Add Image:
    instance.AddImage(url to image);

*/


/* Construct a SingleLargeImageGallery object
 @param paginationSize The size

 @param galleryObjectId = The HTML ID of the div that holds the gallery. This must be a unique ID or else the code might find the wrong gallery.
*/
function SingleLargeImageGallery(galleryObjectId, paginationSize, flags, galleryEffects, slideshowInfo )
{
	// Use this to track which image to show. It's reset back to 0 (the first item) when the page is loaded
    this._galleryObject = document.getElementById(galleryObjectId);
	this._slideshowInfo = slideshowInfo;

	this._index = 0;
	this._paginationSize = paginationSize;
	this._flags = flags;
	this._galleryEffects = galleryEffects;
    this._images = new Array();

// Set some constants
	this._modeSlideshowNone = "none";

	this._effectSwap = 'instant';//0;
	this._effectFade = 'fadeinout'; //1;
	this._effectCrossFade = 'crossfade';//2;

	this._flagHideEnds = 1;
	this._flagNoEnds = 2;
	this._flagWrap = 4;

/* Set the operation mode */
	this._mode = this._slideshowInfo.mode;

/* Set up the id's of the elements that we transition between in slideshow mode */
	this._ids = new Array();
	this._ids.push('vp_single_large_image');
	this._ids.push('vp_single_large_image2');
	this._currentContainer = 0;
}

/* Refreshes the gallery. Call this at least once after you've initialised the instance.
*/
SingleLargeImageGallery.prototype.Refresh = function()
{
    this._SetNavButtonStatus();
    this._SetPaginationContent();

/* If we aren't using crossfading, then we actually hide the second div */
	if ( this._galleryEffects != this._effectCrossFade ) {
		this._GetElement('vp_single_large_image').style.position = "relative";
		this._GetElement('vp_single_large_image2').style.display = "none";
	}

	this.StopSlideshow();

	// Start the slideshow
	if ( this._slideshowInfo.mode != this._modeSlideshowNone ) {
		this.ClickPlayPause();
	}
}

/* Resets the timer, but will only start it again if we are in slideshow mode and currently playing. */
SingleLargeImageGallery.prototype.ResetTimer = function() {
	this._StopTimer();
	if ( this._mode != this._modeSlideshowNone && this._slideshowInfo.playing) {
		this._StartTimer(this._slideshowInfo.delay);
	}
}

SingleLargeImageGallery.prototype.StartSlideshow = function() {
	if ( this._mode == this._modeSlideshowNone ) {
		return;
	}
	this._StartTimer(this._slideshowInfo.delay);
	this._slideshowInfo.playing = true;
}

SingleLargeImageGallery.prototype.StopSlideshow = function() {
	this._StopTimer();
	this._slideshowInfo.playing = false;
}

/* The main slideshow code that moves the slideshow forward */
SingleLargeImageGallery.prototype._SlideshowCallback = function(instance)
{
//	instance._StopTimer();
	instance.ClickNext();
//	instance._StartTimer(instance._slideshowInfo.delay);
}

SingleLargeImageGallery.prototype._StopTimer = function()
{
	clearInterval(this._slideshowInfo.intervalId);
}

SingleLargeImageGallery.prototype._StartTimer = function(delayInSeconds)
{
	var instance = this;
	this._slideshowInfo.intervalId = setInterval( function() { instance._SlideshowCallback(instance); }, delayInSeconds * 1000 );
}

/*
 Stub function to call our method due to 'this' being out of context on the onclick
*/
function CallClick(ob, currentImage)
{
    ob.vpgallery._Click(currentImage);
}

/* Returns the HTML code for a pagination number in the pagination list.
  @param currentImage The index of the image that you want HTML for
  @param visibleImage The index of the image that is currently being displayed
*/
SingleLargeImageGallery.prototype._PaginationNumberCode = function(currentImage, visibleImage)
{
    var span = document.createElement('span');
    span.className = 'vpgallery_pagination_number';
    span.vpgallery = this;
    span.onclick = function() { CallClick(this, currentImage); };

    var font = document.createElement('font');
	if ( currentImage == visibleImage ) {
        font.className = 'vpgallery_pagination_current_number';

        font.appendChild(document.createTextNode((currentImage + 1)));

	} else {
        font.appendChild(document.createTextNode((currentImage + 1)));
    }

    span.appendChild(font);
	return span;
}

/* Sets all the pagination text in the pagination div */
SingleLargeImageGallery.prototype._SetPaginationContent = function()
{
    if ( this._paginationSize == 0 ) {
 		return;
	}

	var currentImage = 0;		// Always try and start from the first image

	// Make sure the currently displayed image's index is in the left pagination group
	if ( this._index >= this._paginationSize ) {
		currentImage = (this._index - this._paginationSize) + 1;
	}

	// Make sure currentImage doesn't get too large or too big
	currentImage = Math.max(Math.min(currentImage, this._ImageCount() - (this._paginationSize * 2)), 0);

    var paginationNode = this._GetElement('vpgallery_pagination');
    while(paginationNode.firstChild) {
        paginationNode.removeChild(paginationNode.firstChild);
    }
	var visibleImage = this._index;
	var html = "";
	var count = 0;
	while( currentImage < this._ImageCount() && count < this._paginationSize ) {
		var newNode = this._PaginationNumberCode(currentImage, visibleImage);

        paginationNode.appendChild(newNode);
		++currentImage;
		++count;
		if (currentImage < this._ImageCount() && count < this._paginationSize) {
            paginationNode.appendChild(document.createTextNode(" "));
		}
	}

	// Do we even need a second half?
	if ( this._ImageCount() - currentImage > 0 ) {

		if ( currentImage < this._ImageCount() - this._paginationSize )
		{
            paginationNode.appendChild(document.createTextNode("..."));
		} else {
            paginationNode.appendChild(document.createTextNode(" "));
		}

		count = 0;
		currentImage = this._ImageCount() - this._paginationSize;
		while( currentImage < this._ImageCount() && count < this._paginationSize ) {
        	var newNode = this._PaginationNumberCode(currentImage, visibleImage);
            paginationNode.appendChild(newNode);
			++currentImage;
			++count;
			if ( currentImage < this._ImageCount() && count < this._paginationSize ) {
                paginationNode.appendChild(document.createTextNode(" "));
			}
		}
	}
}

/* Returns whether we are showing the last image in the gallery
@returns {bool} True = at the last image in the gallery, false = not at last image in the gallery
*/

SingleLargeImageGallery.prototype._AtLastImage = function ()
{
    return  this._index >= this._ImageCount() - 1;
}

/* Returns whether we are showing the first image in the gallery
@returns {bool} True = at the first image in the gallery, false = not at first image in the gallery
*/
SingleLargeImageGallery.prototype._AtFirstImage = function()
{
    return this._index == 0;
}

/* Sets the status of the navigation buttons in the pagination area.
  Will enable or disable the next and previous buttons depending on whether
  the user is at the beginning or end of the list of images.
*/
SingleLargeImageGallery.prototype._SetNavButtonStatus = function()
{
    var enableNext = true;
    var enablePrev = true;

    if ( this._AtLastImage() ) {
        enableNext = false;
    }

    if ( this._AtFirstImage() ) {
        enablePrev = false;
    }

	if ( this._NoEnds() ) {
		enableNext = false;
		enablePrev = false;
	}

    if ( enablePrev ) {
        this._EnableNavButton('vpgallery_prevbutton');
    } else {
        this._DisableNavButton('vpgallery_prevbutton');
    }

    if ( enableNext ) {
        this._EnableNavButton('vpgallery_nextbutton');
    } else {
        this._DisableNavButton('vpgallery_nextbutton');
    }

}

/* Handles clicking of the play/pause button */
SingleLargeImageGallery.prototype.ClickPlayPause = function()
{
		var element = this._GetElement("vpgallery_playpause");
		if ( this._slideshowInfo.playing )
		{
			this.StopSlideshow();
			element.className = "vpgallery_pause";
			element.innerHTML = this._slideshowInfo.playText;
		} else {
			this.StartSlideshow();
			element.className = "vpgallery_play";
			element.innerHTML = this._slideshowInfo.pauseText;
		}
		return false;
}

/* Handles the clicking of the 'next image' button */
SingleLargeImageGallery.prototype.ClickNext = function()
{
	if ( this._inNext ) {
		return;
	}
	this._inNext = true;

    if ( this._AtLastImage() && !this._WrapNavigation() ) {
		this._inNext = false;
        return;
    }

	this._index = (++this._index) % this._images.length;
    this.ShowImage(this._index);
    this._SetNavButtonStatus();
	this._SetPaginationContent();

}

/* Handles the clicking of the 'previous image' button */
SingleLargeImageGallery.prototype.ClickPrev = function()
{
	if ( this._inPrev ) {
		return;
	}
	this._inPrev = true;
    if ( this._AtFirstImage() && !this._WrapNavigation()) {
		this._inPrev = false;
        return;
    }

	this._index = (--this._index) < 0 ? this._images.length - 1 : this._index;
    this.ShowImage(this._index);
    this._SetNavButtonStatus();
	this._SetPaginationContent();
}

/* Handles the clicking of a pagination number. Shows the images that who's number was clicked */
SingleLargeImageGallery.prototype._Click = function(newIndex)
{
	this._index = newIndex;
	this.ShowImage(this._index);
    this._SetNavButtonStatus();
	this._SetPaginationContent();
}

/* Gets an element within this gallery's block
  @param id Id of the element to get
*/
SingleLargeImageGallery.prototype._GetElement = function(id)
{

    var node = this._galleryObject;
    var className = id;
    if ( !this._galleryObject.getElementsByClassName ) {
        if( !node ) {
			node = this._galleryObject.getElementsByTagName("body")[0];
		}
		var a = [];
		var re = new RegExp('\\b' + className + '\\b');
		var els = node.getElementsByTagName("*");
		for(var i = 0, j = els.length; i < j; i++) {
			if( re.test(els[i].className) ){
				a.push(els[i]);
			}
		}
        node = a[0];
    } else {
        node = this._galleryObject.getElementsByClassName(id)[0];
    }

    if ( node == null ) {
        var node = document.getElementById(id);
    }
    return node;
}

/* Disables a navigation button based on the ID of the button
  @param id The HTML id of the item you want to disable (hide)
*/
SingleLargeImageGallery.prototype._DisableNavButton = function(id)
{
    var element = this._GetElement(id);
    if ( element ) {
        element.className = id + ' vp_nav_button_disabled';
		if ( element ) {
			if ( this._HideEnds() ) {					// It's possible the element isn't there
				element.style.visibility = 'hidden';
			} else if ( this._NoEnds() ) {
				element.style.display = 'none';
			}
		}
    }
}

/* Enables a navigation button based on the ID of the button
  @param id The HTML id of the item you want to enable (show)
*/
SingleLargeImageGallery.prototype._EnableNavButton = function (id)
{
    var element = this._GetElement(id);
    if ( element ) {
        element.className = id + ' vp_nav_button_enabled';
		if ( element ) {
			if ( this._HideEnds() ) {
				element.style.visibility = 'visible';
			} else if ( this._NoEnds() ) {
				element.style.display = 'none';
			}
		}
    }
}

SingleLargeImageGallery.prototype.AddImage = function(link)
{
    this._images.push( { url: link, image: null, imageIndex: this._images.length } );
}

/* Shows an image in the main viewer area
  @param imageIndex The index of the image that you want to show
*/
SingleLargeImageGallery.prototype.ShowImage = function(imageIndex)
{
		var img = this._images[imageIndex];

		this._StopTimer();

		if (img.image != null) {
			this._DisplayImage(img);
		} else {
			this._PrefetchImage(img, true);
		}

}

SingleLargeImageGallery.prototype._PrefetchImage = function(image, flag)
{
	var instance = this;
	imageObject = new Image();
	imageObject.onload = function() {
		instance._images[image.imageIndex].image = this;
		instance._DisplayImage(image);
	}
//	image.image = imageObject;
	imageObject.src = image.url;
}


SingleLargeImageGallery.prototype._DisplayImage = function(image)
{
	var fadeOutElement = this._GetElement(this._ids[this._currentContainer]);

    if ( fadeOutElement ) {

		if ( this._galleryEffects ) {

            var instance = this;            // Need to save this for the afterFinish callback

			switch( this._galleryEffects ) {
				case this._effectFade:
					new Effect.Opacity(fadeOutElement, {
							duration: this._slideshowInfo.transitionSpeed / 2 ,
							transition:Effect.Transitions.linear,
							from: 1.0,
							to: 0.01,
							afterFinish:function(effect) {
								fadeOutElement.src = image.url;
								new Effect.Appear( fadeOutElement,
												{
													duration: instance._slideshowInfo.transitionSpeed /2, afterFinish:function(effect) { instance._inNext = false; instance._inPrev = false; instance.ResetTimer(); }
												}
											);
							}
					});
				break;
				case this._effectCrossFade:
					this._currentContainer = (++this._currentContainer) % 2;
					var fadeInElement = this._GetElement(this._ids[this._currentContainer]);
					new Effect.Opacity(fadeOutElement, {
							duration: this._slideshowInfo.transitionSpeed,
							transition:Effect.Transitions.linear,
							from: 1.0,
							to: 0.01
					});
					fadeInElement.src = image.url;
					new Effect.Appear(fadeInElement,
									  {
										duration: this._slideshowInfo.transitionSpeed,
										afterFinish:function(effect) {	instance._inNext = false; instance._inPrev = false; instance.ResetTimer();}
									  }
									);
					break;
				default:
					fadeOutElement.style.display = 'none';
					fadeOutElement.src = image.url;
					fadeOutElement.style.display = 'block';
					this._inNext = false;
					this._inPrev = false;
					this.ResetTimer();
					break;
			}

		} else {
			fadeOutElement.style.display = 'none';
			fadeOutElement.src = image.url;
			fadeOutElement.style.display = 'block';
			this._inNext = false;
			this._inPrev = false;
			this.ResetTimer();
		}

    }

}


/* Returns the number of images managed by this gallery
@returns {array} Number of images
*/
SingleLargeImageGallery.prototype._ImageCount = function()
{
    return this._images.length;
}

SingleLargeImageGallery.prototype._HideEnds = function()
{
	return this._flags & this._flagHideEnds;
}

SingleLargeImageGallery.prototype._NoEnds = function()
{
	return this._flags & this._flagNoEnds;
}

SingleLargeImageGallery.prototype._WrapNavigation = function()
{
	return this._flags & this._flagWrap;
}
