/*******************************************************************************
 *  CondeNet Document Carousel Version 1
 *  -----------------------------------
 *      Capable of vertical and horizontal movement
 *******************************************************************************/

    function Carousel(args){		
        //Required constructor arguments
        this.containerEl = document.getElementById(args.containerId);
        this.groupSize = args.groupSize;
        this.speed = args.speed;
        this.direction = args.direction;
        this.effectType = args.effectType;
        this.transitionLength = args.transitionLength;

        //Optional constructor arguments
        this.autoScroll = args.autoScroll;
        
        //Internals
        this.slides = new Array( );
        this.numGroups;
        this.activeGroup = 1;
        this.position = 0;
        this.isMoving = false;

        //DOM Elements
        this.slideWrapperEl = this.setSlideWrapperEl( );
        this.slideListEl = this.setSlideListEl( );
        this.prevButtonEl = this.makeControl(Carousel.PREV);
        this.nextButtonEl = this.makeControl(Carousel.NEXT);
        this.init( );
    }
    Carousel.prototype.init = function( ){
        this.setSlides( this.makeSlides( ) );
        this.groupNav = this.createGroupNav();
        this.groupTriggers = this.groupNav.getElementsByTagName('A');
        for(var i=0; i<this.groupTriggers.length; i++){
            var gcontrol = this.groupTriggers[i];
            this.registerControlEvent( gcontrol, "GROUP" );
        }
        this.updateControlDisplay( );
        this.setupLayout( );
        if(this.autoScroll) this.autoScrollInit( );
    }
    Carousel.prototype.getSlides = function(  ){ return this.slides }
    Carousel.prototype.setSlides = function( slides ){ 
        this.slides = slides;
        this.setNumGroups( );
    }
    Carousel.prototype.makeSlides = function( ) {
        var slideEls, slides;
        slides = new Array( );
        slideEls = getElements(null, 'LI', this.slideListEl);
        for(var i=0; i<slideEls.length; i++)
            slides.push( new Slide(slideEls[i], this.effectType) )
        return slides;
    }
    Carousel.prototype.setSlideListEl = function( ){
        var slideListEl = getElements(null, 'UL', this.slideWrapperEl)[0];
        return slideListEl;
    }
    Carousel.prototype.getSlideListEl = function(){return this.slideListEl;}
    Carousel.prototype.setSlideWrapperEl = function( ){return getElements('slideWrapper', 'DIV', this.containerEl)[0]}
    Carousel.prototype.clearSlideWrapperEl = function( ){this.slideWrapperEl. innerHTML = '';}
    Carousel.prototype.setupLayout = function( ){
        switch(this.direction){
            case Carousel.HORIZONTAL:
                this.setSlideListElWidth( this.getSlideListElWidth( ) );
                this.setSlideWrapperElWidth( this.getSlideWrapperElWidth( ) );
                this.setSlideWrapperElHeight(this.getMaxVisibleSlideHeight() );
                break;
            case Carousel.VERTICAL:
                this.setSlideWrapperElHeight( this.getSlideWrapperElHeight( ) );
                break;
        }
    }
    Carousel.prototype.getPosition = function( ){ return this.position; }
    Carousel.prototype.setPosition = function( position ){
        this.position = position;
        var cssDirection = ( this.direction == Carousel.HORIZONTAL ? 'left' : 'top' );
        this.getSlideListEl( ).style[cssDirection] = position + 'px';
    }
    Carousel.prototype.getSlideWidth = function( ){return this.slides[0].getWidth( );}
    Carousel.prototype.getSlideHeight = function( ){return this.slides[0].getHeight( );}
    Carousel.prototype.getMaxVisibleSlideHeight = function(){
        var displayedIndices, max = 0;
        displayedIndices = this.getDisplayedIndices( );
        for(var i=displayedIndices[0]; i<=displayedIndices[1]; i++)
            if(this.slides[i].getHeight( ) > max)
                max = this.slides[i].getHeight( );
        return max;
    }
    Carousel.prototype.getSlideListElWidth = function( ){ return this.slides.length * this.getSlideWidth( ) }
    Carousel.prototype.setSlideListElWidth = function(width){ this.getSlideListEl( ).style.width = width + 'px' }
    Carousel.prototype.getSlideWrapperElWidth = function( ){ return this.getSlideWidth( ) * this.groupSize }
    Carousel.prototype.setSlideWrapperElWidth = function(width){ this.slideWrapperEl.style.width = width + 'px' }
    Carousel.prototype.getSlideWrapperElHeight = function( ){ return this.getSlideHeight( ) * this.groupSize }
    Carousel.prototype.setSlideWrapperElHeight = function(height){ this.slideWrapperEl.style.height = height + 'px' }
    Carousel.prototype.setNumGroups = function( ){ this.numGroups = Math.ceil(this.slides.length/this.groupSize) }
    Carousel.prototype.getDisplayedIndices = function( ){
        var firstDisplayedIndex, lastDisplayedIndex, activeGroupIndex;
        activeGroupIndex = this.activeGroup -1;
        firstDisplayedIndex = activeGroupIndex * this.groupSize;
        lastDisplayedIndex = ( firstDisplayedIndex+this.groupSize-1<this.slides.length ? firstDisplayedIndex+this.groupSize-1 : this.slides.length-1 );
        return new Array(firstDisplayedIndex, lastDisplayedIndex);
    }
    Carousel.prototype.makeControl = function( buttonType ){
        var control = document.createElement('A');
        this.containerEl.appendChild( control );
        this.registerControlEvent( control, buttonType );
        return control;
    }
    Carousel.prototype.createGroupNav = function(){
        var groupNav = document.createElement('DIV');
        groupNav.className = 'group_nav';
        this.containerEl.appendChild(groupNav);        
        for(var i=0; i<this.numGroups; i++){
            var navButton = document.createElement('A');
            navButton.className = 'group_activator';
            navButton.id = this.containerEl.id + '_group_' + (i+1);
            groupNav.appendChild(navButton);
        }
        return groupNav;
    }
    Carousel.prototype.registerControlEvent = function( control, buttonType ){
        var carousel = this;
        if (buttonType =="GROUP")  {
            var clickHandler = carousel.switchGroup;
            control.onclick = function(event){ clickHandler.apply(carousel, arguments); }
        } else {
            var clickHandler = ( buttonType == Carousel.NEXT ? carousel.advance : carousel.retract );
            control.onclick = function( ){ clickHandler.apply(carousel, [1]); }
        }
    }
    Carousel.prototype.updateControlDisplay = function( ){
        for(var i=0; i<this.groupTriggers.length; i++)
            this.groupTriggers[i].className = '';
        this.groupTriggers[this.activeGroup - 1].className = 'active';
        this.prevButtonEl.className = ( this.activeGroup == 1 ? Carousel.PREV_DISABLED : Carousel.PREV);
        this.nextButtonEl.className = ( this.activeGroup == this.numGroups ? Carousel.NEXT_DISABLED : Carousel.NEXT );
    }
    Carousel.prototype.advance = function(numGroupsToScroll){
        if( this.activeGroup == this.numGroups || this.isMoving) return;
        var carousel, currentPosition, destinationPosition, slideWrapperSize, numScroll, cssDirection, clearer;
        currentPosition = this.getPosition( );
        slideWrapperSize = ( this.direction == Carousel.HORIZONTAL ? this.getSlideWrapperElWidth( ) : this.getSlideWrapperElHeight( ) );
        destinationPosition = currentPosition - ( slideWrapperSize * numGroupsToScroll );
        this.activeGroup = this.activeGroup + numGroupsToScroll;
        this.updateControlDisplay( );
        this.isMoving = true;
        if(this.effectType) this.effectStart( );
        carousel = this;
        clearer = setInterval(
            function( ){
                if(currentPosition - carousel.speed >= destinationPosition){
                    currentPosition -= carousel.speed;
                    carousel.setPosition(currentPosition);
                }else{
                    clearInterval(clearer);
                    carousel.setPosition(destinationPosition);
                    carousel.isMoving = false;
                    if(carousel.effectType) carousel.effectEnd( );
                    if(carousel.direction==Carousel.HORIZONTAL) carousel.setSlideWrapperElHeight( carousel.getMaxVisibleSlideHeight( ) );
                }
            }
        ,10);
    }
    Carousel.prototype.retract = function(numGroupsToScroll){    
        if( this.activeGroup == 1 || this.isMoving) return;
        var carousel, currentPosition, destinationPosition, slideWrapperSize, numScroll, cssDirection, clearer;
        currentPosition = this.getPosition( );
        slideWrapperSize = (this.direction == Carousel.HORIZONTAL ? this.getSlideWrapperElWidth( ) : this.getSlideWrapperElHeight( ));
        destinationPosition = currentPosition + (slideWrapperSize * numGroupsToScroll);
        cssDirection = (this.direction == Carousel.HORIZONTAL ? 'left' : 'top');
        this.activeGroup = this.activeGroup - numGroupsToScroll;
        this.updateControlDisplay( );
        this.isMoving = true;
        carousel = this;
        if(this.effectType) this.effectStart( )
        clearer = setInterval(
            function( ){
                if(currentPosition + carousel.speed <= destinationPosition){
                    currentPosition += carousel.speed;
                    carousel.setPosition(currentPosition);
                }else{
                    clearInterval(clearer);
                    carousel.setPosition(destinationPosition);
                    carousel.isMoving = false;
                    if(carousel.effectType) carousel.effectEnd( );
                    if(carousel.direction==Carousel.HORIZONTAL) carousel.setSlideWrapperElHeight( carousel.getMaxVisibleSlideHeight( ) );
                }
            }
        ,10);
    }
    Carousel.prototype.switchGroup = function(event){
    var focusElement = event.currentTarget || event.srcElement;
    var startingGroup = this.activeGroup;
    var destinationGroup = focusElement.id.replace(/\D+/,'');
    var distance = Math.abs(startingGroup - destinationGroup);
    if( distance == 0 ) return;
    var direction = (startingGroup < destinationGroup ? 'advance' : 'retract');
    direction == 'advance' ? this.advance(distance) : this.retract(distance);
    }
    Carousel.prototype.effectStart = function(effectType){this.ghostItems(true);}
    Carousel.prototype.effectEnd = function(effectType){
        var displayedIndices, effectEls, startIndex, endIndex, currentIndex, carousel, clearer, transitionLength;
        transitionLength = this.transitionLength;
        carousel = this;
        displayedIndices = this.getDisplayedIndices( );
        startIndex = displayedIndices[0];
        endIndex = displayedIndices[1];
        currentIndex = startIndex;
        clearer = setInterval(function( ){
                effectEls = carousel.slides[currentIndex].getEffectEls( );
                for(j=0; j<effectEls.length; j++)
                    fadeIn(effectEls[j], 2*j);
                currentIndex++;
                if(currentIndex > endIndex)
                    clearInterval(clearer)
        }, transitionLength);
    }
    Carousel.prototype.ghostItems = function(ghostFlag){
        var state, effectEls;
        state = (ghostFlag ? 0 : 99.9);
        for(var i=0; i<this.slides.length; i++){
            effectEls = this.slides[i].getEffectEls( );
            for(var j=0; j<effectEls.length; j++)
                setCssOpacity(effectEls[j], state);
        }
    }
    Carousel.prototype.autoScrollInit = function( ){
        var carousel, clearer;
        carousel = this;
        clearer = setInterval( function( ){
            if( carousel.slides.length > 0 ){
                carousel.startAutoScroll( );
                clearInterval(clearer);
            }
        }, 500);
    }
    Carousel.prototype.startAutoScroll = function( ){
        var carousel, interval, endMethod; 
        interval = this.autoScroll*1000;
        carousel = this;
        loop = 0;
        endMethod = function( ){carousel.endAutoScroll( ) }
        this.autoScrollClearer = setInterval( function( ){carousel.autoScrollManager( )}, interval);
        if(addEventListener){
            this.prevButtonEl.addEventListener('click', endMethod, false);
            this.nextButtonEl.addEventListener('click', endMethod, false);
        }else if(attachEvent){
            this.prevButtonEl.attachEvent('click', endMethod);
            this.nextButtonEl.attachEvent('click', endMethod);
        }
    }
    Carousel.prototype.autoScrollManager = function( ){
        if(this.activeGroup < this.numGroups && loop == 0) {
            this.advance(1);
        }
        else if(this.activeGroup == this.numGroups && loop == 0) {
            loop = 1;
            this.retract(3);
        }
        else this.endAutoScroll( )
    }
    Carousel.prototype.endAutoScroll = function( ){
        var autoScrollClearer = this.autoScrollClearer;
        if(autoScrollClearer)
            clearInterval(autoScrollClearer);
    }
    Carousel.HORIZONTAL = 1;                                                                              
    Carousel.VERTICAL = 2;
    Carousel.NEXT = 'carouselControlNext';
    Carousel.PREV = 'carouselControlPrevious';
    Carousel.PREV_DISABLED = 'carouselControlPrevious previousDisabled';
    Carousel.NEXT_DISABLED = 'carouselControlNext nextDisabled';
    
