﻿// Carousel related enumerations
var ImageCarouselScrollType = {NoScroll : 0, PreviousNextArrows : 1, Dots : 2, Thumbnails : 3};
var ImageCarouselTransitionType = {None : 0, Fade : 1};

// Create a new image carousel object, initialize the images, and start the carousel
function ImageCarousel(clientId)
{

    // Initialize the object properties
    this.clientId = clientId;
    this.containerDiv = $(clientId + '_ImageCarouselDiv');
    this.transitionDiv = $(clientId + '_ImageCarouselTransitionDiv');
    this.transitionType = parseInt($(clientId + '_hiddenTransitionType').value);
    this.transitionInterval = null;
    this.textDiv = $(clientId + '_ImageCarouselTextDiv');
    this.titleDiv = $(clientId + '_ImageCarouselTitleDiv');
    this.descriptionDiv = $(clientId + '_ImageCarouselDescriptionDiv');
    this.autoScrollDelayMs = parseInt($(clientId + '_hiddenAutoScrollDelayMs').value);
    this.scrollType = parseInt($(clientId + '_hiddenScrollType').value);
    this.imageUrls = eval($(clientId + '_hiddenImageUrlsArray').value);
    this.imageIds = eval($(clientId + '_hiddenImageIdsArray').value);
    this.thumbnailResizeWidth = parseInt($(clientId + '_hiddenThumbnailResizeWidth').value);
    this.thumbnailsPerGroup = parseInt($(clientId + '_hiddenThumbnailsPerGroup').value);
    this.currentImageIndex = -1;
    this.currentThumbnailGroupIndex = -1;
    this.imageTextAndLinkCache = [];
    
     // Initialize the control
    this.preloadCarouselImagesInBrowser();
    this.initializeScrollNavigation();
    this.setImageByIndex(0);
    
    // Attach even handlers
    var _this = this;
    this.containerDiv.onmouseover = function() { _this.clearAutoScrollTimer(); }; // stop auto scrolling when the user hovers over on the current image
    this.containerDiv.onmouseout = function() { _this.restartAutoScrollTimer(); }; // restart auto scrolling when the user's mouse leaves the curretnt image
    
}

// Force the browser to preload the images in the carousel so that scrolling is faster/smoother.
ImageCarousel.prototype.preloadCarouselImagesInBrowser = function()
{
    // Preload the images
    for(var i=0; i < this.imageUrls.length; i++)
    {
        var preload = new Image();
        preload.src = this.imageUrls[i];
    }
}

// Initialize the scroll navigation, if any
ImageCarousel.prototype.initializeScrollNavigation = function()
{
    switch (this.scrollType)
    {
        case ImageCarouselScrollType.PreviousNextArrows : this.initializeArrowScrollNavigation(); break;
        case ImageCarouselScrollType.Dots               : this.initializeDotsScrollNavigation(); break;
        case ImageCarouselScrollType.Thumbnails         : this.initializeThumbnailScrollNavigation(); break;
    }
}

// Initialize the "previous and next arrow" scroll navigation for this control.
ImageCarousel.prototype.initializeArrowScrollNavigation = function()
{
    var _this = this;
    this.previousDiv = document.getElementById(this.clientId + '_ImageCarouselPreviousDiv');
    this.nextDiv = document.getElementById(this.clientId + '_ImageCarouselNextDiv');
    this.previousDiv.onclick = function() { _this.previousDivClicked(true); };
    this.nextDiv.onclick = function() { _this.nextDivClicked(true); };
}

// Initialize the "dots" scroll navigation for this control.
ImageCarousel.prototype.initializeDotsScrollNavigation = function()
{
    if (this.imageUrls.length > 1)
    {
        var _this = this;
        var dotsDiv = document.getElementById(this.clientId + '_ImageCarouselDotsDiv');
        this.dotsArray = new Array();
        for (var i=0; i < this.imageUrls.length; i++)
        {
            var newDot = document.createElement('div');
            newDot.imageIndex = i;
            newDot.className = 'image-carousel-dot';
            newDot.onclick = function() { _this.dotClicked(this); };
            dotsDiv.appendChild(newDot);
            this.dotsArray[i] = newDot;
        }   
    }
}

