/*
Copyright (c) 2008, Stephen Gerstacker. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 0.9.1
*/

YAHOO.namespace('Stack');

(function() {
	
	/**
	 * The Carousel class wraps a simple list of images and turns it into
	 * a sliding image carousel.
	 * @namespace YAHOO.Stack
	 * @class Carousel
	 * @constructor
	 * @param {String | HTMLElement} el An element containing the list of images
	 * @param {Object} userConfig The user configurable settings for the carousel
	 */
	 
    YAHOO.Stack.Carousel = function(el, userConfig) { 

        if(el) {
            this.init(el, userConfig);
        }
    };

    var Dom = YAHOO.util.Dom,
        Event = YAHOO.util.Event,
        Anim = YAHOO.util.Anim,
        Carousel = YAHOO.Stack.Carousel;

    Carousel.prototype = {
		
		/**
		 * The container surrounding the carousel
		 * @property element
		 * @private
		 * @type Object
		 */
		element: null,

		/**
		 * The images of the carousel
		 * @property images
		 * @private
		 * @type Array
		 */
        images: null,

		/**
		 * The list items inside of the slider
		 * @property lis
		 * @private
		 * @type Array
		 */
        lis: null,

		/**
		 * The margin between each image
		 * @property margin
		 * @type Integer
		 */
		margin: null,
		
		/**
		 * The Dom object used to advance the carousel forward
		 * @property next
		 * @type String | HTMLElement
		 */
		next: null,
		
		/**
		 * The Dom object used to advance the carousel backward
		 * @property prev
		 * @type String | HTMLElement
		 */
		prev: null,
		
		/**
		 * The list element used to slide the images
		 * @property slider
		 * @private
		 * @type Object
		 */
        slider: null,

		/**
		 * The time it takes to move from one image to the next
		 * @property speed
		 * @type Double
		 */
		speed: null,

		/**
		 * Calculates the size the inner slider needs to be so that the contained images are 
		 * in a straight line.
		 * @private
		 * @method calculateSliderSize
		 */
        calculateSliderSize: function() {
            var slideWidth = 0;

            for (var i = 0; i < this.lis.length; i++) {
				// Add the image to the list
                var li = this.lis[i];
				var img = li.getElementsByTagName('img')[0];
                this.images.push(img);

				// Add the width to the total slider width
				var bound = YAHOO.util.Dom.getRegion(img);
				slideWidth += bound.right - bound.left + this.margin;
                
				// Set the image margin
                Dom.setStyle(img, 'margin-right', this.margin + 'px');
            }

            Dom.setStyle(this.slider, 'width', slideWidth + 'px');
        },
        
		/**
		 * Connects the prev/next buttons that control the carousel.
		 * @private
		 * @method connectButtons
		 */
        connectButtons: function() {
            var me = this;

            if (this.prev) {
				Dom.addClass(this.prev, 'stacks-carousel-button');
                Event.addListener(this.prev, 'click', function() { me.prevImage(); return false; });
            }
            
            if (this.next) {
				Dom.addClass(this.next, 'stacks-carousel-button');
                Event.addListener(this.next, 'click', function() { me.nextImage(); return false; });
            }
        },
        
		/**
		 * Initializes the carousel and adjusts the properties for displaying correctly.
		 * @private
		 * @method init
		 * @param {String | HTMLElement} el An element containing the list of images
		 * @param {Object} userConfig The user configurable settings for the carousel
		 */
        init: function(el, userConfig) {
            // Set up pointers to DOM elements
            this.element = YAHOO.util.Dom.get(el);
            this.slider = this.element.getElementsByTagName('ul')[0];
            this.lis = this.slider.getElementsByTagName('li');
            this.images = [];
            Dom.addClass(this.element, 'stacks-carousel');
            
            // Initialize counters
            this.currentIndex = 0;
            this.currentMargin = 0;
            
            // Set up the rest of the carousel
            this.parseConfig(userConfig);
            this.calculateSliderSize();
            this.connectButtons();
        },

		/**
		 * Moves the carousel to the next image
		 * @method nextImage
		 */
        nextImage: function(evt) {
            if (this.currentIndex == this.images.length - 1) {
                return;
            }
            
            var curImage = this.images[this.currentIndex];
            this.currentMargin -= curImage.width + this.margin;
            
            var anim = new Anim(this.slider, {
                marginLeft: { to: this.currentMargin }
            }, this.speed, YAHOO.util.Easing.easeOut);
            anim.animate();
            
            this.currentIndex++;
        },
        
		/**
		 * Reads the supplied configuration and sets the default properties.
		 * The following options are configurable:
		 * @private
		 * @method parseConfig
		 * @param {Object} userConfig The user configurable settings for the carousel
		 */
        parseConfig: function(userConfig) {
	
			var config = userConfig || {};
			
			this.margin = config.margin || 5;
			this.next = config.next || 'next';
			this.prev = config.prev || 'prev';
			this.speed = config.speed || 0.5;
        },

		/**
		 * Moves the carousel to the previous image
		 * @method prevImage
		 */
        prevImage: function(evt) {
            if (this.currentIndex == 0) {
                return;
            }
            
            var prevImage = this.images[this.currentIndex - 1];
            this.currentMargin += prevImage.width + this.margin;
            
            var anim = new Anim(this.slider, {
                marginLeft: { to: this.currentMargin }
            }, this.speed, YAHOO.util.Easing.easeOut);
            anim.animate();
            
            this.currentIndex--;
        }
    };
}());

YAHOO.register("carousel", YAHOO.Stack.Carousel, { version: "0.9.1" });