/*  Slide
    ------ */
    function Slide( itemEl, hasEffect ){
        this.itemEl = itemEl;
        this.hasEffect = hasEffect;
        this.init( );
    }
    Slide.prototype.init = function(){
        if(this.hasEffect) this.setEffectEls( );
    }
    Slide.prototype.getItemEl = function( ){return this.itemEl;}
    Slide.prototype.getWidth = function( ){return this.itemEl.offsetWidth;}
    Slide.prototype.getHeight = function( ){return this.itemEl.offsetHeight;}
    Slide.prototype.setEffectEls = function(){
        this.imgEl = getElements( null, 'IMG', this.itemEl)[0];
        this.descriptionContainerEl= getElements( 'description', null, this.itemEl )[0];
        this.titleContainerEl = getElements( 'title', null, this.itemEl )[0];
    }
    Slide.prototype.getEffectEls = function( ){return [this.imgEl, this.descriptionContainerEl, this.titleContainerEl]}

/*  Carousel Utility Functions
    -------------------------- */
	function getElements(classname, tagname, root){
		var all, elements, element;
        if(!root) root = document;
		else if (typeof root == "string") root = document.getElementById(root);
		if(!tagname) tagname = "*";
		all = root.getElementsByTagName(tagname);
		if(!classname) return all;
		elements = [];
		for(var i = 0; i < all.length; i++){
			element = all[i];
			if( isMember(element,classname) )
				elements.push(element)
		}
		return elements;
	}
	function isMember(element, classname){
		var classes, whitespace, c; 
        classes = element.className;
		if(!classes) return false;
		if(classes == classname) return true;
		whitespace = /\s+/;
		if (!whitespace.test(classes)) return false;
		c = classes.split(whitespace);
		for(var i = 0; i < c.length; i++)
			if (c[i] == classname) return true;
		return false;
	}
	function fadeIn(fadeElement, fadeSpeed, terminator){
		var fadeSpeed =  fadeSpeed || 9;
		var opacity = 0;
		var clearer = setInterval(function( ){
			setCssOpacity(fadeElement, opacity);
			if(opacity+fadeSpeed < 99) opacity+=fadeSpeed;
			else{ 
				setCssOpacity(fadeElement, 99);
				clearInterval(clearer);
                resetCssOpacity(fadeElement);
                if(terminator) terminator( );
			}
		},10)
	}
	function setCssOpacity(targetedElement, opacity) {
		opacity = (opacity == 100)?99.999:opacity;
		targetedElement.style.filter = "alpha(opacity: "+opacity+")";
		targetedElement.style.opacity = opacity/100;    
	}
    function resetCssOpacity(targetedElement){
        targetedElement.style.filter = "alpha(opacity: '')";
		targetedElement.style.opacity = "";        
    }