// Initialize the "thumbnail" scroll navigation for this control.
ImageCarousel.prototype.initializeThumbnailScrollNavigation = function()
{
    var _this = this;
    this.previousDiv = document.getElementById(this.clientId + '_ImageCarouselThumbnailPreviousDiv');
    this.nextDiv = document.getElementById(this.clientId + '_ImageCarouselThumbnailNextDiv');
    this.previousDiv.onclick = function() { _this.previousDivClicked(false); };
    this.nextDiv.onclick = function() { _this.nextDivClicked(false); };
    this.thumbnailImagesDiv = document.getElementById(this.clientId + '_ImageCarouselThumbnailImagesDiv');
    // Create the image tags for the thumbnail images, which will be hidden for now
    var thumbnailCount = this.thumbnailsPerGroup;
    for (var thumbnailIndex=0; thumbnailIndex<thumbnailCount; thumbnailIndex++)
    {
        this.thumbnailImagesDiv.appendChild(this.createThumbnailImageTag(thumbnailIndex));    
    }
    this.currentlySelectedThumbnailImage = null;
}

// Create an image tag setup for use as a Thumbnail image for scroll navigation
ImageCarousel.prototype.createThumbnailImageTag = function(index)
{
    var thumbnailImg = document.createElement('img');
    thumbnailImg.className = 'image-carousel-thumbnail-img';
    thumbnailImg.id = this.getThumbnailImageTagId(index);
    thumbnailImg.style.visibility = 'hidden';
    return thumbnailImg;
}

// Return the Html id of the thumbnail image with the specified index
ImageCarousel.prototype.getThumbnailImageTagId = function(index)
{
    return this.clientId + '_thumbnail_image_' + index.toString();
}

// Set the current image by the index of the image (within the imageUrls array)
ImageCarousel.prototype.setImageByIndex = function(newIndex)
{
    // Ensure the new index is valid before proceeding
    if (this.isValidImageIndex(newIndex))
    {
        // Save the current index
        var oldIndex = this.currentImageIndex;
        // Restart the auto scrolling
        this.restartAutoScrollTimer();
        // Get the title, description, and link for the new image, and update the presentation
        this.loadTextAndLinkForImage(this.imageIds[newIndex]);
        // Update the currently selected image, applying the image transition, if any
        this.transitionImages(this.imageUrls[oldIndex], this.imageUrls[newIndex]);
        // Update the scroll navigation, if any
        this.currentImageIndex = newIndex;
        this.updateScrollNavigation(oldIndex);
    }
}

// Apply the transition for this image carousel to the specified images.
ImageCarousel.prototype.transitionImages = function(oldImageUrl, newImageUrl)
{
    // Stop any previous transition animation
    this.clearTransitionInterval();
    
    // Apply the appropriate transition
    if (this.transitionType == ImageCarouselTransitionType.None || !oldImageUrl || oldImageUrl == undefined || oldImageUrl == '')
    {
        this.containerDiv.style.backgroundImage = 'url(' + newImageUrl + ')';
    }
    else if (this.transitionType == ImageCarouselTransitionType.Fade)
    {
        this.startFadeTransition(newImageUrl);
    }
}

// Clear the transition interval, if any, associated with this image carousel
ImageCarousel.prototype.clearTransitionInterval = function()
{
    if (this.transitionInterval)
    {
        clearInterval(this.transitionInterval);
        this.transitionInterval = null;
    }
}

// Start the "Fade" animation
ImageCarousel.prototype.startFadeTransition = function(fadeToImageUrl)
{
    // Initially the next image is completely transparent
    this.fadeTransitionOpacity = 0.0; 
    setElementOpacity(this.transitionDiv, this.fadeTransitionOpacity);
    // Show the next image in the transition div
    this.transitionDiv.style.backgroundImage = 'url(' + fadeToImageUrl + ')';
    this.transitionDiv.style.display = 'block';
    // Start the fading ...
    var _this = this;
    this.transitionInterval = setInterval(function() { _this.updateFadeTransition(); }, 30);
}

// Update the currently animating "Fade" transition animation
ImageCarousel.prototype.updateFadeTransition = function()
{
    // Still fading?
    if (this.fadeTransitionOpacity < 1.0)
    {
        // Fade-in 1 more step
        this.fadeTransitionOpacity = this.fadeTransitionOpacity + 0.09;
        this.fadeTransitionOpacity = Math.min(this.fadeTransitionOpacity, 1.0);
        setElementOpacity(this.transitionDiv, this.fadeTransitionOpacity);
    }
    else // Done fading
    {
        // Complete the fade transition
        this.clearTransitionInterval();
        this.containerDiv.style.backgroundImage = this.transitionDiv.style.backgroundImage;
        this.transitionDiv.style.display = 'none'; 
    }
}

