/**
 * jQuery bxSlider v3.0
 * http://bxslider.com
 *
 * Copyright 2010, Steven Wanderski
 * http://stevenwanderski.com
 *
 * Free to use and abuse under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 * 
 */


(function ($) {

    $.fn.bxSlider = function (options) {

        var defaults = {
            mode: 'horizontal', 								// 'horizontal', 'vertical', 'fade'
            infiniteLoop: true, 								// true, false - display first slide after last
            hideControlOnEnd: false, 					// true, false - if true, will hide 'next' control on last slide and 'prev' control on first
            controls: true, 										// true, false - previous and next controls
            speed: 500, 												// integer - in ms, duration of time slide transitions will occupy
            easing: 'swing',                    // used with jquery.easing.1.3.js - see http://gsgd.co.uk/sandbox/jquery/easing/ for available options
            pager: false, 											// true / false - display a pager
            pagerSelector: null, 							// jQuery selector - element to contain the pager. ex: '#pager'
            pagerType: 'full', 								// 'full', 'short' - if 'full' pager displays 1,2,3... if 'short' pager displays 1 / 4
            pagerLocation: 'bottom', 					// 'bottom', 'top' - location of pager
            pagerShortSeparator: '/', 					// string - ex: 'of' pager would display 1 of 4
            pagerActiveClass: 'pager-active', 	// string - classname attached to the active pager link
            nextText: 'next', 									// string - text displayed for 'next' control
            nextImage: '', 										// string - filepath of image used for 'next' control. ex: 'images/next.jpg'
            nextSelector: null, 								// jQuery selector - element to contain the next control. ex: '#next'
            prevText: 'prev', 									// string - text displayed for 'previous' control
            prevImage: '', 										// string - filepath of image used for 'previous' control. ex: 'images/prev.jpg'
            prevSelector: null, 								// jQuery selector - element to contain the previous control. ex: '#next'
            captions: false, 									// true, false - display image captions (reads the image 'title' tag)
            captionsSelector: null, 						// jQuery selector - element to contain the captions. ex: '#captions'
            auto: false, 											// true, false - make slideshow change automatically
            autoDirection: 'next', 						// 'next', 'prev' - direction in which auto show will traverse
            autoControls: false, 							// true, false - show 'start' and 'stop' controls for auto show
            autoControlsSelector: null, 				// jQuery selector - element to contain the auto controls. ex: '#auto-controls'
            autoStart: true, 									// true, false - if false show will wait for 'start' control to activate
            autoHover: false, 									// true, false - if true show will pause on mouseover
            autoDelay: 0,                       // integer - in ms, the amount of time before starting the auto show
            pause: 3000, 											// integer - in ms, the duration between each slide transition
            startText: 'start', 								// string - text displayed for 'start' control
            startImage: '', 										// string - filepath of image used for 'start' control. ex: 'images/start.jpg'
            stopText: 'stop', 									// string - text displayed for 'stop' control
            stopImage: '', 										// string - filepath of image used for 'stop' control. ex: 'images/stop.jpg'
            ticker: false, 										// true, false - continuous motion ticker mode (think news ticker)
            // note: autoControls, autoControlsSelector, and autoHover apply to ticker!
            tickerSpeed: 5000, 							  // float - use value between 1 and 5000 to determine ticker speed - the smaller the value the faster the ticker speed
            tickerDirection: 'next', 					// 'next', 'prev' - direction in which ticker show will traverse
            tickerHover: false,                 // true, false - if true ticker will pause on mouseover
            wrapperClass: 'bx-wrapper', 				// string - classname attached to the slider wraper
            startingSlide: 0, 									// integer - show will start on specified slide. note: slides are zero based!
            displaySlideQty: 1, 								// integer - number of slides to display at once
            moveSlideQty: 1, 									// integer - number of slides to move at once
            randomStart: false, 								// true, false - if true show will start on a random slide
            onBeforeSlide: function () { }, 			// function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager
            onAfterSlide: function () { }, 				// function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager
            onLastSlide: function () { }, 				// function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager
            onFirstSlide: function () { }, 				// function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager
            onNextSlide: function () { }, 				// function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager
            onPrevSlide: function () { }, 				// function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager
            buildPager: null										// function(slideIndex, slideHtmlObject){ return string; } - advanced use only! see the tutorial here: http://bxslider.com/custom-pager
        }

        var options = $.extend(defaults, options);

        // cache the base element
        var base = this;
        // initialize (and localize) all variables
        var $parent = '';
        var $origElement = '';
        var $children = '';
        var $outerWrapper = '';
        var $firstChild = '';
        var childrenWidth = '';
        var childrenOuterWidth = '';
        var wrapperWidth = '';
        var wrapperHeight = '';
        var $pager = '';
        var interval = '';
        var $autoControls = '';
        var $stopHtml = '';
        var $startContent = '';
        var $stopContent = '';
        var autoPlaying = true;
        var loaded = false;
        var childrenMaxWidth = 0;
        var childrenMaxHeight = 0;
        var currentSlide = 0;
        var origLeft = 0;
        var origTop = 0;
        var origShowWidth = 0;
        var origShowHeight = 0;
        var tickerLeft = 0;
        var tickerTop = 0;
        var isWorking = false;

        var firstSlide = 0;
        var lastSlide = $children.length - 1;


        // PUBLIC FUNCTIONS

        /**
        * Go to specified slide
        */
        this.goToSlide = function (number, stopAuto) {
            if (!isWorking) {
                isWorking = true;
                // set current slide to argument
                currentSlide = number;
                options.onBeforeSlide(currentSlide, $children.length, $children.eq(currentSlide));
                // check if stopAuto argument is supplied
                if (typeof (stopAuto) == 'undefined') {
                    var stopAuto = true;
                }
                if (stopAuto) {
                    // if show is auto playing, stop it
                    if (options.auto) {
                        base.stopShow(true);
                    }
                }
                slide = number;
                // check for first slide callback
                if (slide == firstSlide) {
                    options.onFirstSlide(currentSlide, $children.length, $children.eq(currentSlide));
                }
                // check for last slide callback
                if (slide == lastSlide) {
                    options.onLastSlide(currentSlide, $children.length, $children.eq(currentSlide));
                }
                // horizontal
                if (options.mode == 'horizontal') {
                    $parent.animate({ 'left': '-' + getSlidePosition(slide, 'left') + 'px' }, options.speed, options.easing, function () {
                        isWorking = false;
                        // perform the callback function
                        options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide));
                    });
                    // vertical
                } else if (options.mode == 'vertical') {
                    $parent.animate({ 'top': '-' + getSlidePosition(slide, 'top') + 'px' }, options.speed, options.easing, function () {
                        isWorking = false;
                        // perform the callback function
                        options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide));
                    });
                    // fade	
                } else if (options.mode == 'fade') {
                    setChildrenFade();
                }
                // check to remove controls on last/first slide
                checkEndControls();
                // accomodate multi slides
                if (options.moveSlideQty > 1) {
                    number = Math.floor(number / options.moveSlideQty);
                }
                // make the current slide active
                makeSlideActive(number);
                // display the caption
                showCaptions();
            }
        }

        /**
        * Go to next slide
        */
        this.goToNextSlide = function (stopAuto) {
            // check if stopAuto argument is supplied
            if (typeof (stopAuto) == 'undefined') {
                var stopAuto = true;
            }
            if (stopAuto) {
                // if show is auto playing, stop it
                if (options.auto) {
                    base.stopShow(true);
                }
            }
            // makes slideshow finite
            if (!options.infiniteLoop) {
                if (!isWorking) {
                    var slideLoop = false;
                    // make current slide the old value plus moveSlideQty
                    currentSlide = (currentSlide + (options.moveSlideQty));

                    // if current slide has looped on itself
                    if (currentSlide <= lastSlide) {
                        checkEndControls();
                        // next slide callback
                        options.onNextSlide(currentSlide, $children.length, $children.eq(currentSlide));
                        // move to appropriate slide
                        base.goToSlide(currentSlide);
                    } else {
                        currentSlide -= options.moveSlideQty;
                    }
                } // end if(!isWorking)		
            } else {
                if (!isWorking) {
                    isWorking = true;
                    var slideLoop = false;
                    // make current slide the old value plus moveSlideQty
                    currentSlide = (currentSlide + options.moveSlideQty);
                    // if current slide has looped on itself
                    if (currentSlide > lastSlide) {
                        currentSlide = currentSlide % $children.length;
                        slideLoop = true;
                    }
                    // next slide callback
                    options.onNextSlide(currentSlide, $children.length, $children.eq(currentSlide));
                    // slide before callback
                    options.onBeforeSlide(currentSlide, $children.length, $children.eq(currentSlide));
                    if (options.mode == 'horizontal') {
                        // get the new 'left' property for $parent
                        var parentLeft = (options.moveSlideQty * childrenOuterWidth);
                        // animate to the new 'left'
                        $parent.animate({ 'left': '-=' + parentLeft + 'px' }, options.speed, options.easing, function () {
                            isWorking = false;
                            // if its time to loop, reset the $parent
                            if (slideLoop) {
                                $parent.css('left', '-' + getSlidePosition(currentSlide, 'left') + 'px');
                            }
                            // perform the callback function
                            options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide));
                        });
                    } else if (options.mode == 'vertical') {
                        // get the new 'left' property for $parent
                        var parentTop = (options.moveSlideQty * childrenMaxHeight);
                        // animate to the new 'left'
                        $parent.animate({ 'top': '-=' + parentTop + 'px' }, options.speed, options.easing, function () {
                            isWorking = false;
                            // if its time to loop, reset the $parent
                            if (slideLoop) {
                                $parent.css('top', '-' + getSlidePosition(currentSlide, 'top') + 'px');
                            }
                            // perform the callback function
                            options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide));
                        });
                    } else if (options.mode == 'fade') {
                        setChildrenFade();
                    }
                    // make the current slide active
                    if (options.moveSlideQty > 1) {
                        makeSlideActive(Math.ceil(currentSlide / options.moveSlideQty));
                    } else {
                        makeSlideActive(currentSlide);
                    }
                    // display the caption
                    showCaptions();
                } // end if(!isWorking)

            }
        } // end function

        /**
        * Go to previous slide
        */
        this.goToPreviousSlide = function (stopAuto) {
            // check if stopAuto argument is supplied
            if (typeof (stopAuto) == 'undefined') {
                var stopAuto = true;
            }
            if (stopAuto) {
                // if show is auto playing, stop it
                if (options.auto) {
                    base.stopShow(true);
                }
            }
            // makes slideshow finite
            if (!options.infiniteLoop) {
                if (!isWorking) {
                    var slideLoop = false;
                    // make current slide the old value plus moveSlideQty
                    currentSlide = currentSlide - options.moveSlideQty;
                    // if current slide has looped on itself
                    if (currentSlide < 0) {
                        currentSlide = 0;
                        // if specified, hide the control on the last slide
                        if (options.hideControlOnEnd) {
                            $('.bx-prev', $outerWrapper).hide();
                        }
                    }
                    checkEndControls();
                    // next slide callback
                    options.onPrevSlide(currentSlide, $children.length, $children.eq(currentSlide));
                    // move to appropriate slide
                    base.goToSlide(currentSlide);
                }
            } else {
                if (!isWorking) {
                    isWorking = true;
                    var slideLoop = false;
                    // make current slide the old value plus moveSlideQty
                    currentSlide = (currentSlide - (options.moveSlideQty));
                    // if current slide has looped on itself
                    if (currentSlide < 0) {
                        negativeOffset = (currentSlide % $children.length);
                        if (negativeOffset == 0) {
                            currentSlide = 0;
                        } else {
                            currentSlide = ($children.length) + negativeOffset;
                        }
                        slideLoop = true;
                    }
                    // next slide callback
                    options.onPrevSlide(currentSlide, $children.length, $children.eq(currentSlide));
                    // slide before callback
                    options.onBeforeSlide(currentSlide, $children.length, $children.eq(currentSlide));
                    if (options.mode == 'horizontal') {
                        // get the new 'left' property for $parent
                        var parentLeft = (options.moveSlideQty * childrenOuterWidth);
                        // animate to the new 'left'
                        $parent.animate({ 'left': '+=' + parentLeft + 'px' }, options.speed, options.easing, function () {
                            isWorking = false;
                            // if its time to loop, reset the $parent
                            if (slideLoop) {
                                $parent.css('left', '-' + getSlidePosition(currentSlide, 'left') + 'px');
                            }
                            // perform the callback function
                            options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide));
                        });
                    } else if (options.mode == 'vertical') {
                        // get the new 'left' property for $parent
                        var parentTop = (options.moveSlideQty * childrenMaxHeight);
                        // animate to the new 'left'
                        $parent.animate({ 'top': '+=' + parentTop + 'px' }, options.speed, options.easing, function () {
                            isWorking = false;
                            // if its time to loop, reset the $parent
                            if (slideLoop) {
                                $parent.css('top', '-' + getSlidePosition(currentSlide, 'top') + 'px');
                            }
                            // perform the callback function
                            options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide));
                        });
                    } else if (options.mode == 'fade') {
                        setChildrenFade();
                    }
                    // make the current slide active
                    if (options.moveSlideQty > 1) {
                        makeSlideActive(Math.ceil(currentSlide / options.moveSlideQty));
                    } else {
                        makeSlideActive(currentSlide);
                    }
                    // display the caption
                    showCaptions();
                } // end if(!isWorking)				
            }
        } // end function

        /**
        * Go to first slide
        */
        this.goToFirstSlide = function (stopAuto) {
            // check if stopAuto argument is supplied
            if (typeof (stopAuto) == 'undefined') {
                var stopAuto = true;
            }
            base.goToSlide(firstSlide, stopAuto);
        }

        /**
        * Go to last slide
        */
        this.goToLastSlide = function () {
            // check if stopAuto argument is supplied
            if (typeof (stopAuto) == 'undefined') {
                var stopAuto = true;
            }
            base.goToSlide(lastSlide, stopAuto);
        }

        /**
        * Get the current slide
        */
        this.getCurrentSlide = function () {
            return currentSlide;
        }

        /**
        * Get the total slide count
        */
        this.getSlideCount = function () {
            return $children.length;
        }

        /**
        * Stop the slideshow
        */
        this.stopShow = function (changeText) {
            clearInterval(interval);
            // check if changeText argument is supplied
            if (typeof (changeText) == 'undefined') {
                var changeText = true;
            }
            if (changeText && options.autoControls) {
                $autoControls.html($startContent).removeClass('stop').addClass('start');
                autoPlaying = false;
            }
        }

        /**
        * Start the slideshow
        */
        this.startShow = function (changeText) {
            // check if changeText argument is supplied
            if (typeof (changeText) == 'undefined') {
                var changeText = true;
            }
            setAutoInterval();
            if (changeText && options.autoControls) {
                $autoControls.html($stopContent).removeClass('start').addClass('stop');
                autoPlaying = true;
            }
        }

        /**
        * Stops the ticker
        */
        this.stopTicker = function (changeText) {
            $parent.stop();
            // check if changeText argument is supplied
            if (typeof (changeText) == 'undefined') {
                var changeText = true;
            }
            if (changeText && options.ticker) {
                $autoControls.html($startContent).removeClass('stop').addClass('start');
                autoPlaying = false;
            }
        }

        /**
        * Starts the ticker
        */
        this.startTicker = function (changeText) {
            if (options.mode == 'horizontal') {
                if (options.tickerDirection == 'next') {
                    // get the 'left' property where the ticker stopped
                    var stoppedLeft = parseInt($parent.css('left'));
                    // calculate the remaining distance the show must travel until the loop
                    var remainingDistance = (origShowWidth + stoppedLeft) + $children.eq(0).width();
                } else if (options.tickerDirection == 'prev') {
                    // get the 'left' property where the ticker stopped
                    var stoppedLeft = -parseInt($parent.css('left'));
                    // calculate the remaining distance the show must travel until the loop
                    var remainingDistance = (stoppedLeft) - $children.eq(0).width();
                }
                // calculate the speed ratio to seamlessly finish the loop
                var finishingSpeed = (remainingDistance * options.tickerSpeed) / origShowWidth;
                // call the show
                moveTheShow(tickerLeft, remainingDistance, finishingSpeed);
            } else if (options.mode == 'vertical') {
                if (options.tickerDirection == 'next') {
                    // get the 'top' property where the ticker stopped
                    var stoppedTop = parseInt($parent.css('top'));
                    // calculate the remaining distance the show must travel until the loop
                    var remainingDistance = (origShowHeight + stoppedTop) + $children.eq(0).height();
                } else if (options.tickerDirection == 'prev') {
                    // get the 'left' property where the ticker stopped
                    var stoppedTop = -parseInt($parent.css('top'));
                    // calculate the remaining distance the show must travel until the loop
                    var remainingDistance = (stoppedTop) - $children.eq(0).height();
                }
                // calculate the speed ratio to seamlessly finish the loop
                var finishingSpeed = (remainingDistance * options.tickerSpeed) / origShowHeight;
                // call the show
                moveTheShow(tickerTop, remainingDistance, finishingSpeed);
                // check if changeText argument is supplied
                if (typeof (changeText) == 'undefined') {
                    var changeText = true;
                }
                if (changeText && options.ticker) {
                    $autoControls.html($stopContent).removeClass('start').addClass('stop');
                    autoPlaying = true;
                }
            }
        }

        /**
        * Initialize a new slideshow
        */
        this.initShow = function () {

            // reinitialize all variables
            // base = this;
            $parent = $(this);
            $origElement = $parent.clone();
            $children = $parent.children();
            $outerWrapper = '';
            $firstChild = $parent.children(':first');
            childrenWidth = $firstChild.width();
            childrenMaxWidth = 0;
            childrenOuterWidth = $firstChild.outerWidth();
            childrenMaxHeight = 0;
            wrapperWidth = getWrapperWidth();
            wrapperHeight = getWrapperHeight();
            isWorking = false;
            $pager = '';
            currentSlide = 0;
            origLeft = 0;
            origTop = 0;
            interval = '';
            $autoControls = '';
            $stopHtml = '';
            $startContent = '';
            $stopContent = '';
            autoPlaying = true;
            loaded = false;
            origShowWidth = 0;
            origShowHeight = 0;
            tickerLeft = 0;
            tickerTop = 0;

            firstSlide = 0;
            lastSlide = $children.length - 1;

            // get the largest child's height and width
            $children.each(function (index) {
                if ($(this).outerHeight() > childrenMaxHeight) {
                    childrenMaxHeight = $(this).outerHeight();
                }
                if ($(this).outerWidth() > childrenMaxWidth) {
                    childrenMaxWidth = $(this).outerWidth();
                }
            });

            // get random slide number
            if (options.randomStart) {
                var randomNumber = Math.floor(Math.random() * $children.length);
                currentSlide = randomNumber;
                origLeft = childrenOuterWidth * (options.moveSlideQty + randomNumber);
                origTop = childrenMaxHeight * (options.moveSlideQty + randomNumber);
                // start show at specific slide
            } else {
                currentSlide = options.startingSlide;
                origLeft = childrenOuterWidth * (options.moveSlideQty + options.startingSlide)+5;
                origTop = childrenMaxHeight * (options.moveSlideQty + options.startingSlide);
            }

            // set initial css
            initCss();

            // check to show pager
            if (options.pager && !options.ticker) {
                if (options.pagerType == 'full') {
                    showPager('full');
                } else if (options.pagerType == 'short') {
                    showPager('short');
                }
            }

            // check to show controls
            if (options.controls && !options.ticker) {
                setControlsVars();
            }

            // check if auto
            if (options.auto || options.ticker) {
                // check if auto controls are displayed
                if (options.autoControls) {
                    setAutoControlsVars();
                }
                // check if show should auto start
                if (options.autoStart) {
                    // check if autostart should delay
                    setTimeout(function () {
                        base.startShow(true);
                    }, options.autoDelay);
                } else {
                    base.stopShow(true);
                }
                // check if show should pause on hover
                if (options.autoHover && !options.ticker) {
                    setAutoHover();
                }
            }
            // make the starting slide active
            if (options.moveSlideQty > 1) {
                makeSlideActive(Math.ceil(currentSlide / options.moveSlideQty));
            } else {
                makeSlideActive(currentSlide);
            }
            // check for finite show and if controls should be hidden
            checkEndControls();
            // show captions
            if (options.captions) {
                showCaptions();
            }
            // perform the callback function
            options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide));
        }

        /**
        * Destroy the current slideshow
        */
        this.destroyShow = function () {
            // stop the auto show
            clearInterval(interval);
            // remove any controls / pagers that have been appended
            $('.bx-next, .bx-prev, .bx-pager, .bx-auto', $outerWrapper).remove();
            // unwrap all bx-wrappers
            $parent.unwrap().unwrap().removeAttr('style');
            // remove any styles that were appended
            $parent.children().removeAttr('style').not('.pager').remove();
            // remove any childrent that were appended
            $children.removeClass('pager');

        }

        /**
        * Reload the current slideshow
        */
        this.reloadShow = function () {
            base.destroyShow();
            base.initShow();
        }

        // PRIVATE FUNCTIONS

        /**
        * Creates all neccessary styling for the slideshow
        */
        function initCss() {
            // layout the children
            setChildrenLayout(options.startingSlide);
            // CSS for horizontal mode
            if (options.mode == 'horizontal') {
                // wrap the <ul> in div that acts as a window and make the <ul> uber wide
                $parent
				.wrap('<div class="' + options.wrapperClass + '" style="width:' + wrapperWidth + 'px; position:relative;"></div>')
				.wrap('<div class="bx-window" style="position:relative; overflow:hidden; width:' + wrapperWidth + 'px;"></div>')
				.css({
				    width: '999999px',
				    position: 'relative',
				    left: '-' + (origLeft) + 'px'
				});
                $parent.children().css({
                    width: childrenWidth,
                    'float': 'left',
                    listStyle: 'none'
                });
                $outerWrapper = $parent.parent().parent();
                $children.addClass('pager');
                // CSS for vertical mode
            } else if (options.mode == 'vertical') {
                // wrap the <ul> in div that acts as a window and make the <ul> uber tall
                $parent
				.wrap('<div class="' + options.wrapperClass + '" style="width:' + childrenMaxWidth + 'px; position:relative;"></div>')
				.wrap('<div class="bx-window" style="width:' + childrenMaxWidth + 'px; height:' + wrapperHeight + 'px; position:relative; overflow:hidden;"></div>')
				.css({
				    height: '999999px',
				    position: 'relative',
				    top: '-' + (origTop) + 'px'
				});
                $parent.children().css({
                    listStyle: 'none',
                    height: childrenMaxHeight
                });
                $outerWrapper = $parent.parent().parent();
                $children.addClass('pager');
                // CSS for fade mode
            } else if (options.mode == 'fade') {
                // wrap the <ul> in div that acts as a window
                $parent
				.wrap('<div class="' + options.wrapperClass + '" style="width:' + childrenMaxWidth + 'px; position:relative;"></div>')
				.wrap('<div class="bx-window" style="height:' + childrenMaxHeight + 'px; width:' + childrenMaxWidth + 'px; position:relative; overflow:hidden;"></div>');
                $parent.children().css({
                    listStyle: 'none',
                    position: 'absolute',
                    top: 0,
                    left: 0,
                    zIndex: 98
                });
                $outerWrapper = $parent.parent().parent();
                $children.not(':eq(' + currentSlide + ')').fadeTo(0, 0);
                $children.eq(currentSlide).css('zIndex', 99);
            }
            // if captions = true setup a div placeholder
            if (options.captions && options.captionsSelector == null) {
                $outerWrapper.append('<div class="bx-captions"></div>');
            }
        }

        /**
        * Depending on mode, lays out children in the proper setup
        */
        function setChildrenLayout() {
            // lays out children for horizontal or vertical modes
            if (options.mode == 'horizontal' || options.mode == 'vertical') {

                // get the children behind
                var $prependedChildren = getArraySample($children, 0, options.moveSlideQty, 'backward');

                // add each prepended child to the back of the original element
                $.each($prependedChildren, function (index) {
                    $parent.prepend($(this));
                });

                // total number of slides to be hidden after the window
                var totalNumberAfterWindow = ($children.length + options.moveSlideQty) - 1;
                // number of original slides hidden after the window
                var pagerExcess = $children.length - options.displaySlideQty;
                // number of slides to append to the original hidden slides
                var numberToAppend = totalNumberAfterWindow - pagerExcess;
                // get the sample of extra slides to append
                var $appendedChildren = getArraySample($children, 0, numberToAppend, 'forward');

                if (options.infiniteLoop) {
                    // add each appended child to the front of the original element
                    $.each($appendedChildren, function (index) {
                        $parent.append($(this));
                    });
                }
            }
        }

        /**
        * Sets all variables associated with the controls
        */
        function setControlsVars() {
            // check if text or images should be used for controls
            // check "next"
            if (options.nextImage != '') {
                nextContent = options.nextImage;
                nextType = 'image';
            } else {
                nextContent = options.nextText;
                nextType = 'text';
            }
            // check "prev"
            if (options.prevImage != '') {
                prevContent = options.prevImage;
                prevType = 'image';
            } else {
                prevContent = options.prevText;
                prevType = 'text';
            }
            // show the controls
            showControls(nextType, nextContent, prevType, prevContent);
        }

        /**
        * Puts slideshow into auto mode
        *
        * @param int pause number of ms the slideshow will wait between slides 
        * @param string direction 'forward', 'backward' sets the direction of the slideshow (forward/backward)
        * @param bool controls determines if start/stop controls will be displayed
        */
        function setAutoInterval() {
            if (options.auto) {
                // finite loop
                if (!options.infiniteLoop) {
                    if (options.autoDirection == 'next') {
                        interval = setInterval(function () {
                            currentSlide += options.moveSlideQty;
                            // if currentSlide has exceeded total number
                            if (currentSlide > lastSlide) {
                                currentSlide = currentSlide % $children.length;
                            }
                            base.goToSlide(currentSlide, false);
                        }, options.pause);
                    } else if (options.autoDirection == 'prev') {
                        interval = setInterval(function () {
                            currentSlide -= options.moveSlideQty;
                            // if currentSlide is smaller than zero
                            if (currentSlide < 0) {
                                negativeOffset = (currentSlide % $children.length);
                                if (negativeOffset == 0) {
                                    currentSlide = 0;
                                } else {
                                    currentSlide = ($children.length) + negativeOffset;
                                }
                            }
                            base.goToSlide(currentSlide, false);
                        }, options.pause);
                    }
                    // infinite loop
                } else {
                    if (options.autoDirection == 'next') {
                        interval = setInterval(function () {
                            base.goToNextSlide(false);
                        }, options.pause);
                    } else if (options.autoDirection == 'prev') {
                        interval = setInterval(function () {
                            base.goToPreviousSlide(false);
                        }, options.pause);
                    }
                }

            } else if (options.ticker) {

                options.tickerSpeed *= 10;

                // get the total width of the original show
                $('.pager', $outerWrapper).each(function (index) {
                    origShowWidth += $(this).width();
                    origShowHeight += $(this).height();
                });

                // if prev start the show from the last slide
                if (options.tickerDirection == 'prev' && options.mode == 'horizontal') {
                    $parent.css('left', '-' + (origShowWidth + origLeft) + 'px');
                } else if (options.tickerDirection == 'prev' && options.mode == 'vertical') {
                    $parent.css('top', '-' + (origShowHeight + origTop) + 'px');
                }

                if (options.mode == 'horizontal') {
                    // get the starting left position
                    tickerLeft = parseInt($parent.css('left'));
                    // start the ticker
                    moveTheShow(tickerLeft, origShowWidth, options.tickerSpeed);
                } else if (options.mode == 'vertical') {
                    // get the starting top position
                    tickerTop = parseInt($parent.css('top'));
                    // start the ticker
                    moveTheShow(tickerTop, origShowHeight, options.tickerSpeed);
                }

                // check it tickerHover applies
                if (options.tickerHover) {
                    setTickerHover();
                }
            }
        }

        function moveTheShow(leftCss, distance, speed) {
            // if horizontal
            if (options.mode == 'horizontal') {
                // if next
                if (options.tickerDirection == 'next') {
                    $parent.animate({ 'left': '-=' + distance + 'px' }, speed, 'linear', function () {
                        $parent.css('left', leftCss);
                        moveTheShow(leftCss, origShowWidth, options.tickerSpeed);
                    });
                    // if prev
                } else if (options.tickerDirection == 'prev') {
                    $parent.animate({ 'left': '+=' + distance + 'px' }, speed, 'linear', function () {
                        $parent.css('left', leftCss);
                        moveTheShow(leftCss, origShowWidth, options.tickerSpeed);
                    });
                }
                // if vertical		
            } else if (options.mode == 'vertical') {
                // if next
                if (options.tickerDirection == 'next') {
                    $parent.animate({ 'top': '-=' + distance + 'px' }, speed, 'linear', function () {
                        $parent.css('top', leftCss);
                        moveTheShow(leftCss, origShowHeight, options.tickerSpeed);
                    });
                    // if prev
                } else if (options.tickerDirection == 'prev') {
                    $parent.animate({ 'top': '+=' + distance + 'px' }, speed, 'linear', function () {
                        $parent.css('top', leftCss);
                        moveTheShow(leftCss, origShowHeight, options.tickerSpeed);
                    });
                }
            }
        }

        /**
        * Sets all variables associated with the controls
        */
        function setAutoControlsVars() {
            // check if text or images should be used for controls
            // check "start"
            if (options.startImage != '') {
                startContent = options.startImage;
                startType = 'image';
            } else {
                startContent = options.startText;
                startType = 'text';
            }
            // check "stop"
            if (options.stopImage != '') {
                stopContent = options.stopImage;
                stopType = 'image';
            } else {
                stopContent = options.stopText;
                stopType = 'text';
            }
            // show the controls
            showAutoControls(startType, startContent, stopType, stopContent);
        }

        /**
        * Handles hover events for auto shows
        */
        function setAutoHover() {
            // hover over the slider window
            $outerWrapper.find('.bx-window').hover(function () {
                if (autoPlaying) {
                    base.stopShow(false);
                }
            }, function () {
                if (autoPlaying) {
                    base.startShow(false);
                }
            });
        }

        /**
        * Handles hover events for ticker mode
        */
        function setTickerHover() {
            // on hover stop the animation
            $parent.hover(function () {
                if (autoPlaying) {
                    base.stopTicker(false);
                }
            }, function () {
                if (autoPlaying) {
                    base.startTicker(false);
                }
            });
        }

        /**
        * Handles fade animation
        */
        function setChildrenFade() {
            // fade out any other child besides the current
            $children.not(':eq(' + currentSlide + ')').fadeTo(options.speed, 0).css('zIndex', 98);
            // fade in the current slide
            $children.eq(currentSlide).css('zIndex', 99).fadeTo(options.speed, 1, function () {
                isWorking = false;
                // ie fade fix
                if (jQuery.browser.msie) {
                    $children.eq(currentSlide).get(0).style.removeAttribute('filter');
                }
                // perform the callback function
                options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide));
            });
        };

        /**
        * Makes slide active
        */
        function makeSlideActive(number) {
            if (options.pagerType == 'full' && options.pager) {
                // remove all active classes
                $('a', $pager).removeClass(options.pagerActiveClass);
                // assign active class to appropriate slide
                $('a', $pager).eq(number).addClass(options.pagerActiveClass);
            } else if (options.pagerType == 'short' && options.pager) {
                $('.bx-pager-current', $pager).html(currentSlide + 1);
            }
        }

        /**
        * Displays next/prev controls
        *
        * @param string nextType 'image', 'text'
        * @param string nextContent if type='image', specify a filepath to the image. if type='text', specify text.
        * @param string prevType 'image', 'text'
        * @param string prevContent if type='image', specify a filepath to the image. if type='text', specify text.
        */
        function showControls(nextType, nextContent, prevType, prevContent) {
            // create pager html elements
            var $nextHtml = $('<a href="" class="bx-next"></a>');
            var $prevHtml = $('<a href="" class="bx-prev"></a>');
            // check if next is 'text' or 'image'
            if (nextType == 'text') {
                $nextHtml.html(nextContent);
            } else {
                $nextHtml.html('<img src="' + nextContent + '" />');
            }
            // check if prev is 'text' or 'image'
            if (prevType == 'text') {
                $prevHtml.html(prevContent);
            } else {
                $prevHtml.html('<img src="' + prevContent + '" />');
            }
            // check if user supplied a selector to populate next control
            if (options.prevSelector) {
                $(options.prevSelector).append($prevHtml);
            } else {
                $outerWrapper.append($prevHtml);
            }
            // check if user supplied a selector to populate next control
            if (options.nextSelector) {
                $(options.nextSelector).append($nextHtml);
            } else {
                $outerWrapper.append($nextHtml);
            }
            // click next control
            $nextHtml.click(function () {
                base.goToNextSlide();
                return false;
            });
            // click prev control
            $prevHtml.click(function () {
                base.goToPreviousSlide();
                return false;
            });
        }

        /**
        * Displays the pager
        *
        * @param string type 'full', 'short'
        */
        function showPager(type) {
            // sets up logic for finite multi slide shows
            var pagerQty = $children.length;
            // if we are moving more than one at a time and we have a finite loop
            if (options.moveSlideQty > 1) {
                // if slides create an odd number of pages
                if ($children.length % options.moveSlideQty != 0) {
                    // pagerQty = $children.length / options.moveSlideQty + 1;
                    pagerQty = Math.ceil($children.length / options.moveSlideQty);
                    // if slides create an even number of pages
                } else {
                    pagerQty = $children.length / options.moveSlideQty;
                }
            }
            var pagerString = '';
            // check if custom build function was supplied
            if (options.buildPager) {
                for (var i = 0; i < pagerQty; i++) {
                    pagerString += options.buildPager(i, $children.eq(i * options.moveSlideQty));
                }

                // if not, use default pager
            } else if (type == 'full') {
                // build the full pager
                for (var i = 1; i <= pagerQty; i++) {
                    pagerString += '<a href="" class="pager-link pager-' + i + '">' + i + '</a>';
                }
            } else if (type == 'short') {
                // build the short pager
                pagerString = '<span class="bx-pager-current">' + (options.startingSlide + 1) + '</span> ' + options.pagerShortSeparator + ' <span class="bx-pager-total">' + $children.length + '<span>';
            }
            // check if user supplied a pager selector
            if (options.pagerSelector) {
                $(options.pagerSelector).append(pagerString);
                $pager = $(options.pagerSelector);
            } else {
                var $pagerContainer = $('<div class="bx-pager"></div>');
                $pagerContainer.append(pagerString);
                // attach the pager to the DOM
                if (options.pagerLocation == 'top') {
                    $outerWrapper.prepend($pagerContainer);
                } else if (options.pagerLocation == 'bottom') {
                    $outerWrapper.append($pagerContainer);
                }
                // cache the pager element
                $pager = $('.bx-pager', $outerWrapper);
            }
            $pager.children().click(function () {
                // only if pager is full mode
                if (options.pagerType == 'full') {
                    // get the index from the link
                    var slideIndex = $pager.children().index(this);
                    // accomodate moving more than one slide
                    if (options.moveSlideQty > 1) {
                        slideIndex *= options.moveSlideQty;
                    }
                    base.goToSlide(slideIndex);
                }
                return false;
            });
        }

        /**
        * Displays captions
        */
        function showCaptions() {
            // get the title from each image
            var caption = $('img', $children.eq(currentSlide)).attr('title');
            // if the caption exists
            if (caption != '') {
                // if user supplied a selector
                if (options.captionsSelector) {
                    $(options.captionsSelector).html(caption);
                } else {
                    $('.bx-captions', $outerWrapper).html(caption);
                }
            } else {
                // if user supplied a selector
                if (options.captionsSelector) {
                    $(options.captionsSelector).html('&nbsp;');
                } else {
                    $('.bx-captions', $outerWrapper).html('&nbsp;');
                }
            }
        }

        /**
        * Displays start/stop controls for auto and ticker mode
        *
        * @param string type 'image', 'text'
        * @param string next [optional] if type='image', specify a filepath to the image. if type='text', specify text.
        * @param string prev [optional] if type='image', specify a filepath to the image. if type='text', specify text.
        */
        function showAutoControls(startType, startContent, stopType, stopContent) {
            // create pager html elements
            $autoControls = $('<a href="" class="bx-start"></a>');
            // check if start is 'text' or 'image'
            if (startType == 'text') {
                $startContent = startContent;
            } else {
                $startContent = '<img src="' + startContent + '" />';
            }
            // check if stop is 'text' or 'image'
            if (stopType == 'text') {
                $stopContent = stopContent;
            } else {
                $stopContent = '<img src="' + stopContent + '" />';
            }
            // check if user supplied a selector to populate next control
            if (options.autoControlsSelector) {
                $(options.autoControlsSelector).append($autoControls);
            } else {
                $outerWrapper.append('<div class="bx-auto"></div>');
                $('.bx-auto', $outerWrapper).html($autoControls);
            }

            // click start control
            $autoControls.click(function () {
                if (options.ticker) {
                    if ($(this).hasClass('stop')) {
                        base.stopTicker();
                    } else if ($(this).hasClass('start')) {
                        base.startTicker();
                    }
                } else {
                    if ($(this).hasClass('stop')) {
                        base.stopShow(true);
                    } else if ($(this).hasClass('start')) {
                        base.startShow(true);
                    }
                }
                return false;
            });

        }

        /**
        * Checks if show is in finite mode, and if slide is either first or last, then hides the respective control
        */
        function checkEndControls() {
            // alert(currentSlide + " - " + lastSlide + " - " + $children.length);
            if (!options.infiniteLoop && options.hideControlOnEnd) {
                // check previous
                if (currentSlide == firstSlide) {
                    $('.bx-prev', $outerWrapper).hide();
                } else {
                    $('.bx-prev', $outerWrapper).show();
                }
                // check next
                if (currentSlide == lastSlide) {
                    $('.bx-next', $outerWrapper).hide();
                } else {
                    $('.bx-next', $outerWrapper).show();
                }
            }
        }

        /**
        * Returns the left offset of the slide from the parent container
        */
        function getSlidePosition(number, side) {
            if (side == 'left') {
                var position = $('.pager', $outerWrapper).eq(number).position().left;
            } else if (side == 'top') {
                var position = $('.pager', $outerWrapper).eq(number).position().top;
            }
            return position;
        }

        /**
        * Returns the width of the wrapper
        */
        function getWrapperWidth() {
            var wrapperWidth = $firstChild.outerWidth() * options.displaySlideQty;
            return wrapperWidth;
        }

        /**
        * Returns the height of the wrapper
        */
        function getWrapperHeight() {
            // if displaying multiple slides, multiple wrapper width by number of slides to display
            var wrapperHeight = $firstChild.outerHeight() * options.displaySlideQty;
            return wrapperHeight;
        }

        /**
        * Returns a sample of an arry and loops back on itself if the end of the array is reached
        *
        * @param array array original array the sample is derived from
        * @param int start array index sample will start
        * @param int length number of items in the sample
        * @param string direction 'forward', 'backward' direction the loop should travel in the array
        */
        function getArraySample(array, start, length, direction) {
            // initialize empty array
            var sample = [];
            // clone the length argument
            var loopLength = length;
            // determines when the empty array should start being populated
            var startPopulatingArray = false;
            // reverse the array if direction = 'backward'
            if (direction == 'backward') {
                array = $.makeArray(array);
                array.reverse();
            }
            // loop through original array until the length argument is met
            while (loopLength > 0) {
                // loop through original array
                $.each(array, function (index, val) {
                    // check if length has been met
                    if (loopLength > 0) {
                        // don't do anything unless first index has been reached
                        if (!startPopulatingArray) {
                            // start populating empty array
                            if (index == start) {
                                startPopulatingArray = true;
                                // add element to array
                                sample.push($(this).clone());
                                // decrease the length clone variable
                                loopLength--;
                            }
                        } else {
                            // add element to array
                            sample.push($(this).clone());
                            // decrease the length clone variable
                            loopLength--;
                        }
                        // if length has been met, break loose
                    } else {
                        return false;
                    }
                });
            }
            return sample;
        }

        this.each(function () {
            base.initShow();
        });

        return this;
    }

    jQuery.fx.prototype.cur = function () {
        if (this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null)) {
            return this.elem[this.prop];
        }

        var r = parseFloat(jQuery.css(this.elem, this.prop));
        // return r && r > -10000 ? r : 0;
        return r;
    }


})(jQuery);


