/**
 * Slide Carousel
 * 
 * Copyright (c) 2009, Jason Gabriele
 * Code licensed under the BSD License:
 * http://developer.yahoo.net/yui/license.txt
 * 
 * Note: This project is not an official YUI extension. It was developed separately for
 * use with the official YUI libraries.
 * 
 * 
 * This is a fancy version of the YUI carousel. It extends the YUI Carousel object
 * so requires it be included before this script is.
 * 
 * @author Jason Gabriele
 * @version 0.1
 */

YAHOO.namespace( 'extension.SlideCarousel' );

(function() {
    var DOM = YAHOO.util.Dom,
        EVENT = YAHOO.util.Event,
        LANG = YAHOO.lang;
                    
    YAHOO.extension.SlideCarousel = function( el, userConfig ) {
        userConfig = userConfig || {};
        
        //Default Settings
        var settings = {
            animation: { speed: 0.5 },
            autoStart: true,
            autoPlay: 5000,
            isCircular: true,
            numVisible: 1,
            selectOnScroll: false,
            previewWidth: 50,
            previewHeight: 50,
            maxPreviews: 5,
            showDescriptions: true
        };
        LANG.augmentObject( settings, userConfig, true );
        
        //Call the superclass constructor
        YAHOO.extension.SlideCarousel.superclass.constructor.call( this, el, settings );
        
        //Set default width and height for preview images
        this._previewWidth = settings.previewWidth;
        this._previewHeight = settings.previewHeight;
        this._maxPreviews = settings.maxPreviews;
        
        this.on( 'render', function(e) {
            //Start Autoplay on render
            if( settings.autoStart && settings.autoPlay > 0 ) this.startAutoPlay();
            
            //Build text dialog
            if( settings.showDescriptions ) {
                this._createDescriptionBox();
                this.on( 'pageChange', this._updateDescriptionBox );
            }
            
            //Rebuild nav menu when changing items
            this.on( 'itemAdded', this._syncPagerUI, [ 1, true ] );
            this.on( 'itemRemoved', this._syncPagerUI, [ 1, true ] );
        });
    };
    
    LANG.extend( YAHOO.extension.SlideCarousel, YAHOO.widget.Carousel, {
        _navMenuBuilt: false,
        _previewWidth: 50,
        _previewHeight: 50,
        _maxPreviews: 5,
        
        /**
         * Create the description box
         */
        _createDescriptionBox: function() {
            var pn = this.get( "currentPage" );
            
            //Create Element
            var db = document.createElement( 'p' );
            db.className = 'yui-carousel-description';
            db.innerHTML = this._getDescription( pn );
            
            this._carouselDescription = db;
            this._clipEl.parentNode.appendChild( db );
        },
        /**
         * Update the description box
         * @param {Int} Page Num
         */
        _updateDescriptionBox: function( page ) {
            page = page || 0;
            this._carouselDescription.innerHTML = this._getDescription( page );
        },
        /**
         * Get the description for a certain page
         * @param {Int} Page Num
         * @return {String} Description
         */
        _getDescription: function( page ) {
            var ol = DOM.getElementsByClassName( 'yui-carousel-element', 'ol', this.get( "element" ) )[0];
            var listItems = ol.getElementsByTagName( 'li' );
            
            //Make sure page exists
            if( !listItems[page] ) return "";
            
            var img = listItems[page].getElementsByTagName( 'img' );
            if( img.length > 0 && img[0].getAttribute( 'alt' ) ) {
                return img[0].getAttribute( 'alt' );
            }
            
            return ""
        },
        /**
         * Override the default method so we can draw the custom html
         * @param {Int} Page Number
         */
        _syncPagerUI: function( page, force ) {
            force = force || false;
            //The following is pulled from the default method
            var numVisible = this.get( "numVisible" );
            page = page || 0;
            var numPages = Math.ceil( this.get( "numItems" ) / numVisible );
            this._pages.num = numPages;
            this._pages.cur = page;
            
            //Adjust pages if max previews is lower
            numPages = Math.min( numPages, this._maxPreviews );
            
            //Iterate through and create 
            if( !this._navMenuBuilt || force ) {
                //Get list items
                var ol = DOM.getElementsByClassName( 'yui-carousel-element', 'ol', this.get( "element" ) )[0];
                var markup = "",
                    listItems = ol.getElementsByTagName( 'li' );
                
                //Iterate through and build image preview menu
                for( var i = 0; i < numPages; i++ ) {
                    if( LANG.isUndefined( this._itemsTable.items[ i * numVisible ] ) ) break;
                   
                    var a = this._itemsTable.items[ i * numVisible ].id;
                    markup += "<li class='" + 
                              ( i === 0 ? this.CLASSES.FIRST_PAGE : "" ) + 
                              ( i == page ? " " + this.CLASSES.SELECTED_NAV : "" ) + 
                              "'><a href='#" + a + "' tabindex='0'>";
                    
                    //Check if the item has a preview image
                    var img = listItems[i].getElementsByTagName( 'img' );
                    if( img.length > 0 && img[0].getAttribute( 'data-preview' ) ) {
                        markup += "<img src='" + img[0].getAttribute( 'data-preview' ) + "' alt='Scroll to item #" + ( i + 1 ) + "' " +
                                  "height='" + this._previewHeight + "' width='" + this._previewWidth + "'>";
                    //Else use the standard markup
                    } else {
                        markup += "<em>" + this.STRINGS.PAGER_PREFIX_TEXT + " " + ( i + 1 ) + "</em>";
                    }
                    markup += "</a></li>";
                }
                
                this._pages.el.innerHTML = markup;
                this._navMenuBuilt = true;
            } else {
                //Simply set item to selected
                for( var i = 0; i < numPages; i++ ) {
                    if( LANG.isUndefined( this._itemsTable.items[ i * numVisible ] ) ) break;
                    
                    //Add selected class
                    if( i === page ) {
                        DOM.addClass( this._pages.el.childNodes[i], 'yui-carousel-nav-page-selected' );
                    } else {
                        DOM.removeClass( this._pages.el.childNodes[i], 'yui-carousel-nav-page-selected' );
                    }
                }
            }
        },
        /**
         * If selectOnScroll is turned off then stop the bloody focus!
         */
        focus: function() {
            if( this.get( 'selectOnScroll' ) ) YAHOO.extension.SlideCarousel.superclass.focus.call( this );
        },
        //Override to fix autoplay functionality
        scrollTo: function( item, dontSelect ) {
            //Reset autoplay to handle bug
            var ap = this.get( 'autoPlay' );
            if( ap > 0 ) {
                this.stopAutoPlay();
                this.set( 'autoPlay', ap );
            }
            YAHOO.extension.SlideCarousel.superclass.scrollTo.call( this, item, dontSelect );
        },
        //Override to prevent double scrollTos
        _setFirstVisible: function( val ) {
            if( val < 0 || val > ( this.get( "numItems" ) - 1 ) ) {
                val = this.get("firstVisible");
            }
            return val;
        },
        //Change to handle clicks from new navigation
        _pagerClickHandler: function( e ) {
            var pos, val;

            var target = EVENT.getTarget( e ).parentNode;
            val = target.href || target.value;
            
            if( LANG.isString( val ) && val ) {
                pos = val.lastIndexOf( "#" );
                if( pos != -1 ) {
                    val = this.getItemPositionById( val.substring( pos + 1 ) );
                    this.scrollTo( val );
                    EVENT.preventDefault( e );
                }
            }
        }
    });
})();