/*  ==========================================================================================================  */
/*  ibSlider v 1.0
/*  ==========================================================================================================  */

    var SlidingBox = Class.create({

        // Don't like the CSS classnames? Change'em here...
        classNames : {
            slider          : 'slider',         //
            slideLeft       : 'slide-left',     //
            slideRight      : 'slide-right',    //
            slideMask       : 'slide-mask',     //
            slideContent    : 'slide-content'   //
        },

        setOptions: function(opt) {
            this.options = {
                infinite: false,
                increments: null,
                duration: 1,
                autoslide: false,
                delay: 3
            };
            Object.extend(this.options, opt || {});
        },

        initialize: function(sbox, opt) {
            // Set the options
            this.setOptions(opt);
            if (this.options.autoslide === true) this.options.infinite = true;

            // set up some vars
            this.slider         = sbox;
            this.container      = this.slider.down('.'+this.classNames.slideContent);
            this.mask           = this.slider.down('.'+this.classNames.slideMask);
            this.item           = this.slider.down('li');
            if (this.item === undefined) return; // if dynamically filled slider has no items
            this.itemCount      = this.slider.select('li').size();
            this.itemWidth      = this.getItemWidth();
            this.increments     = this.getIncrements();
            this.scroll_offset  = this.itemWidth * this.increments;
            this.triggerLeft    = this.slider.down('.'+this.classNames.slideLeft);
            this.triggerRight   = this.slider.down('.'+this.classNames.slideRight);

            this.triggerLeft.style.visibility = 'visible';
            this.triggerRight.style.visibility = 'visible';
            // set up the slide-container width
            this.setSlidingContainer();
            // initially disable triggers, slideLeft always...
            $$('.'+this.classNames.slideLeft).invoke('addClassName', 'inactive');
            // ... and slideRight, if there are too few items in the slider
            if (this.itemCount <= this.increments) {
                $$('.'+this.classNames.slideRight).invoke('addClassName', 'inactive');
            }
            if (this.options.autoslide === true) {
                this.horizontal_slider();
            }
        },

        getItemWidth: function() {
            var itemWidth = (this.item.getWidth()) + (parseInt(this.item.getStyle('margin-right'))) + (parseInt(this.item.getStyle('margin-left')));
            return itemWidth;
        },

        // how many items to move at a time
        getIncrements: function() {
            // Either it's declared by options
            if (this.options.increments !== null) {
                this.increments = this.options.increments;
            // or increment is set to the number of visible items
            } else {
                var maskWidth = this.mask.getWidth();
                this.increments = Math.round(maskWidth / this.itemWidth);
            }
            return this.increments;
        },

        setSlidingContainer: function() {
            var containerWidth  = (this.itemWidth * this.itemCount);
            this.container.setStyle({
                left: 0,
                width: containerWidth + 'px'
            });
            // now, bind event handler to the box
            this.slider.observe('click', this.slideBoxEvents.bindAsEventListener(this));
        },

        // figure out which element was clicked and say what happens next
        slideBoxEvents: function(event) {
            var trigger = event.element();
            if ((trigger.match('.'+this.classNames.slideLeft) || trigger.match('.'+this.classNames.slideRight))) {
                Event.stop(event); // stop default behaviour of trigger element
                if (!trigger.hasClassName('inactive')) {
                    this.horizontal_slider(trigger);
                }
            } else return;
        },

        // Same as slideRight, but separated to run in it's own scope (effect queue)
        autoSlide: function(ctx, trigger, scroll_offset, duration, lastMargin, max_position, maskSize, startOver) {
            var triggerLeft = ctx.triggerLeft;

            if (ctx.options.autoslide) {
                window.clearTimeout(ctx.timeoutId);
            }

            new Effect.Move(ctx.container, {
                x: -(scroll_offset),
                y: 0,
                ctx:ctx,
                mode: 'relative',
                duration: duration,
                queue: {position: 'end', scope: 'autoslide', limit: 1},
                afterFinish: function() {
                    max_position = max_position - scroll_offset - lastMargin;
                    // toggle triggers inactive-state
                    if (max_position <= maskSize) {
                        trigger.addClassName('endpoint');
                    }
                    triggerLeft.removeClassName('inactive');
                    this.ctx.horizontal_slider();
                }
            });
        },

        slideRight: function(trigger, scroll_offset, duration, lastMargin, max_position, maskSize, startOver) {
            var triggerLeft = this.triggerLeft;

            if (this.options.autoslide) {
                window.clearTimeout(this.timeoutId);
            }
            new Effect.Move(this.container, {
                x: -(scroll_offset),
                y: 0,
                ctx:this,
                mode: 'relative',
                duration: duration,
                queue: {position: 'end', scope: 'anims', limit: 1},
                afterFinish: function() {
                    max_position = max_position - scroll_offset - lastMargin;
                    // toggle triggers inactive-state
                    if (max_position <= maskSize) {
                        if (startOver === true) {
                            trigger.addClassName('endpoint')
                        } else {
                            trigger.addClassName('inactive');
                        }
                    }
                    triggerLeft.removeClassName('inactive');
                    if (this.ctx.options.autoslide) {
                        this.ctx.horizontal_slider();
                    }
                }
            });
        },

        slideLeft: function(trigger, scroll_offset, duration) {
            var triggerRight    = this.triggerRight;
            var scroll_target   = this.container;

            if (this.options.autoslide) {
                window.clearTimeout(this.timeoutId);
            }
            new Effect.Move(scroll_target, {
                x: scroll_offset,
                y: 0,
                mode: 'relative',
                duration: duration,
                ctx: this,
                queue: {position: 'end', scope: 'anims', limit: 1},
                afterFinish: function() {
                    actual_position = parseInt(scroll_target.getStyle('left'));
                    // toggle triggers inactive-state
                    if (actual_position >= 0) {
                        trigger.addClassName('inactive');
                    }
                    triggerRight.removeClassName('inactive').removeClassName('endpoint');
                    if (this.ctx.options.autoslide) {
                        this.ctx.horizontal_slider();
                    }
                }
            });
        },

        slideBack: function(duration, ctx) {
            if (ctx == '' || ctx === undefined) {ctx = this;}
            var triggerLeft = ctx.triggerLeft;
            var triggerRight= ctx.triggerRight;
            var auto_slide  = ctx.options.autoslide;

            new Effect.Move(ctx.container, {
                x: 0,
                y: 0,
                ctx:ctx,
                mode: 'absolute',
                duration: duration,
                queue: {position: 'end', scope: 'anims', limit: 1},
                afterFinish: function() {
                    triggerRight.removeClassName('endpoint').removeClassName('inactive');
                    triggerLeft.addClassName('inactive');
                    if (auto_slide === true) {
                        this.ctx.horizontal_slider();
                    }
                }
            });
        },

        horizontal_slider: function(trigger) {
            var maskSize        = this.mask.getWidth();
            var lastMargin      = parseInt(this.item.getStyle('margin-right'));
            var startOver       = this.options.infinite;
            var duration        = this.options.duration;
            var scroll_offset   = this.scroll_offset;
            var actual_position = (Math.abs(parseFloat(this.container.style.left)));
            var max_position    = parseInt(this.container.getStyle('width')) - actual_position;
            var containerWidth  = (this.itemWidth * this.itemCount);
            // auto slide
            if (this.options.autoslide === true && trigger === undefined) {
                var delay   = this.options.delay;
                    ctx     = this;
                if (max_position <= (maskSize + lastMargin)) {
                    slideBack       = this.slideBack;
                    this.timeoutId  = window.setTimeout(function() {slideBack(duration, ctx)}, delay*1000);
                } else {
                    trigger         = this.triggerRight;
                    autoSlide       = this.autoSlide;
                    this.timeoutId  = window.setTimeout(function() {autoSlide(ctx, trigger, scroll_offset, duration, lastMargin, max_position, maskSize, startOver)}, delay*1000);
                }
            }
            // Slide right
            else if (trigger.hasClassName(this.classNames.slideRight)) {
                var newOffset = containerWidth - maskSize - actual_position;
                if (scroll_offset > newOffset) {
                    var newInc = Math.round(newOffset / this.itemWidth);
                    scroll_offset = this.itemWidth * newInc;
                }
                // if set to infinite, start over
                if (startOver === true && trigger.hasClassName('endpoint')) {
                    this.slideBack(duration);
                }
                // standard movement
                if (max_position > maskSize) {
                    this.slideRight(trigger, scroll_offset, duration, lastMargin, max_position, maskSize, startOver);
                }
            // Slide left
            } else if (trigger.hasClassName(this.classNames.slideLeft)) {
                if (actual_position < scroll_offset) {
                    this.slideBack(duration);
                } else if (actual_position != '0') {
                    this.slideLeft(trigger, scroll_offset, duration);
                }
            }
        }
    });
