﻿//---------------------------------------------------------------------------------------------------------------------
// Copyright 2007 WonderHowTo, Inc.
// 
// Origional Author:    Bryan Crow
// Last Modified By:    Marat Khoudabakhshiev
// Last Modified:       02/06/2009
// Note: To enable paging, page control links must contain two classes: 
//  1. pageLink + element's id, where element's class is a unique identifier for that particular element that was 
//                              passed in during initialization (this._id)
//  2. scrlPage + page number, where page number corresponds to the order of an element in the scroll list
//---------------------------------------------------------------------------------------------------------------------

// Make sure the wht namespace exists:
YAHOO.namespace('wht');

// Scroller class definition:
YAHOO.wht.Scroller = function($id, $aDelayRange, $iDuration, $bScrollHorizontal, $bAlwaysFade) {
    // Private Member Declarations:
    this._id = $id;
    this._aDelayRange = ($aDelayRange != null) ? $aDelayRange : [3,15]; // min/max in seconds
    this._iDuration = ($iDuration != null) ? $iDuration : 1;
    this._bScroll = ($bAlwaysFade != true);
    this._bHorizontal = ($bScrollHorizontal != null) ? $bScrollHorizontal : false;
    
    
    // Fired once the scroller has loaded & is ready on the page:
    this._onScrollerReady = function() {
        this._oContainer = document.getElementById(this._id);
        this._oContainer.scrollTop = 0;
        this._oContainer.scrollLeft = 0;
        this._aItems = null;
        if (this._bHorizontal) {
            this._aItems = YAHOO.util.Dom.getChildren(YAHOO.util.Dom.getChildren(this._oContainer)[0]);
            // Remove any possible CB elements
            this._aItems = this._removeCBElements(this._aItems);
        } else {
            this._aItems = YAHOO.util.Dom.getChildren(this._oContainer);
        }
        this._iItemCount = this._aItems.length;
        this._iItemHeight = this._aItems[0].offsetHeight;
        this._iItemWidth = this._aItems[0].offsetWidth;
        
        // Assign event handlers to page controls
        this._aPageControls = YAHOO.util.Dom.getElementsByClassName('pageLink' + this._id, 'span');
        
        this._captureEvents(this._aPageControls, 'click', this._onPageControlClick);
        
        // Set width of the outer item holder in the case it's a horizontal scroll
        if (this._bHorizontal) {
            YAHOO.util.Dom.setStyle(YAHOO.util.Dom.getChildren(this._oContainer)[0], 'width', px(this._iItemCount * this._iItemWidth));
        }
        
        if (this._iItemCount > 1) this._setRotationTimeout();
    };
    
    
    // Fired when user clicks a page control link
    this._onPageControlClick = function($oEvent) {
        YAHOO.util.Event.stopEvent($oEvent);
        var oElement = YAHOO.util.Event.getTarget($oEvent);
        if (!YAHOO.util.Dom.hasClass(oElement, 'pageLink' + this._id)) oElement = YAHOO.util.Dom.getAncestorByClassName(oElement, 'pageLink' + this._id);
        
        var iPageNumber = getPrefixedClassValue(oElement, 'scrlPage');
        
        // Scroll to page
        this.scrollTo(iPageNumber);
    };
    
    
    // Removes any "cb" elements from the array and returns a new array
    this._removeCBElements = function($aElements) {
        var aNewElements = new Array();
        
        for (var i = 0; i < $aElements.length; i++) {
            if (!YAHOO.util.Dom.hasClass($aElements[i], 'cb')) {
                aNewElements.push($aElements[i]);
            }
        }
        
        return aNewElements;
    };
    
    
    // Captures the events for all elements in an array:
    this._captureEvents = function($aElements, $sEvent, $fEventHandler) {
        for (var x = 0; x < $aElements.length; x++) {
            YAHOO.util.Event.addListener($aElements[x], $sEvent, $fEventHandler, this, true);
        }
    };
    
    
    // Gets the amount of time to delay before rotating again:
    this._getDelay = function() {
        return (this._aDelayRange.length > 0) ? 
            Number(((Math.random() * (this._aDelayRange[1] - this._aDelayRange[0])) + this._aDelayRange[0]) * 1000) :
            Number(this._aDelayRange[0] * 1000);
    };
    
    
    // Gets a reference to the rotation mode function:
    this._getRotationMode = function() {
        var oScope = this;
        return (this._bScroll) ? 
            function(){oScope.scroll();} : 
            function(){oScope.fadeOut();};
    };
    
    
    // Sets a random timeout to scroll again:
    this._setRotationTimeout = function() {
        this._oContainer.style.display = 'none';
        this._oContainer.style.display = '';
        if (this._itoScroll != null) { clearTimeout(this._itoScroll); this._itoScroll = null; }
        this._itoScroll = setTimeout(this._getRotationMode(), this._getDelay());
    };
    
    
    // Sets the currently displayed page to selected
    this._setSelectedPage = function($iPage) {
        if (this._aPageControls.length == 0) return;
        
        YAHOO.util.Dom.removeClass(this._aPageControls, 'pageLinkSelected');
        YAHOO.util.Dom.removeClass(this._aPageControls, ' pageLinkSelected');
        
        YAHOO.util.Dom.addClass(this._aPageControls[$iPage], ' pageLinkSelected');
    };
    
    
    // Animates the content fading out:
    this.fadeOut = function() {
        // Quick tweak: if in horizontal mode and in IE6 or 8 browser, fly back to the first page
        if (this._bHorizontal & ((YAHOO.env.ua.ie >= 6 && YAHOO.env.ua.ie < 7) || (YAHOO.env.ua.ie >= 8 && YAHOO.env.ua.ie < 9))) {
            this.scrollTo(0);
            return;
        }
        
        var oAnim = new YAHOO.util.Anim(this._oContainer, {opacity: {to: 0}}, this._iDuration / 2, YAHOO.util.Easing.easeIn);
        oAnim.onComplete.subscribe(this.fadeIn, this, true);
        oAnim.animate();
    };
    
    
    // Animates the content fading back in at the right point:
    this.fadeIn = function() {
        if (this._bHorizontal) {
            this._oContainer.scrollLeft = (this._oContainer.scrollLeft < this._iItemWidth * (this._iItemCount - 1)) ? Number(this._oContainer.scrollLeft + this._iItemWidth) : 0;
            this._setSelectedPage(this._oContainer.scrollLeft / this._iItemWidth);
        } else {
            this._oContainer.scrollTop = (this._oContainer.scrollTop < this._iItemHeight * (this._iItemCount - 1)) ? Number(this._oContainer.scrollTop + this._iItemHeight) : 0;
            this._setSelectedPage(this._oContainer.scrollTop / this._iItemHeight);
        }
        
        var oAnim = new YAHOO.util.Anim(this._oContainer, {opacity: {to: 1}}, this._iDuration / 2, YAHOO.util.Easing.easeOut);
        oAnim.onComplete.subscribe(this._setRotationTimeout, this, true);
        oAnim.animate();
    };
    
    
    // Animates the scrolling of the content:
    this.scroll = function() {
        if (this._bHorizontal) {
            if (this._oContainer.scrollLeft >= this._iItemWidth * (this._iItemCount - 1)) {this.fadeOut(); return;}
        } else {
            if (this._oContainer.scrollTop >= this._iItemHeight * (this._iItemCount - 1)) {this.fadeOut(); return;}
        }
        
        var aScrollBy = new Array(2);
        
        if (this._bHorizontal) {
            aScrollBy[0] = this._iItemWidth;
            aScrollBy[1] = 0;
            this._setSelectedPage((this._oContainer.scrollLeft  + this._iItemWidth) / this._iItemWidth);
        } else {
            aScrollBy[0] = 0;
            aScrollBy[1] = this._iItemHeight;
            this._setSelectedPage((this._oContainer.scrollTop + this._iItemHeight) / this._iItemHeight);
        }
        
        var oAnim = new YAHOO.util.Scroll(this._oContainer, {scroll: {by: aScrollBy}}, this._iDuration, YAHOO.util.Easing.easeBoth);
        oAnim.onComplete.subscribe(this._setRotationTimeout, this, true);
        oAnim.animate();
    };
    
    
    // Scrolls to the specified page
    this.scrollTo = function($iPage) {
        var aScrollTo = new Array(2);
        
        if (this._bHorizontal) {
            aScrollTo[0] = this._iItemWidth * $iPage;
            aScrollTo[1] = 0;
        } else {
            aScrollTo[0] = 0;
            aScrollTo[1] = this._iItemHeight * $iPage;
        }
        
        this._setSelectedPage($iPage);
        
        var oAnim = new YAHOO.util.Scroll(this._oContainer, {scroll: {to: aScrollTo}}, this._iDuration, YAHOO.util.Easing.easeBoth);
        oAnim.onComplete.subscribe(this._setRotationTimeout, this, true);
        oAnim.animate();
    };
    
    
    // Try to sign up for custom YUI event that will fire when end of page is reached
    try {
        YAHOO.util.Dom.oWHTReadyEvent.subscribe(this._onScrollerReady, this, true);
    } catch (err) {
        // Attach to the specified container object as soon as it's ready on the page:
        YAHOO.util.Event.onContentReady(this._id, this._onScrollerReady, this, true);
    }
};


// Initializes the scrolling of content for a given container, or array of containers:
YAHOO.wht.Scroller.init = function($id, $aDelayRange, $iDuration, $bScrollHorizontal, $bAlwaysFade) {
    if (!YAHOO.lang.isObject(YAHOO.wht.Scroller.oScrollers)) YAHOO.wht.Scroller.oScrollers = {};
    if (YAHOO.lang.isArray($id)) { for (var i=0; i<$id.length; i++) YAHOO.wht.Scroller.init($id[i]); return; }
    if (YAHOO.lang.isUndefined(YAHOO.wht.Scroller.oScrollers[$id])) {
        YAHOO.wht.Scroller.oScrollers[$id] = new YAHOO.wht.Scroller($id, $aDelayRange, $iDuration, $bScrollHorizontal, $bAlwaysFade);
    }
};
