
    function ArtboxSlideshow( slides, loadedSlides, options )
    {
        this.defaults = {
                            playback: 'auto',
                            loop: false,
                            replay: false,
                            display_time: 4,
                            transition_time: 1,
                            transition: 'crossFade',
                            transition_first: false,
                            caption_effect: 'none',
							key: '',
							starting_slide: 0,
							display_caption: false,
							display_controls: false,
							output_title: false,
                            next_button_image: '/static/img/button_next.png',
                            next_button_over_image: '/static/img/button_next_over.png',
                            prev_button_image: '/static/img/button_prev.png',
                            prev_button_over_image: '/static/img/button_prev_over.png',
                            end_button_image: '/static/img/button_end.png'
                       };


        this.settings = $.extend( {}, this.defaults, options );

        // Add Ids
        this.settings.slideshow_id = '#slideshow_' + this.settings.key;
        this.settings.slide_id     = '#slide_' + this.settings.key;

        if ( this.settings.caption_id == undefined )
		  this.settings.caption_id = '#slideshow_' + this.settings.key + '_caption';
		else
		  this.settings.default_caption_id = '#slideshow_' + this.settings.key + '_caption';

        if ( this.settings.title_id != undefined )
		{
			this.settings.default_title_id = '#slideshow_' + this.settings.key + '_title';
		}

		if ( this.settings.prev_button_id == undefined )
		  this.settings.prev_button_id = '#slideshow_' + this.settings.key + '_prev_button';
		else
		  this.settings.default_prev_button_id = '#slideshow_' + this.settings.key + '_prev_button';

		if ( this.settings.next_button_id == undefined )
			this.settings.next_button_id = '#slideshow_' + this.settings.key + '_next_button';
		else
			this.settings.default_next_button_id = '#slideshow_' + this.settings.key + '_next_button';

		// Convert times to milliseconds
		this.settings.display_time = this.settings.display_time * 1000;
		this.settings.transition_time = this.settings.transition_time * 1000;

		// Setup slides
        this.slides = slides;
        this.loadedSlides = loadedSlides;
		this.currentSlideIndex = this.settings.starting_slide;

        // Don't allow manual and looping for now
        if ( this.settings.playback == 'manual' )
          this.settings.loop = false;

        // Initialize prev and next buttons
        this.initializeButtons();

    }


    ArtboxSlideshow.prototype.display = function()
    {
        // Set up cycle
        var obj = this;  // for use in callback
        var timeout = ( this.settings.playback == 'manual' ) ? 0 : this.settings.display_time;
        var speed =  this.settings.transition_time;
        var nowrap = ! this.settings.loop;

        // Set up transitions
        var fx = '';
        var sync = true;

		// Map artbox transitions to cycle
        switch( this.settings.transition )
        {
            case 'scrollHorz':
            case 'scrollVert':
            case 'toss':
            case 'cover':
            case 'uncover':
			case 'none':
                fx = this.settings.transition;
                break;

            case 'fadeBg':
                fx = 'fade';
                sync = false;
                break;

            case 'crossFade':
            default:
                fx = 'fade';
                break;
        }


		// Set title for the slideshow
		if ( this.settings.display_title )
		{
			// Hide default HTML title
			if ( this.settings.default_title_id != undefined )
			{
				$( this.settings.default_title_id ).hide();

				// Only do this once
				this.settings.default_title_id = undefined;
			}

			if ( this.settings.title_id != undefined )
			  $( this.settings.title_id ).html( this.settings.name );
		}

        // Set caption for first slide
		this.setCaption();

        // Start up slideshow
        $( this.settings.slide_id ).cycle( {
	                            containerResize: false,
                                fx: fx,
                                sync: sync,
                                prev: this.settings.prev_button_id,
                                next: this.settings.next_button_id,
                                timeout: timeout,
                                speed: speed,
                                nowrap: nowrap,
                                startingSlide: this.settings.starting_slide,
                                before: function( curSlideElement, nextSlideElement, options, forwardFlag ){ obj.beforeSlide( curSlideElement, nextSlideElement, options, forwardFlag ); },
                                end: function( options ) { obj.endSlide( options ); }
                            }
                         );
    };


    ArtboxSlideshow.prototype.beforeSlide = function( curSlideElement, nextSlideElement, options, forwardFlag )
    {
		var nextSlideIndex;

		$(nextSlideElement).css('display', 'block');

        // The first time through the addSlide function doesn't exist
        if ( ! options.addSlide )
		  return;

        // Determine next slide

        // If this is the first slide
        if ( this.currentSlideIndex == 0  )
		{
			// If we're going forward
			if ( forwardFlag )
			{
				nextSlideIndex = this.currentSlideIndex + 1;
			}

			// If we're going backward and looping is enabled, go to the last slide
			else if ( this.settings.loop )
			{
				nextSlideIndex = this.slides.length - 1;
			}
			else
			{
				nextSlideIndex = this.currentSlideIndex;
			}
		}


		// If this is the last slide
		else if ( this.currentSlideIndex == this.slides.length - 1 )
		{
			// If we're going backward
			if ( ! forwardFlag )
			{
				nextSlideIndex = this.currentSlideIndex - 1;
			}

			// If we're going forward and looping is enabled, go to the first slide
			else if ( this.settings.loop )
			{
				nextSlideIndex = 0;
			}
			else
			{
				// Add class to next_button_id
				nextSlideIndex = this.currentSlideIndex;
			}
		}


		// Not the first or last slide
		else
		{
			if ( forwardFlag )
			{
				nextSlideIndex = this.currentSlideIndex + 1;
			}
			else
			{
				nextSlideIndex = this.currentSlideIndex - 1;
			}
		}

		this.currentSlideIndex = nextSlideIndex;

        // Update nav buttons
        if ( this.currentSlideIndex == 0 )
        {
            if ( this.settings.loop )
              this.enablePrevButton();
            else
              this.disablePrevButton();
		    this.enableNextButton();
        }
        else if ( this.currentSlideIndex == this.slides.length - 1 )
        {
            if ( this.settings.loop )
              this.enableNextButton();
            else
              this.disableNextButton();
		    this.enablePrevButton();
        }
        else
        {
            this.enablePrevButton();
            this.enableNextButton();
        }

		// Update alt, title, link for next slide
		this.updateImageAttributes( nextSlideElement );

        // Update caption
		this.setCaption();

		// Load the next slide
		loaded = this.loadSlide( options );
    };

    ArtboxSlideshow.prototype.loadSlide = function( options )
	{
		// Cycle requires the slides loaded in order, so just load the next slide

		// Are they all loaded?
		if ( this.loadedSlides.length == this.slides.length )
		  return false;

		// Load slide
		var slideIndex = this.loadedSlides.length;
        var s = this.slides[ slideIndex ];
        this.loadedSlides[ slideIndex ] = s;
		var imgNumber = slideIndex + 1;
        options.addSlide( '<div class="slide"><img src="' + s.src + '" id="slide_' + this.settings.key + '_img_' + imgNumber + '" /></div>' );
		return true;
	};


    ArtboxSlideshow.prototype.updateImageAttributes = function( slideSelector )
    {
		var img = $( 'img', slideSelector );
		img.css( 'display', 'block' );

        img.attr( 'alt', this.slides[this.currentSlideIndex].alt );

		if ( this.settings.output_title	)
          img.attr( 'title', this.slides[this.currentSlideIndex].alt );

        if ( this.slides[this.currentSlideIndex].link != '' )
        {
            var target = '';
			if ( this.slides[this.currentSlideIndex].target == '' )
            {
                target = ' target="_blank"';
            }

            img.wrap( '<a href="' + this.slides[this.currentSlideIndex].link + '"' + target + '>' );
        }
	};


	ArtboxSlideshow.prototype.setCaption = function()
	{
		if ( ! this.settings.display_caption )
		  return;

		// Hide default HTML caption
		if ( this.settings.default_caption_id != undefined )
		{
			$( this.settings.default_caption_id ).hide();

			// Only do this once
			this.settings.default_caption_id = undefined;
		}

		var obj = this;

		switch ( this.settings.caption_effect )
		{
			case 'fade':
				$( this.settings.caption_id ).fadeOut( this.settings.transition_time/2,
    												   function() { $(this).html( obj.slides[obj.currentSlideIndex].caption ) } ).fadeIn( this.settings.transition_time/2 );
				break;

			case 'slide':
				$( this.settings.caption_id ).slideUp( this.settings.transition_time/2,
													   function() { $(this).html( obj.slides[obj.currentSlideIndex].caption ) } ).slideDown( this.settings.transition_time/2 );
				break;

			case 'none':
			default:
				$( this.settings.caption_id ).html( this.slides[this.currentSlideIndex].caption );
				break;
		}
	};


    ArtboxSlideshow.prototype.initializeButtons = function()
    {
		// If the back to gallery # is set, show it
		if ( this.settings.back_to_id != undefined )
		  $( this.settings.back_to_id ).css( 'visibility', 'visible' );

		if ( this.settings.default_prev_button_id != undefined )
		  $( this.settings.default_prev_button_id ).hide();

		if ( this.settings.default_next_button_id != undefined )
		  $( this.settings.default_next_button_id ).hide();

        // If automatic playback mode, hide the prev/next controls
        if ( this.settings.playback == 'auto' )
        {
            $( this.settings.prev_button_id ).hide();
            $( this.settings.next_button_id ).hide();
        }
        else if ( this.settings.playback == 'manual' )
        {
			// If only one slide, no buttons needed
            if ( this.slides.length == 1 )
            {
                $( this.settings.prev_button_id ).hide();
                $( this.settings.next_button_id ).hide();
            }
            else if ( this.settings.loop )
            {
                this.enablePrevButton();
                this.enableNextButton();
            }
            else
            {
                // First slide: disable prev, enable next
                if ( this.currentSlideIndex == 0 )
                {
                    this.disablePrevButton();
                    this.enableNextButton();
                }

                // Last slide: enable prev, disable next
                else if ( this.currentSlideIndex == this.slides.length -1 )
                {
                    this.enablePrevButton();
                    this.disableNextButton();
                }
                else
                {
                    this.enablePrevButton();
                    this.enableNextButton();
                }
            }

            // Preload images
            var image = $('<img />').attr( 'src', this.settings.next_button_image );
            image = $('<img />').attr( 'src', this.settings.next_button_over_image );
            image = $('<img />').attr( 'src', this.settings.prev_button_image );
            image = $('<img />').attr( 'src', this.settings.prev_button_over_image );
            image = $('<img />').attr( 'src', this.settings.end_button_image );
        }
    };


    ArtboxSlideshow.prototype.enableNextButton = function()
    {
		$( this.settings.next_button_id ).css( 'visibility', 'visible' );
		$( this.settings.next_button_id ).removeClass( 'slideshow_end' );
	    $( this.settings.next_button_id ).attr( 'src', this.settings.next_button_image );

		$( this.settings.next_button_id ).bind( 'mouseenter.ab', { settings: this.settings }, function(e) {
                                                          $(this).attr( 'src', e.data.settings.next_button_over_image );
                                                          $(this).css( 'cursor', 'pointer' );
                                                      } );
        $( this.settings.next_button_id ).bind( 'mouseleave.ab', { settings: this.settings },  function(e) {
                                                          $(this).attr( 'src', e.data.settings.next_button_image );
                                                          $(this).css( 'cursor', 'auto' );
                                                      } );
    };


    ArtboxSlideshow.prototype.enablePrevButton = function()
    {
		$( this.settings.prev_button_id ).css( 'visibility', 'visible' );
		$( this.settings.prev_button_id ).removeClass( 'slideshow_end' );
        $( this.settings.prev_button_id ).attr( 'src', this.settings.prev_button_image );

		$( this.settings.prev_button_id ).bind( 'mouseenter.ab', { settings: this.settings}, function(e) {
                                                          $(this).attr( 'src', e.data.settings.prev_button_over_image );
                                                          $(this).css( 'cursor', 'pointer' );
                                                      } );
        $( this.settings.prev_button_id ).bind( 'mouseleave.ab', { settings: this.settings}, function(e) {
                                                          $(this).attr( 'src', e.data.settings.prev_button_image );
                                                          $(this).css( 'cursor', 'auto' );
                                                      } );
    };


    ArtboxSlideshow.prototype.disableNextButton = function()
    {
		$( this.settings.next_button_id ).css( 'visibility', 'visible' );
		$( this.settings.next_button_id ).addClass( 'slideshow_end' );
		$( this.settings.next_button_id ).attr( 'src', this.settings.end_button_image );
        $( this.settings.next_button_id ).unbind( 'click.ab' ).unbind( 'mouseenter.ab' ).unbind( 'mouseleave.ab' );
    };


    ArtboxSlideshow.prototype.disablePrevButton = function()
    {
		$( this.settings.prev_button_id ).css( 'visibility', 'visible' );
		$( this.settings.prev_button_id ).addClass( 'slideshow_end' );
        $( this.settings.prev_button_id ).attr( 'src', this.settings.end_button_image );
        $( this.settings.prev_button_id ).unbind( 'click.ab' ).unbind( 'mouseenter.ab' ).unbind( 'mouseleave.ab' );
    };


    ArtboxSlideshow.prototype.endSlide = function( options )
    {
    };

	ArtboxSlideshow.prototype.stop = function()
	{
		$( this.settings.slide_id ).cycle( 'stop' );
	};