// Update the presentation of the scroll navigation according to the currently selected image index, and specified "old index"
ImageCarousel.prototype.updateScrollNavigation = function(oldIndex)
{
    if (this.scrollType == ImageCarouselScrollType.PreviousNextArrows) 
    {
        // Show or hide the appropriate arrow images
        this.previousDiv.style.visibility = (this.currentImageIndex==0)?'hidden':'visible';
        this.nextDiv.style.visibility = (this.currentImageIndex==this.imageUrls.length-1)?'hidden':'visible';
    }
    else if (this.scrollType == ImageCarouselScrollType.Dots)
    {
        // Update the dot images accordingly
        if (this.imageUrls.length > 1)
        {
            if (this.isValidImageIndex(oldIndex))
            {
                this.dotsArray[oldIndex].className = 'image-carousel-dot';
            }
            this.dotsArray[this.currentImageIndex].className = 'image-carousel-dot-selected';
        }
    }
    else if (this.scrollType == ImageCarouselScrollType.Thumbnails)
    {
        // Ensure that we are on the correct thumbnail group for the current image, and move to the correct group if not
        var currentImageThumbnailGroupIndex = this.getThumbnailGroupIndexForImageIndex(this.currentImageIndex);
        this.setThumbnailGroupIndex(currentImageThumbnailGroupIndex);
        this.updateSelectedThumbnailCss();
    }
}

// Set the group index to the new index, and update the presentation by loading the images for the new group
ImageCarousel.prototype.setThumbnailGroupIndex = function(newGroupIndex)
{
    // Only proceed if the new group is different from the currently loaded group.
    if (this.currentThumbnailGroupIndex != newGroupIndex)
    {
        // *** Load the thumbnail images for the current group
        var imageIndexForThumbnail = newGroupIndex * this.thumbnailsPerGroup; // the index of the first image in the group
        var thumbnailCount = this.thumbnailsPerGroup;
        var resizeQueryString = '?width=' + this.thumbnailResizeWidth.toString();
        var _this = this;
        for (var thumbnailIndex = 0; thumbnailIndex < thumbnailCount; thumbnailIndex++)
        {
            var thumbnailImg = document.getElementById(this.getThumbnailImageTagId(thumbnailIndex));
            if (this.isValidImageIndex(imageIndexForThumbnail))
            {
                thumbnailImg.src = this.imageUrls[imageIndexForThumbnail] + resizeQueryString;
                thumbnailImg.style.visibility = 'visible';
                this.attachOnclickHandlerToThumbnail(thumbnailImg, imageIndexForThumbnail);
            }
            else
            {
                thumbnailImg.src = '';
                thumbnailImg.style.visibility = 'hidden';
                thumbnailImg.onclick = function() {};
            }
            thumbnailImg.className = 'image-carousel-thumbnail-img';
            imageIndexForThumbnail++;
        }
        // Update the thumbnail related properties of this object
        this.currentlySelectedThumbnailImage = null;
        this.currentThumbnailGroupIndex = newGroupIndex;
    }
}

// Attach the appropriate onclick event handler for the specified thumbnail image.
ImageCarousel.prototype.attachOnclickHandlerToThumbnail = function(thumbnailImg, imageIndex)
{
    var _this = this;
    thumbnailImg.onclick = function() { _this.setImageByIndex(imageIndex); };
}

// Update the Css for the currently showing thumbnails, ensuring that only currently selected image is highlighted
ImageCarousel.prototype.updateSelectedThumbnailCss = function()
{
    // Deselect the currently selected thumbnail image, if any
    if (this.currentlySelectedThumbnailImage)
    {
        this.currentlySelectedThumbnailImage.className = 'image-carousel-thumbnail-img';
    }
    // Select the thumbnail image associated with the currently selected image (assumes the group for the currently selected image is already showing)
    var currentImageThumbnailIndex = this.currentImageIndex % this.thumbnailsPerGroup;
    this.currentlySelectedThumbnailImage = document.getElementById(this.getThumbnailImageTagId(currentImageThumbnailIndex));
    this.currentlySelectedThumbnailImage.className = 'image-carousel-thumbnail-selected-img';
}

// Return the thumbnail group index that the specified image belongs to
ImageCarousel.prototype.getThumbnailGroupIndexForImageIndex = function(imageIndex)
{
    // Get the index of the first image in the group that 'imageIndex' belongs to.
    var indexOfFirstImageInGroup = imageIndex - (imageIndex % this.thumbnailsPerGroup);
    return parseInt(indexOfFirstImageInGroup / this.thumbnailsPerGroup);
}

