/**
 * @author POP webdev [tw]
 * @version 0.3.3
 * @classDescription A Scroller to move a LIst vertically or horizontally.
 * @lastModified 1/9/2009 [tw]
 * @return {Object}	Returns an new instance.
 * This class depends on Prototype v1.6 and Scriptaculous effects.
 */
/*
TO IMPROVE:
	- add optional hooks into the move effect, either through functions or firing custom events. 
	e.g. fnOnBeforeMove and fnOnAfterMove or scroller:move and scroller:stop
*/

var Scroller = Class.create({
    initialize: function(slideFrame, options) {
        // set options
        this.options = Object.extend({
            initialIndex: 0,
            durationPerSlide: 1,
            orientation: 'horizontal', 	// ['horizontal' | 'vertical']
            restAlignment: 'left', 		// horizontal: [left|center|right], vertical: [top|center|bottom]
            selectOnMove: true, 		// whether or not to "select" a slide when a move or jump method is called.
            selectOnClick: true 		// whether or not to "select" a slide it is clicked.
        }, options || {});

        // construction tasks
        this.slideFrame = $(slideFrame).makePositioned();
        this.slideList = $(slideFrame).down().cleanWhitespace().makePositioned();
        this.slidesAll = this.slideList.childElements() // get some clean list items
        this.slides = this.slidesAll.findAll(function(currentEl){
            return currentEl.down("img");
        }).invoke('cleanWhitespace');
        if (this.slides.length == 0)
            return;       
        
      
        this.slideFrameDim = this.slideFrame.getDimensions();

        // BEGIN horrible ie6 hack to get appropriate slideFrame height (ie6 added overflown elements to height);
        var IE6 = false/*@cc_on || @_jscript_version < 5.7@*/;
        if (IE6) {
            this.slideList.hide();

            this.slideFrameDim = this.slideFrame.getDimensions();
            this.slideList.show();
        }
        // END horrible ie6 hack

        this.currentSlideIndex = this.options.initialIndex; // resting slide
        this.selectedSlideIndex = -1; // user selected slide
        this.moveEffect = null;
        this.isMoving = false;


        // go to the initial index
        this.jumpTo(this.currentSlideIndex, this.options.selectOnMove);

        // optional event handler
        if (this.options.selectOnClick) {
            this.slideList.observe('click', this.__listClick.bindAsEventListener(this));
        }


        /* modified */
        if (this.getSlideCount() == 1) {
            $(slideFrame).next().select("span").invoke("hide");
        }

        this.showHeader(this.options.initialIndex);
    },

    __listClick: function(e) {
        var el = e.element();

        if (el.nodeName == 'UL') {
            return; // user clicked in padding/margin of ul
        }
        if (el.nodeName != 'LI') {
            el = el.up('LI');
        }
        this.setSelectedSlide(el);
    },

    _calculateMoveByX: function(slideIndex) {
        var moveByX = 0;

        var slideListCurrentLeftPos = this.slideList.positionedOffset().left;
       
        var slideCurrentLeftPos = this.slides[slideIndex].positionedOffset().left;
        var slideFrameWidth = this.slideFrameDim.width;
        var slideWidth = this.slides[slideIndex].getWidth();

        // switch on this.options.restAlignment to determine resting place
        switch (this.options.restAlignment) {
            case 'left':
                moveByX = ((slideFrameWidth - slideListCurrentLeftPos) - (slideCurrentLeftPos)) - slideFrameWidth;
                break;
            case 'right':
                moveByX = ((slideFrameWidth - slideCurrentLeftPos) - slideListCurrentLeftPos) - (slideWidth);
                break;
            case 'center':
            default:
                // center (default)
                moveByX = (((slideFrameWidth / 2) - slideCurrentLeftPos) - slideListCurrentLeftPos) - (slideWidth / 2);
                break;
        }
        return Math.round(moveByX);
    },

    _calculateMoveByY: function(slideIndex) {
        var moveByY = 0;

        var slideListCurrentTopPos = this.slideList.positionedOffset().top;
        var slideCurrentTopPos = this.slides[slideIndex].positionedOffset().top;
        var slideFrameHeight = this.slideFrameDim.height;

        var slideHeight = this.slides[slideIndex].getHeight();

        // switch on this.options.restAlignment to determine resting place
        switch (this.options.restAlignment) {
            case 'top':
                moveByY = ((slideFrameHeight - slideListCurrentTopPos) - (slideCurrentTopPos)) - slideFrameHeight;
                break;
            case 'bottom':
                moveByY = ((slideFrameHeight - slideCurrentTopPos) - slideListCurrentTopPos) - (slideHeight);
                break;
            case 'center':
            default:
                // center (default)
                moveByY = (((slideFrameHeight / 2) - slideCurrentTopPos) - slideListCurrentTopPos) - (slideHeight / 2);
                break;
        }
        return Math.round(moveByY);
    },

    // moveToSlide
    moveTo: function(slideIndex) {
        // allow argument to be a slide LI itself
        if (!Object.isNumber(slideIndex) && Object.isElement(slideIndex)) {
            slideIndex = this.slides.indexOf(slideIndex);
        }

        var slideCount = this.getSlideCount();
        if (slideIndex > (slideCount - 1)) { slideIndex = slideCount - 1; } // make sure we're within bounds

        this.stopMoving(); // A.D.D. protection.
        var seconds = Math.abs(this.currentSlideIndex - slideIndex) * this.options.durationPerSlide;
        this.currentSlideIndex = slideIndex;

        if (this.options.selectOnMove) {
            this.setSelectedSlide(slideIndex);
        }

        var effectOptions = {
            //y: moveByY,
            duration: seconds,
            afterFinish: this.stopMoving.bind(this),
            transition: Effect.Transitions.sinoidal,
            fps: 20
        };

        // set the x or y delta in the options depending on orientation
        switch (this.options.orientation) {
            case 'horizontal':
                var moveByX = this._calculateMoveByX(slideIndex);
                effectOptions.x = moveByX;
                break;
            case 'vertical':
                var moveByY = this._calculateMoveByY(slideIndex);
                effectOptions.y = moveByY;
                break;
        }

        this.isMoving = true;
        // all that for this
        this.moveEffect = new Effect.Move(this.slideList, effectOptions);
    },

    moveToNext: function() {
        var nextIndex = this.currentSlideIndex + 1;
        if (nextIndex < this.getSlideCount()) {
            this.moveTo(nextIndex);
        }
        this.showHeader(nextIndex);
     
    },

    moveToPrevious: function() {
      
        var prevIndex = this.currentSlideIndex - 1;
        if (prevIndex >= 0) {
            this.moveTo(prevIndex);
        }
        this.showHeader(prevIndex)
    },

    moveToFirst: function() {
        this.moveTo(0);
    },

    moveToLast: function() {
        this.moveTo(this.getSlideCount() - 1);
    },

    stopMoving: function() {
        if (this.isMoving) {
            this.moveEffect.cancel(); // stops animation wherever it is
        }
        this.isMoving = false;
    },

    jumpTo: function(slideIndex) {
        // allow argument to be a slide LI itself
        if (!Object.isNumber(slideIndex) && Object.isElement(slideIndex)) {
            slideIndex = this.slides.indexOf(slideIndex);
        }

        // stop the animation and go directly to the given index.
        this.currentSlideIndex = slideIndex;

        this.stopMoving();

        switch (this.options.orientation) {
            case 'horizontal':
                this._setLeftPosition(slideIndex);
                break;
            case 'vertical':
                this._setTopPosition(slideIndex);
                break;
        }

        // use optional second argument to skip setSelectedSlide
        var allowSelection = (Object.isUndefined(arguments[1])) ? this.options.selectOnMove : arguments[1];
        if (allowSelection) {
            this.setSelectedSlide(slideIndex);
        }
    },

    _setTopPosition: function(slideIndex) {
        var slideListCurrentTopPos = this.slideList.positionedOffset()[1];
        var slideCurrentTopPos = this.slides[slideIndex].positionedOffset()[1];
        var slideFrameHeight = this.slideFrameDim.height;
        var slideHeight = this.slides[slideIndex].getHeight();

        var topPos = 0;
        switch (this.options.restAlignment) {
            case 'top':
                topPos = -slideCurrentTopPos;
                break;
            case 'bottom':
                topPos = (slideFrameHeight - slideHeight) - (slideCurrentTopPos);
                break;
            case 'center':
            default:
                // center
                topPos = (slideFrameHeight / 2 - slideCurrentTopPos) - (slideHeight / 2);
                break;
        }
        this.slideList.setStyle({ top: topPos + 'px' });
    },

    _setLeftPosition: function(slideIndex) {
        var slideListCurrentLeftPos = this.slideList.positionedOffset()[0];
        var slideCurrentLeftPos = this.slides[slideIndex].positionedOffset()[0];
        var slideFrameWidth = this.slideFrameDim.width;
        var slideWidth = this.slides[slideIndex].getWidth();

        var leftPos = 0;
        switch (this.options.restAlignment) {
            case 'left':
                leftPos = -slideCurrentLeftPos;
                break;
            case 'right':
                leftPos = (slideFrameWidth - slideWidth) - (slideCurrentLeftPos);
                break;
            case 'center':
            default:
                // center
                leftPos = (slideFrameWidth / 2 - slideCurrentLeftPos) - (slideWidth / 2);
                break;
        }
        this.slideList.setStyle({ left: leftPos + 'px' });
    },


    reset: function() {
        this.currentSlideIndex = this.options.initialIndex;
        this.jumpTo(this.currentSlideIndex);
    },

    addSlide: function(elLi, bAddtoBeginning) {
        // add slide to list
        (bAddtoBeginning) ? this.slideList.insert({ top: elLi }) : this.slideList.insert(elLi);
        this.slides = this.slidesAll.findAll(function(currentEl){
            return currentEl.down("img");
        }).invoke('cleanWhitespace');

        if (bAddtoBeginning) {
            // adjust list item indexing
            this.currentSlideIndex++;
            this.selectedSlideIndex++;
            this.jumpTo(this.currentSlideIndex, false);
        }
    },

    removeSlide: function(slideIndex) {
        this.slides[slideIndex].remove();
        this.slides = this.slidesAll.findAll(function(currentEl){
            return currentEl.down("img");
        }).invoke('cleanWhitespace');
        if (this.currentSlideIndex > slideIndex) {
            // adjust list item indexing
            this.currentSlideIndex--;
            this.jumpTo(this.currentSlideIndex);
        }
    },

    sendSlideToEnd: function(slideIndex) {
        this.relocateSlide(slideIndex, this.getSlideCount() - 1);
    },

    sendSlideToBeginning: function(slideIndex) {
        this.relocateSlide(slideIndex, 0);
    },

    // want to be able move from beginning to end, or vice versa
    relocateSlide: function(oldIndex, newIndex) {
        if (newIndex > oldIndex) {
            // ordering slide farther forward
            Element.insert(this.slides[newIndex], { after: this.slides[oldIndex] });
        }
        else {
            // farther back
            Element.insert(this.slides[newIndex], { before: this.slides[oldIndex] });
        }

        this.slides = this.slidesAll.findAll(function(currentEl){
            return currentEl.down("img");
        }).invoke('cleanWhitespace'); // reset indexing.

        // updated the selected index if it was somewhere in the field of change
        var changeRange = (oldIndex > newIndex) ? $R(newIndex, oldIndex) : $R(oldIndex, newIndex);
        if (changeRange.include(this.selectedSlideIndex)) {
            var selSlide = this.findSelectedSlide();
            this.selectedSlideIndex = this.getIndexForSlide(selSlide);
        }
    },

    getSlideCount: function() {
        return this.slides.length;
    },

    getIndexForSlide: function(elSlide) {
        return this.slides.indexOf(elSlide);
    },

    getSlide: function(slideIndex) {
        return this.slides[slideIndex];
    },

    getSelectedSlide: function() {
        return this.slides[this.selectedSlideIndex];
    },

    findSelectedSlide: function() {
        return this.slides.find(function(slide) {
            return slide.hasClassName('selected');
        });
    },

    setSelectedSlide: function(slideIndex) {
        // allow argument to be a slide LI itself
        if (!Object.isNumber(slideIndex) && Object.isElement(slideIndex)) {
            slideIndex = this.slides.indexOf(slideIndex);
        }
        // set the selected class and fire custom event.
        for (var i = 0, len = this.getSlideCount(); i < len; i++) {
            if (i === slideIndex) {
                this.slides[i].addClassName('selected');
                this.selectedSlideIndex = slideIndex;
                this.slideFrame.fire('scroller:slideselected', { slide: this.slides[i], slideIndex: i });
            }
            else {
                this.slides[i].removeClassName('selected');
            }
        }
        return slideIndex; // for future reference
    },
    /* modified */
    showHeader: function(index) {
       
        var text = this.slideFrame.down("li", index).down("h4").innerHTML;
        this.slideFrame.nextSiblings()[0].childElements()[1].update(text);
    },
    
    nextShowHide: function(obj, el){
	    if ((obj.getSlideCount() - 1) == obj.currentSlideIndex) {
		    el.style.display = "none";
	    }
	    else {
		    el.style.display = "block";
	    }
	},
    
    previousShowHide: function(obj, el){
	    if (obj.currentSlideIndex <= 0) {
		    el.addClassName("invisible");
	    }
	    else {
		    el.removeClassName("invisible");
	    }
    }

});

document.observe('dom:loaded', function(){
	//vs = new Scroller($('verticalscroller_frame'), {orientation: 'vertical', durationPerSlide: 0.25, restAlignment: 'top'});

/* sneaking code here for style change related to newsletter page */
/* checks if there is a form attribute on the page with an action to post the newsletters,
if there is, change the callout style*/
 if($$("form[action*='/newsletters.aspx']")[0] || $$("form[action*='/investors.aspx']")[0]){
	$$("div.callout-minor").invoke(

		"removeClassName","callout-minor"

	).invoke("addClassName","callout-minor-gray");
 
 
 }


});


