/**
 * carousel.js
 * PB 13/03/08
 * converts and existing unordered list in to scroll carousel.
 * The scroll it's self is triggered by next and previous buttons
 * which required artwork (110 x 82). All presentational only css
 * is left out.
 *
 * Dependancies:
 * ===============================================================
 * base.js  http://dean.edwards.name/weblog/2006/03/base/
 * event.js http://dean.edwards.name/weblog/2005/10/add-event2/
 */

var Carousel = Base.extend({

    DISTANCE: null,     /* Number, width of the gallery */
    carousel: null,
    list: null,
    uiControls: null,
    uiPrev: null,
    uiNext: null,
    position: null,     /* Number, ref to left hand most visible link */
    
    /**
     * @param   id{String}  id of the ul containing gallery links;
     */
    constructor: function( id ) {
        if( ! document.getElementById ||
            ! document.getElementsByTagName ){
            return false;
        };
        this.position = 3;
        this.DISTANCE = 116;
        this.build( id );
	},
	
	build: function( id ){
	    var text;
	
	    this.carousel = document.getElementById( id );
	    this.carousel.style.overflow = "hidden";
	    this.carousel.style.padding = "88px 0 0 0";
	    
	    this.list = this.carousel.getElementsByTagName("ul")[0];
	    this.list.style.height = "88px";
	    this.list.style.width = "10000px";
	    this.list.style.position = "absolute";
	    this.list.style.top = "0";
	    
	    this.uiControls = document.createElement("div");
        this.uiControls.id = "uiControls";
        this.uiControls.className = "clear";
        this.carousel.appendChild( this.uiControls);
        
        this.uiPrev = document.createElement("a");
        this.uiPrev.id = "uiPrev";
        text = document.createTextNode("Previous");
        this.uiPrev.appendChild(text);
        this.setOpacity(this.uiPrev, 70);
        
        this.uiNext = document.createElement("a");
        this.uiNext.id = "uiNext";
        text = document.createTextNode("Next");
        this.uiNext.appendChild(text);
        
        this.uiControls.appendChild( this.uiPrev );
        this.uiControls.appendChild( this.uiNext );

        addEvent( this.uiPrev, "click", this.fire(this, this.initialize) );
        addEvent( this.uiNext, "click", this.fire(this, this.initialize) );
	},
	
	/**
	 * All carsousel events are handled by fire(), no error 
	 * handling, probably should impliment this;
     * @param   callee{Object}      context to run the callback in;
     * @param   func{Object}        callback to run when event fires;
     * "return  closure providing    ref to current object;
     */
	fire: function( callee, func ){
	   return function( e ){
	        var id = ( e.target || 
	            e.srcElement).id.toLowerCase();
	   		func.call( callee, id );
	   		return stopDefault(e);
	   };
	},
	
	initialize: function( id ){
           var button, currX, finalX;
           button = this.getButton( id );
           if( ! this.isButtonActive( button ) ){
                this.setOpacity( button, 70 );
                return false;
           }
           this.setOpacity(this.uiPrev, 100);
           this.setOpacity(this.uiNext, 100);
           this.setPosition( button );
           
           currX = parseInt(this.list.style.left || "0px");
           finalX = ( button == this.uiNext ) ?
               currX - this.DISTANCE :
               currX + this.DISTANCE;

           this.animate(this.list, currX, finalX, 0.1, 20);
	},
	
	getButton: function( id ){
	    return (id.indexOf("next")!== -1) ? 
	        this.uiNext : this.uiPrev;
	},
	
	setPosition: function( button ){
       var anchors = this.list.getElementsByTagName("a");
       var count = anchors.length;
       if( button == this.uiNext ){
           this.position = ( this.position >= count ) ? 
                count : this.position += 1;
       }else{
           this.position = ( this.position <= 1 ) ? 
                1 : this.position -= 1;
       };
	},
	
	isButtonActive: function( button ){
       var anchors = this.list.getElementsByTagName("a"),
           count = anchors.length,
           pos = this.position;
       if(  pos == 3 && button == this.uiPrev ){
           return false;
       }else if( pos == count && button == this.uiNext ){
           return false;
       };
       return true;
	},
	
	/**
	 * Animate the carousel. Creates a stack of setTimeout calls
	 * which moves the list element to a percentage of the total 
	 * distance NOT a percentage of the remaining distance;
     * @param   el{HTMLElement}     thie list to animate;
     * @param   currX{Number}       current el.style.left;
     * @param   finalX{Number}      final el.style.left;
     * @param   dur{Number}         length of animation in secs;
     * @param   frames{Number}      number of frame in animation;
     */
    animate: function( el, currX, finalX, dur, frames ){
       var dist;
       for( var i = 0; i <= frames; i++ ){
          (function(){
                // fix i with in the closure;
                var pos = i;
                setTimeout(function(){
                    dist = Math.ceil(( pos / frames ) * (finalX - currX));
                    el.style.left = (currX + dist) + "px";
                }, (pos + 1) * ((1000*dur) / frames) );   
          })();
        };
    },
    
   setOpacity: function( elem, level ){
        // check for IE's filters if not use w3c;
        if( elem.filters ){
            elem.style.filter = 'alpha( opacity = ' + level + ')';
        }else{
            elem.style.opacity = level / 100;
        };
    }
});