// Load the title and description text for the specified image from the server, and update the presentation
ImageCarousel.prototype.loadTextAndLinkForImage = function(imageId)
{
    // Has the text already been loaded for this image?
    var cachedTextAndLink = this.imageTextAndLinkCache[imageId.toString()];
    if (cachedTextAndLink)
    {
        this.setTextAndLink(cachedTextAndLink);
    }
    else // no entry in cache found : fetch from server, update the cache, and update the presentation
    {
        var _this = this;
        StationWebsites.ImageCarousel.GetCarouselImage(imageId, function(res) { _this.loadTextAndLinkForImageCallback(res); });
    }
}

// Set the title, description, and link according to the specified parameter.
ImageCarousel.prototype.setTextAndLink = function(image)
{
    var showTextDiv = false;
    if (image.Title != '')
    {
        this.titleDiv.innerHTML = image.Title;
        this.titleDiv.style.visibility = 'visible';
        showTextDiv = true
    }
    else
    {
        this.titleDiv.style.visibility = 'hidden';
    }
    if (image.Description != '')
    {
        this.descriptionDiv.innerHTML = image.Description;
        this.descriptionDiv.style.visibility = 'visible';
        showTextDiv = true;
    }
    else
    {
        this.descriptionDiv.style.visibility = 'hidden';
    }
    this.textDiv.style.visibility = showTextDiv?'visible':'hidden';
    
    if (image.LinkUrl != '')
    { 
        var _this = this;
        this.containerDiv.onclick = function() { _this.imageClicked(image.LinkUrl); }; 
        this.containerDiv.style.cursor = 'pointer';  
    }
    else
    {
        this.containerDiv.style.cursor = '';  
        this.containerDiv.onclick = function() {};
    }
}

// Ajax callback for loadTextForImage
ImageCarousel.prototype.loadTextAndLinkForImageCallback = function(res)
{
    if (res && res.value)
    {
        var image = res.value;
        this.setTextAndLink(image);
        this.imageTextAndLinkCache[image.Id.toString()] = image;
    }
}

// Restart the auto scroll timer (i.e. thread) associated with the current image carousel
ImageCarousel.prototype.restartAutoScrollTimer = function()
{
    // Only start auto-scrolling if there are multiple images and the delay is set.
    if (this.imageUrls.length > 1 && this.autoScrollDelayMs > 0)
    {
        // Clear the existing auto scroll timer, if any
        this.clearAutoScrollTimer();
        // Start a new timer for auto scrolling
        var _this = this; // when the timer is fired, "this" will be an event ... _this will be bound to the correct object via closure
        this.autoScrollTimer = setTimeout(function() { _this.autoScroll(); }, this.autoScrollDelayMs);
    }
}

// Auto scroll to the next image in the current image carousel, and schedule the new auto scroll operation
ImageCarousel.prototype.autoScroll = function()
{
    // The timer has now fired : set it to null
    this.autoScrollTimer = null;
    // Last image?
    var newIndex = this.currentImageIndex + 1;
    if (newIndex >= this.imageUrls.length)
    {
        newIndex = 0;
    }
    // Move to the next image
    this.setImageByIndex(newIndex);
}

// Clear the auto scroll timer (if any) and set it to null
ImageCarousel.prototype.clearAutoScrollTimer = function()
{
    // Is there an existing timer to clear? 
    if (this.autoScrollTimer)
    {
        clearTimeout(this.autoScrollTimer);
        this.autoScrollTimer = null;
    }
}

// Called when the "previous" button div is clicked
ImageCarousel.prototype.previousDivClicked = function(stopEventPropagation)
{
    this.lastImageClickWasScroll = stopEventPropagation;
    this.setImageByIndex(this.currentImageIndex-1);
}

// Called when the "next" button div is clicked
ImageCarousel.prototype.nextDivClicked = function(stopEventPropagation)
{
    this.lastImageClickWasScroll = stopEventPropagation;
    this.setImageByIndex(this.currentImageIndex+1);
}

// Called when a particular "dot" scroll navigation button is clicked
ImageCarousel.prototype.dotClicked = function(dotThatWasClicked)
{
    this.restartAutoScrollTimer();
    this.setImageByIndex(dotThatWasClicked.imageIndex);
}

// Called when an image is clicked : navigates to targetUrl unless the click came from an image carousel scroll object.
ImageCarousel.prototype.imageClicked = function(targetUrl)
{
    if (!this.lastImageClickWasScroll && targetUrl != '')
    {
        window.location = targetUrl;
    }
    this.lastImageClickWasScroll = false;
}

// Is the specified image index valid, i.e. does it fall within the bounds of the image url's array?
ImageCarousel.prototype.isValidImageIndex = function(imageIndex)
{
    return (imageIndex >=0) && (imageIndex < this.imageUrls.length);
}
