/*!
 * ImageScroller (c) 2009 J.B. van der Burgh
 */

/* If the name of a variable starts with $ than it is an instance of the jQuery object.
 */
var ImageScroller;
(function($) {
    //IS & ImageScroller refer to the same class,
    var IS, defaultOptions = {
        enableImageDrag: false,
        onlyTrackOnload: false
    };

    //define the constructor
    IS = ImageScroller = function(cfg) {
        IS.log("ImageScroller");
        this.cfg = $.extend({}, defaultOptions, cfg);
        //accuracy for floating point percentage, 1 means only integers, 10 means 1 digit, 100 means 2 digits ...
        this.accuracy = 10;
        this.loadingCompleted = false;

        this.$imageContainer = $(this.cfg.container);
        this.$imageContainer.css('cursor', 'wait');

        this.$scroller_under = $(this.cfg.scroller_under);
    };

    //static functions
    IS.log = function(s) {
        // #ifdef DEBUG
        // console.log(s);
        // #endif
    };

    //instance functions
    IS.prototype = {

        cleanup: function() {

            delete this.$viewport;
            delete this.viewportWidth;
            delete this.$imageContainer;

            delete this.scrollbarWidth;
            delete this.$scroller;
            delete this.scrollerWidth;
            delete this.$imgList;
            delete this.imageCount;
        },
        init: function() {
            var that = this;

            $(window).unload(function() {
                //cleanup some stuff on  unload...
                that.cleanup();
            });

            this.$viewport = $(this.cfg.viewport);
            this.viewportWidth = this.$viewport.width();
            this.$imageContainer = $(this.cfg.container);
            this.$imageContainer.css('position', 'absolute').css('cursor', 'wait');

            this.scrollbarWidth = $(this.cfg.scrollbar).width();
            this.$scroller = $(this.cfg.scroller);
            this.scrollerWidth = this.$scroller.width();
            this.$imgList = this.$imageContainer.find('div');
            this.imageCount = this.$imgList.length;
            this.loadedImages = 0;
            this.totalWidth = 0;
            this.imageHeight = 0;
            this.currentPercentage = 0;

            if (!this.cfg.onlyTrackOnload) {
                //check for images to load,
                // we do this so we can use the scroller before the window.onload fires (The window.onload event only fires when all resources (images, scripts, ..) are loaded, and that could take a while.. especially when using google analytics
                this.$imgList.load(function() {
                    that.loadedImages++;

                    // #ifdef DEBUG
                    IS.log('loaded: ' + that.loadedImages + ' / ' + that.imageCount);
                    // #endif

                    if (that.loadedImages >= that.imageCount) {
                        // #ifdef DEBUG
                        IS.log('all images loaded, total width: ' + that.totalWidth);
                        // #endif
                        that.loaded();
                    }
                });
            }
            //also listen to the window.onload just to be sure (it can happen that one or more images fail to fire the load event)
            $(window).load(function() {
                // #ifdef DEBUG
                IS.log('window.onload 1 - imagecount = ' + that.imageCount);
                // #endif

                //update width, to ensure the container uses the correct width haven't used any margins/padding in our calculations
                that.updateContainerWidth();
                if (!that.loadingCompleted) {
                    that.loaded();
                }
            });
        },
        updateContainerWidth: function() {
            this.totalWidth = this.$imageContainer.width() - this.$viewport.width();
        },

        //all images loaded, initialize dragmode
        loaded: function() {
            this.loadingCompleted = true;
            this.updateContainerWidth();
            var that = this;

            this.$imageContainer.css('cursor', 'auto');
            //all images loaded, initialize scrollbar
            //todo: calculate scroller size
            this.$scroller.draggable({
                scroll: false,
                addClasses: false,
                axis: 'x',
                containment: 'parent',
                drag: function(e, ui) {
                    that.drag(e, ui);
                },
                stop: function(e, ui) {
                    that.dragStopped(e, ui);
                }
            });

            if (this.cfg.enableImageDrag) {
                //enable dragging the images to scroll:

                //init image drag
                this.$viewport.mouseleave(function(e) {
                    this.mouseIsDown = false;
                });
                this.$viewport.mouseup(function(e) {
                    this.mouseIsDown = false;

                });
                this.$viewport.mousedown(function(e) {
                    this.mouseIsDown = true;
                    this.mouseX = e.pageX;
                    return false;
                });
                this.$viewport.mousemove(function(e) {
                    if (!this.mouseIsDown) return;
                    var nx = e.pageX;
                    var diff = nx - this.mouseX;
                    if (diff != 0) {
                        this.mouseX = nx;
                        that.scrollBy(diff);
                    }
                    return false;
                });
            }
        },


        scrollLeftBy: function(px) {
            this.scrollBy(Math.abs(px));
        },
        scrollRightBy: function(px) {
            this.scrollBy(-1 * Math.abs(px));
        },
        /**
        * This function changes the 'x' of the container
        * and updates the 'x' of the scrollbar
        */
        //scroll the image container by the specified amount of pixels
        scrollBy: function(px) {


            //calculate container x
            var currentLeft = parseInt(this.$imageContainer.css('left'));
            //check for 'NaN', if we haven't yet scrolled, the css left property is not yet available
            if (isNaN(currentLeft)) currentLeft = 0;
            currentLeft += px;
            var minX = -1 * this.totalWidth;
            var maxX = 0;
            currentLeft = Math.max(minX, Math.min(maxX, currentLeft));

            //update container x
            this.$imageContainer.css('left', currentLeft + 'px');
            this.updateScrollerPosition();

        },
        /** update the scrollbar from the position of the container */
        updateScrollerPosition: function() {

            //calculate container x
            var currentLeft = parseInt(this.$imageContainer.css('left'));
            //check for 'NaN', if we haven't yet scrolled, the css left property is not yet available
            if (isNaN(currentLeft)) currentLeft = 0;
            //calculate scroll percentage:
            var perc = (-1 * (Math.floor((currentLeft / (this.totalWidth / 100)) * this.accuracy) / this.accuracy));
            perc = Math.max(0, Math.min(100, perc));

            //update scroller x
            var scrollbarW = (this.scrollbarWidth - this.scrollerWidth);
            var scrollerX = Math.round((scrollbarW / 100) * perc);
            this.$scroller.css('left', scrollerX + 'px');
            this.$scroller_under.css('left', scrollerX + 'px');
        },
        /** update the container  from the position of the scrollbar*/
        updateContainerPosition: function() {
            //calculate drag
            var scrollerX = parseInt(this.$scroller.css('left'));

            //this.scrollbarWidth
            var w = (this.scrollbarWidth - this.scrollerWidth);
            var perc = Math.floor(scrollerX / (w / 100) * this.accuracy) / this.accuracy;

            //only update the UI if the rounded percentage has changed
            if (this.currentPercentage != perc) {
                // #ifdef DEBUG
                IS.log('' + perc + '%');
                // #endif

                //var containerX = -1 * Math.round(((this.totalWidth - this.viewportWidth) / 100) * perc);
                var containerX = -1 * Math.round(((this.totalWidth) / 100) * perc);

                this.$imageContainer.css('left', containerX + 'px');
            }
            this.updateScrollerPosition();
        },

        /*
        * This function updates the container
        * by using the 'x' of the scrollbar
        */
        drag: function(e, ui) {
            this.updateContainerPosition();
        },
        dragStopped: function(e, ui) {
            // #ifdef DEBUG
            IS.log('drag stopped');
            // #endif

            //reset the cached percentage to force a UI update
            this.currentPercentage = Number.MIN_VALUE;
            this.updateContainerPosition();
        }

    };

})(jQuery);
