﻿/************************************** Splendid *************************************
 * Created By:		Steve Doggett
 * Creation Date:	3rd September 2007
 * Edited ----------------------------------------------------------------------------
 *      By:               On:
 * Description -----------------------------------------------------------------------
 *      This file creates a Carousel
 *      Uses the JQuery plugin (http://code.google.com/p/jqueryjs/downloads/detail?name=jquery-1.1.4.pack.js)
 *
 *      Carousel:
 *          init:  // Initialises the elements needed for the carousel
 *              createCarouselElement( obj )
 *              setInitPositions()
 *              applyActions( idx, action )
 *          scrollLeft:  // Scrolls the carousel left
 *          
 *          scrollRight:  // Scrolls the carousel right
 *
 *          animateScroll:  // Does the animation for each carousel element (used internally really)
 *
 *          scrollTo: // Scrolls through to a particular image
 *
 *          ScrollBy: // Scrolls in a given direction by the given number of images
 *
 *          animationCompleted: // Event handler to deal with animations completing
 *
 *      Array.prototype: // Some array handling to make push/pop/clear cross browser
 *          carClear()
 *          carPush()
 *          carPop()
 *      
 **************************************************************************************/

/****
 * The Carousel object
 * 
 * numShown: The number of images to show in the carousel. usually an odd number (3 each side and one in middle, for example)
 * imgOffset: The offset used for the image on either side of the front image. The rest of them are scaled appropriately
 * imgWidth: The width of the images in the carousel
 * imgHeight: The height of the images in the carousel
 ****/
