/**
 * Carousel.js
 * @author Brian Crescimanno <brian.crescimanno@autotrader.com>
 *
 * Creates a thumbnail carousel to be associated with an image viewer component for viewing the full size images
 * represented by the thumbnails.  Also ties to a lightbox component for slideshow capabilities.
 *
 * @requires Prototype >= 1.6.0, Script.aculo.us >= 1.8.0, ATC Component Image Viewer, ATC Component Lightbox Slideshow
 */

if(typeof Prototype == "undefined"){
    throw("Carousel requires the Prototype library");
}

var Carousel = Class.create({

    initialize: function(id, options){
        //Webkit doesn't load effect properly or on time... then use this:  
        if(typeof Effect == "undefined" && !Prototype.Browser.WebKit){
            throw("Carousel requires the Scriptaculous library, with Effects loaded.");
        }
        this.carousel = $(id);
        if(this.carousel == undefined){
            throw("Could not find element: " + id);
        }
        this._extendOptions(options);
        this.viewer = this._createViewer();
        if(this.options.showCount){
            this.countBox = $(id+'-count');
        }
        this.imageSlideBox = this._prepareImageSlideBox();
        this.videoSlideBox = this._prepareVideoSlideBox();

        this._setDefaultSlideBox();
        if(this.slideBox != null){
            this._slideShowSetup();
            this._setPageWidth();
            this._addEventHandlers();
            this._loadCurrent();
            this._checkSlideArrows();
            this._hideOnOne();
        } else {
            $(this.options.imageViewer).update("<p>No Images Found</p>");
        }

        if(this.options.autoStart){
            this.slideShow();
        }

    },

    pauseSlideShow: function(){
        clearTimeout(this._t);
        this.slideshowRunning = false;
        this.startShow.show();
        this.stopShow.hide();
        this.pauseShow.hide();
        this.slideBox.slideShowState = this.slideBox.current.next();
    },

    resumeSlideShow: function(){
        //console.debug("trying to resume")
        var iterator = this._getIndex(this.slideBox.slideShowState);
        this._runSlide(this.slideBox.slideShowState, 3, ++iterator);
        this.startShow.hide();
        this.stopShow.hide();
        this.pauseShow.show();
        this._hideOnOne();
        this.slideshowRunning = true;
        this.slideBox.slideShowState = null;
    },

    slideLeft: function(){
        if(this.slideBox.currentPage == this.slideBox.numPages){
            return false;
        }
        this.slideBox.currentPage++;
        this._slide(-this.pageWidth);
        this._checkSlideArrows();
    },

    slideLeftClick: function(){
        if(this.slideshowRunning){
            this.pauseSlideShow();
        }
        this.slideLeft();
    },

    slideRight: function(){
        if(this.slideBox.currentPage == 1){
            return false;
        }
        this.slideBox.currentPage--;
        this._slide(this.pageWidth);
        this._checkSlideArrows();
    },

    slideRightClick: function(){
        if(this.slideshowRunning){
            this.pauseSlideShow();
        }
        this.slideRight();
    },

    slideShow: function(delay){
        if(this.slideBox.type === "image"){
            if(this.slideBox.slideShowState != null){
                this.resumeSlideShow();
            } else {
                if(!(delay > 0)) delay = 3;
                if(this.slideBox.currentPage > 1) this.slideToOrigin();
                this._runSlide(this.slideBox.thumbnails[0], delay, 1);
                this.startShow.hide();
                this.stopShow.hide();
                this.pauseShow.show();
                this._hideOnOne();
                this.slideshowRunning = true;
            }
        }
    },

    showVideos: function(){
        if(this.slideBox.type != "video" && (this.videoSlideBox != null)){
            this.slideBox = this.videoSlideBox;
            this.stopSlide();
            this._hideOnOne();
            this.imageSlideBox.box.hide();
            this.videoSlideBox.box.show();
            this.startShow.hide();
            this._checkSlideArrows();
            this._loadCurrent();
        }
    },

    showPhotos: function(){
        if(this.slideBox.type != "image" && (this.imageSlideBox != null)){
            this.slideBox = this.imageSlideBox;
            this._hideOnOne();
            this.videoSlideBox.box.hide();
            this.imageSlideBox.box.show();
            this.startShow.show();
            this._checkSlideArrows();
            this._loadCurrent();
        }
    },

    slideToOrigin: function(){
        if(this.slideBox.currentPage>1){
            this._slide((this.pageWidth*(this.slideBox.currentPage-1)));
            this.slideBox.currentPage = 1;
            this._checkSlideArrows();
        }        
    },

    stopSlide: function(){
        clearTimeout(this._t);
        this.slideshowRunning = false;
        this.startShow.show();
        this.stopShow.hide();
        this.pauseShow.hide();
    },

    /* ---------- Begin Private Methods ----------------------------------------------------------------------------- */

    _activate: function(el){
        this.slideBox.current.removeClassName("active");
        el.addClassName("active");
        this.slideBox.current = el;
    },

    _activateMedia: function(el){
        el = el.up();
        var show;
        if(this.slideshowRunning){
            this.pauseSlideShow();
        }
        if(this.slideBox.type == "image"){
            show = function(){
                this.viewer.show(el.href, el.getAttribute('title'));
            }.bind(this);
        } else if(this.slideBox.type == "video"){
            show = function(){
                this.viewer.showVideo(el);
            }.bind(this);
        } else {
            throw("Found an unknown media type.");
        }
        if(el.tagName.toLowerCase() == "a"){
            show();
            this._activate(el.up());
            if(this.options.showCount){
                this._changeCounter(el.up());
            }
        }
    },

    _addEventHandlers: function(){
        this.carousel.previous().observe("click", this.slideRightClick.bind(this));
        this.carousel.next().observe("click", this.slideLeftClick.bind(this));
        this.startShow.observe("click", this.slideShow.bind(this));
        this.stopShow.observe("click", this.stopSlide.bind(this));
        this.pauseShow.observe("click", this.pauseSlideShow.bind(this));
        this.carousel.observe("click", this._carouselClickHandler.bindAsEventListener(this));
        document.observe("viewport:zoomout", this._loadCurrent.bind(this));
        document.observe("viewport:zooming", this.pauseSlideShow.bind(this));
        document.observe("viewport:showphotos", this.showPhotos.bind(this));
        document.observe("viewport:showvideos", this.showVideos.bind(this));
    },

    _carouselClickHandler: function(e){
        var el = e.element();
        if(el.tagName.toLowerCase() == "img"){
            e.stop();
            this._activateMedia(el);
        }
    },

    _changeCounter: function(clicked){
        var text;
        if(this.slideBox.type == "image"){
            text = "Image ";
        } else if(this.slideBox.type == "video"){
            text = "Video ";
        } else {
            throw("Found an unknown media type.");
        }
        for(var i=0; i<this.slideBox.numThumbnails; i++){
            if(clicked == this.slideBox.thumbnails[i]){
                this.countBox.update(text + (i+1) + " of " + this.slideBox.numThumbnails);
            }
        }
    },

    _checkSlideArrows: function(){
        if(this.slideBox.currentPage == 1){
            this.carousel.previous().setStyle({visibility: "hidden"});
        } else {
            this.carousel.previous().setStyle({visibility: "visible"});
        }
        
        if(this.slideBox.currentPage == this.slideBox.numPages){
            this.carousel.next().setStyle({visibility: "hidden"});
        } else {
            this.carousel.next().setStyle({visibility: "visible"});
        }
    },

    _createViewer: function(){
        return new ImageViewer(this.options.imageViewer, this.options.imageViewerOptions);
    },

    _extendOptions: function(options){
        this.options = Object.extend({
            thumbnailsPerPage: 5,
            showCount: false,
            fade: true, // Fade out the row of pages before sliding
            fadeSpeed: 0.3, // Will be automatically set to 0 if fade is false
            speed: 0.6,
            imageViewer: false,
            imageViewerOptions: {},
            startPage: 1,
            fps: 50,
            expandButton: 'viewer-fullview',
            autoStart: false
        }, options || {});

        /* Sanity check */
        if(!this.options.fade){this.options.fadeSpeed = 0;}
    },

    _fadeOut: function() {
        new Effect.Opacity(this.slideBox.box, {
                from: 1.0,
                to: 0.5,
                duration: this.options.fadeSpeed,
                fps: this.options.fps});
    },

    _fadeIn: function() {
        new Effect.Opacity(this.slideBox.box, {
                from: 0.5,
                to: 1.0,
                duration: this.options.fadeSpeed,
                fps: this.options.fps});
    },

    _getIndex: function(el){
        var index = -1;
        this.slideBox.thumbnails.each(function(thumb, i){
            if(el === thumb){
                index = i;
                $break;
            }
        });
        return index;
    },

    _hideMe: function(){
        this.carousel.up().hide();
        if(this.carousel.up().next()){
            this.carousel.up().next().hide();   
        }
    },

    _hideOnOne: function(){
        if(this.slideBox.numThumbnails < 2){
            this._hideMe();
        } else {
            this._showMe();
        }
    },

    _loadCurrent: function(){
        this._activateMedia(this.slideBox.current.down().down());  
    },

    _prepareBox: function(box, type){
        var tn = box.select('li');
        var cnt = tn.length;
        var pages = Math.ceil(cnt / this.options.thumbnailsPerPage);

        return {    box: box,
                    type: type,
                    thumbnails: tn,
                    numThumbnails: cnt,
                    numPages: pages,
                    currentPage: 1,
                    current: tn[0],
                    slideShowState: null};
    },

    _prepareImageSlideBox: function(){
        if(this.carousel.down('.islidebox')){
            return this._prepareBox(this.carousel.down('.islidebox'), "image");
        } else {
            return null;
        }
    },

    _prepareVideoSlideBox: function(){
        if(this.carousel.down('.vslidebox')){
            return this._prepareBox(this.carousel.down('.vslidebox'), "video");
        } else {
            return null;
        }
    },

    _runSlide: function(el, delay, iterator){
        this.viewer.show(el.down().href, el.down().getAttribute("title"));
        this._activate(el);
        if(this.options.showCount){
            this._changeCounter(el);
        }
        if((iterator > 1) && (iterator%this.options.thumbnailsPerPage == 1)){ this.slideLeft(); }
        if(el.next()){
            this.viewer.preloadImage(el.next().down().href);
            this._t = setTimeout(function() {this._runSlide(el.next(), delay, ++iterator); }.bind(this), (delay*1000));
        } else {
            this._t = setTimeout(function(){
                this._activate(this.slideBox.thumbnails[0]);
                this.viewer.show(this.slideBox.thumbnails[0].down().href,this.slideBox.thumbnails[0].down().getAttribute('title'));
                this.slideToOrigin();
                this.stopSlide();
                if(this.options.showCount){
                    this._changeCounter(this.slideBox.thumbnails[0]);
                }
            }.bind(this), (delay*1000));
        }
    },

    _setPageWidth: function(){
        this.pageWidth = (this.slideBox.thumbnails[0].getWidth() + parseInt(this.slideBox.thumbnails[0].getStyle('margin-right'))) *
                         this.options.thumbnailsPerPage;
    },

    _setDefaultSlideBox: function(){
        if(this.imageSlideBox != null){
            this.slideBox = this.imageSlideBox;
        } else if(this.videoSlideBox != null){
            this.slideBox = this.videoSlideBox;
        } else {
            this._hideMe();
            this.slideBox = null;
        }
    },
    
    _showMe: function(){
        this.carousel.up().show();
        this.carousel.up().next().show();
    },

    _slide: function(distance){
        var fadeIn = function(){};
        var fadeOut = function(){};
        if(this.options.fade){
            fadeIn = this._fadeIn.bind(this);
            fadeOut = this._fadeOut.bind(this);
        }

        new Effect.Move(this.slideBox.box, {
            x: distance,
            y: 0,
            mode: 'relative',
            delay: this.options.fadeSpeed,
            duration: this.options.speed,
            fps: this.options.fps,
            afterFinish: fadeIn,
            beforeStart: fadeOut});
    },

    _slideShowSetup: function(){
        this.startShow = this.carousel.next().next();
        this.stopShow = this.startShow.next();
        this.pauseShow = this.stopShow.next();
    }
});