var Carousel = {
    numShown: 7,
    imgOffset: 122,
    imgWidth: 145,
    imgHeight: 185,
    
    animating: 0,
    containerHeight: 0,
    containerWidth: 0,
    containerID: '',
    arrVisible: null,
    arrActions: null,
    arrElements: null,
    arrAnimations: null,
    middleVal: 1,
    startPosition: $('#StartPosNum').html() == "" ? '4': $('#StartPosNum').html(),
    //startPosition: 4,
    
    init: function( container )
    {// Initialises the carousel on the page
        // Set the carousel container variable up.
        //alert(Carousel.startPosition);
        Carousel.containerID = container;
        
        // Initialise the array to store visible element data
        Carousel.arrVisible = new Array(Carousel.numShown);
        
        // Create the outer ul element
        var elemUL = document.createElement('ul');
        elemUL.setAttribute('id', 'ul_Carousel');
        
        
        
        // Go set the container height/woidth
        Carousel.containerHeight = $('#'+Carousel.containerID).height();
        Carousel.containerWidth = $('#'+Carousel.containerID).width();

        // Now add that lot into the page...
        document.getElementById(Carousel.containerID).appendChild(elemUL);
        // And show the ul, it is hidden by default in the css
        $('#ul_Carousel').show();
        
        // Now go and create the inner elements needed for this.
        for( var i=0; i<arrCarousel.length; i++)
        {
            elemUL.appendChild(createCarouselElement(arrCarousel[i], i) );
            
        }
        
        // Now need to set everything to it's initial positions
        
        setInitPositions();
        
        // Initialise the animations array
        Carousel.arrAnimations = new Array();
       
        // Set it to start in the middle somewhere...
        Carousel.scrollBy( Carousel.startPosition, 'left' );
        
    /******************** Init Functions ********************/
        /****
         * Creates a single carousel element
         ****/
        function createCarouselElement( obj, idx )
        {
            // Create the image elemtns
            var elemImg = document.createElement('img');
            elemImg.setAttribute('src', obj.image.src);
            elemImg.setAttribute('alt', obj.image.alt);
            elemImg.setAttribute('id', 'carImg'+idx);
            
            // Create the link element
            var elemA = document.createElement('a');
            elemA.setAttribute('href', obj.href);
            
            // Create the li element
            var elemLI = document.createElement('li');
            var id = 'carLi'+idx;
            elemLI.setAttribute('id', id);
            
            // Now put it all together
            elemA.appendChild(elemImg);
            elemLI.appendChild(elemA);

           // elemLI.setAttribute('style', 'width:150px; height:150px; display: block;');

            //$('#'+id).show();
            return elemLI;
        } // createCarouselElement
        
        /****
         * Initialises the carousel elements to their start positions.
         ****/
        function setInitPositions()
        {
            var currZ = 1000;
            var scale = 0.8;
            var currWidth = Carousel.imgWidth;
            var currHeight = Carousel.imgHeight;
            var centerLeft = Math.floor( ( Carousel.containerWidth/2 )-( Carousel.imgWidth/2 ) );
            var currLeft = centerLeft;
            var currLeftReflect = 0;
            var opacity = 1;
            var i = 0;
            var numToShow = Math.floor(Carousel.numShown/2);
            var arrPos = numToShow;
            var objAction = null;
            var reflectIdx = arrPos;
            // Want to set up an array of actions to apply to each visible element
            Carousel.arrActions = new Array(Carousel.numShown);
            // Grab an array of the newly created elements now to use...



            Carousel.arrElements = document.getElementById('ul_Carousel').getElementsByTagName('li');
            //this fails post jquery 1.1.4?
            //Carousel.arrElements = $('#'+Carousel.containerID+'/ul/li');



            // Loop through and set the elements to their initial state. 
            // Opacity takes care of hiding ones that shouldn't be seen
            for( i=0; i<Carousel.arrElements.length; i++)
            {
                // Add actions to the action array
                objAction = {
                    imgHeight: currHeight,
                    imgWidth: currWidth,
                    zIdx: currZ,
                    liLeft: currLeft,
                    liTop: Math.floor( (Carousel.containerHeight-currHeight)/2 ),
                    opacity: opacity
                };
                  
                applyActions( i, objAction )
                
                // shove the element number into the visible array
                if( arrPos < Carousel.numShown )
                {
                    Carousel.arrActions[arrPos] = objAction;
                    Carousel.arrVisible[arrPos] = i;
                }
                
                // Want top add the reflect action into the action Array too at this point
                if( reflectIdx>=0 && i!=0 )
                {
                    // Want to add in the refection on the other side too...
                    objAction = null;
                    objAction = {
                        imgHeight: currHeight,
                        imgWidth: currWidth,
                        zIdx: currZ,
                        liLeft: currLeftReflect,
                        liTop: Math.floor( (Carousel.containerHeight-currHeight)/2 ),
                        opacity: opacity
                    };
                    Carousel.arrActions[reflectIdx] = objAction;
                }
                

                // Reset values for next loop round
                currZ = currZ-(parseInt(i+1)*100)
                currHeight = Math.ceil(currHeight*scale);
                currWidth = Math.ceil(currWidth*scale);
                opacity = opacity-( 1/( parseInt(Carousel.numShown+1)/2 ) );
                currLeft = Math.floor(currLeft+(Carousel.imgOffset/parseInt(i+1)));
                currLeftReflect = ( Carousel.containerWidth/2 )-( currLeft-( Carousel.containerWidth/2 ) )-currWidth;
                arrPos++;
                reflectIdx--;
                objActions = null;
                
                // The css sets all li elements to be hidden to start with, so show them now they're set right
                document.getElementById('carLi'+i).style.display = 'block';
            }
        } // setInitPositions
        
        /**** 
         * Takes the actions from the action object in the array and applies it to the current elements
         ***/
        function applyActions( idx, action )
        {        

            var li = $('#carLi'+idx);
            li.css('top', action.liTop+'px');
            li.css('left',action.liLeft+'px');
            li.css('z-Index', action.zIdx);
            li.css('opacity', action.opacity );

            var img = $('img', li)[0];
            img.height = action.imgHeight;
            img.width = action.imgWidth;
        }         
    },
    
    scrollLeft: function()
    {
        var i = 0;
        var tmpArray = new Array(Carousel.numShown);
        var centreOfArray = Math.floor(Carousel.numShown/2);
        var loopCounter = 1;
        var node = null;
        
        // Update the visible array values to what we want it to be, 
        // ie. move to the left and add the new one onto the end 
        for( i=0; i<Carousel.numShown; i++)
        {
            tmpArray[i] = Carousel.arrVisible[i+1];
        }

        // Now need to fill in the last space in the array with the next carousel element
        if( parseInt(Carousel.arrVisible[Carousel.arrVisible.length-1]) < parseInt(Carousel.arrElements.length-1) )
            tmpArray[tmpArray.length-1] = parseInt(Carousel.arrVisible[Carousel.arrVisible.length-1]+1);
        else if( parseInt(Carousel.arrVisible[Carousel.arrVisible.length-1]) == parseInt(Carousel.arrElements.length-1) )
            tmpArray[tmpArray.length-1] = 0;

        // Don't want to scroll past the centre point
        if( parseInt(tmpArray[Math.floor(Carousel.numShown/2)]) < parseInt(Carousel.arrElements.length) )
        {
            // Copy the tmp array back to the global one...
            Carousel.arrVisible = tmpArray;

            // reset the middle val
            Carousel.middleVal = Carousel.arrVisible[Math.floor(Carousel.numShown/2)];
                
            // Cycle through all the carousel elements set their height, width, position and opacity
            for( i=0; i<Carousel.arrVisible.length; i++ )
            {
                if( Carousel.arrVisible[i] != null )
                {
                    Carousel.animating++; // Counter of the animations going on.
                    Carousel.animateScroll( i, Carousel.arrVisible[i] )
                }
            }
            
            // Need to fade opacity of those that have been shoved off the end...
            for(i=0; i<Carousel.arrVisible[0]; i++)
            {
                $('#carLi'+i).css('opacity', 0);            
            }
        }
    },
    
    scrollRight: function()
    {
        var i = 0;
        var tmpArray = new Array(Carousel.numShown);
        var centreOfArray = Math.floor(Carousel.numShown/2);
        var loopCounter = 1;
        var node = null;
        
        // Update the visible array values to what we want it to be, 
        // ie. move to the left and add the new one onto the end 
        for( i=0; i<Carousel.numShown; i++)
        {
            tmpArray[i] = Carousel.arrVisible[i-1];
        }

        // Now need to fill in the last space in the array with the next carousel element
        if( parseInt(Carousel.arrVisible[0]) > 0 )
            tmpArray[0] = parseInt(Carousel.arrVisible[0]-1);
        else 
            tmpArray[0] = parseInt(Carousel.arrElements.length-1);

        if( parseInt(tmpArray[Math.floor(Carousel.numShown/2)]) > -1 )
        {
            // Copy the tmp array back to the global one...
            Carousel.arrVisible = tmpArray;

            // reset the middle val
            Carousel.middleVal = Carousel.arrVisible[Math.floor(Carousel.numShown/2)];
                
            // Cycle through all the carousel elements set their height, width, position and opacity
            for( i=0; i<Carousel.arrVisible.length; i++ )
            {
                if( Carousel.arrVisible[i] != null )
                {
                    Carousel.animating++; // Counter of the animations going on.
                    Carousel.animateScroll( i, Carousel.arrVisible[i] )
                }
            }
            
            // Need to fade opacity of those that have been shoved off the end...
            for(i=Carousel.arrElements.length-1; i>Carousel.arrVisible[Carousel.arrVisible.length-1]; i--)
            {
                $('#carLi'+i).css('opacity', 0);            
            }
        }
    },
    
    animateScroll: function( actionIdx, elemIdx )
    {
        var thisAction = Carousel.arrActions[actionIdx];
        // Change the image dimensions
        $('#carImg'+elemIdx).animate({
                width: thisAction.imgWidth, 
                height: thisAction.imgHeight
            }, 
            { duration: 75 }
        );
        $('#carLi'+elemIdx).css('z-index', thisAction.zIdx);
        // Move the elements
        $('#carLi'+elemIdx).animate({
                left: thisAction.liLeft, 
                top: thisAction.liTop
            }, 
            { duration: 75 }
        ).fadeTo(10, thisAction.opacity, function()
        {
            Carousel.animationCompleted();
        });
    },
    
    scrollTo: function( idx )
    {
        // If there's an animation running, stop it first...
        Carousel.arrAnimations.carClear();
        
        if( parseInt(Carousel.middleVal) > parseInt(idx) )
            Carousel.scrollBy( parseInt(Carousel.middleVal-idx), 'right' );
        else
            Carousel.scrollBy( parseInt(idx-Carousel.middleVal), 'left' );
    },
    
    scrollBy: function( numToMove, dir )
    {
        var i=0;
        
        if( parseInt(numToMove) < Carousel.arrElements.length )
        {
            // Now decide whether need to scroll left or right to get where I'm going...
            if( dir.toLowerCase() == 'right' )
            {
                // Now stick the moves into the animations array.
                // These get triggered when each animation completes
                for( i=1; i<numToMove; i++)
                {
                    Carousel.arrAnimations.carPush('right');
                }
                // Need to trigger the first scroll
                Carousel.scrollRight();
            } else
            {
                // Now stick the moves into the animations array.
                // These get triggered when each animation completes
                for( i=1; i<numToMove; i++)
                {
                    Carousel.arrAnimations.carPush('left');
                }
                // Need to trigger the first scroll
                Carousel.scrollLeft();
            }
        }
    },
    
    animationCompleted: function()
    {
        // the animation has completed, so can decrease the animation counter
        Carousel.animating = parseInt(Carousel.animating-1);
        // Trigger the next animation, if one's in the queue waiting
        if( parseInt(Carousel.animating) == parseInt(0) 
                && Carousel.arrAnimations.length > 0 )
        {
            switch(Carousel.arrAnimations[0].toLowerCase())
            {
                case 'left':
                    Carousel.scrollLeft();
                    break;
                case 'right':
                    Carousel.scrollRight();
            }
            Carousel.arrAnimations.carPop();
        }
    }     
    
}

/*********************************** Extend the Array Object ***********************/
// Want to make sure that the array can do pop/push on all browsers

/****
 * Extend the Array object to give a clear method
 ****/
Array.prototype.carClear = function() 
{
    this.length = 0;
};

/****
 * Extend the Array object to give a method to add stack functionality to Arrays.
 * Same as push functionality, but supported by all browsers
 *
 * element - string, the value to "push"
 */
Array.prototype.carPush = function(element) 
{
    this[this.length] = element;
    return this.length;
};

/****
 * Extend the Array object to give a method to remove stack functionality to Arrays.
 * Same as pop functionality, but supported by all browsers
 ****/
Array.prototype.carPop = function() 
{
	var array = [];
	var i = 0;
	for ( i=0; i<this.length-1; i++) {
		array.push(this[i]);
	}
	this.carClear();
	for ( i=0; i<array.length; i++) {
		this.push(array[i]);
	}
	array = null;
	return this.length;
};
