// standard library

var pr = function( obj )
{
  if( typeof console == 'object' )
  {
    for( i in obj )
    {
    //  console.log( i + ' is: ' + obj[i] );      
    }
  }
}

var cl = function( msg )
{
  if( typeof console == 'object' )
  {
  //  console.log( msg );      
  }
}

var id = function( el )
{
  return document.getElementById( el );
}

var isset = function( is_obj )
{
  if( typeof us_obj == 'undefined' )
  {
    return false;    
  }
  else
  {
    return true;
  }
}






var fadeBG = {
  // call this to use shadow in an iframe
  fadeInIframe: function ( url, fields )
  {
    if( typeof fields == 'object' )
    {
      // if using symfony create url get fields as part of url string
      var gets = '';
      for( i in fields )
      {
        gets += '/' + escape( i ) + '/' + escape( fields[i] );      
      }
      url = url + gets;
    }
    // fade in background
    fadeBG.fadeInBg( function ()
    {
      var top = winDim.getScrollTop() + 100; // add 100 px to the scroll
      var iframe = '\
  <iframe id="asset_iframe" scrolling="no" style="background-color: #ffffff; border: none; height: 600px; width: 800px; z-index: 15; position: absolute; top: '+top+'px; left: 50%; margin-left: -400px;" src="'+url+'"></iframe>\
      ';
      $( 'body' ).prepend( iframe );
      $( '#fade_bg' ).click( function() { 
         this.endSlideShow(); 
            });
    });
    
  },
    // removes iframe
   closeshadowIframe: function ()
  {
    $( '#asset_iframe' ).remove();
    fadeBG.fadeOutBg();
  },
  
  fadeInBg: function ( cb )
  {
    if( id( 'fade_bg' ))
    {
      //fade background exists so remove it
      $( id( 'fade_bg' )).remove();
    }
    $( 'body' ).prepend(
      '<div id="fade_bg"></div>'
    )
    $( '#fade_bg' ).css({ 
      'opacity': 0,
      'z-index': 10, 
      'width': '100%', 
      'height': winDim.getDocHeight(),
      'position': 'absolute', 
      'left': 0, 
      'top': 0,
      'backgroundColor': 'black',
      'display': 'block'
    })
    .fadeTo( 750, .5, function()
    {
      
      if( typeof cb == 'function' )
      {
        cb();
      }
    });  
  },
    
    fadeOutBg: function( cb ) {
    if( id( 'fade_bg' ))
    {
      //fade background exists so fade it out and remove it
            $( '#fade_bg' ).fadeOut( 750, function() {
        $( id( 'fade_bg' )).remove();
                
        if( cb != null && typeof cb == 'function' )
        {
          cb();
        }
            });
    }
    }
} // end fadeBG

/**
 *
 * This is a generic class, not to be used directly. Takes care of the basic functionality for all slideshow.
 *
 */
function jellSlideshow () {
  
  // public
  this.imgArr= []; // public - array of slide images
  this.imgCount= 0; // public - current slide id
  this.autoPlayTimeout= 1250; // time between slide change in autoplay [unfinished]
  this.nextSlideId= 1;  // index of next slide in imgArr
  this.prevSlideId= -1;  // index of prev slide in imgArr
  this.containerId= null; // public - id attribute of DOM element we're inserting the slideshow into
  this.nextSlide= null; // public - object referencing next slide
  this.prevSlide= null; // public - object referencing prev slide
  
  // internal
  this.count = 0;  // number of total images
  this.preloadedImages = []; // array of preloaded Image() objects
  this.slidesAreLoaded = false; // true once all slides images have been preloaded and imgArr has been populated
  this.checkIfSlidesLoaded = null; // setinterval that checks value of this.slidesAreLoaded
  
  var parent = this;

  this.preloadImage = function( objectIndex, imgObject, cb ) { // preloads images one at a time and executes callback when all images loaded 
    var parent = this;
    if ( objectIndex < parent.count ) {
      var img = new Image();
      var newIndex = objectIndex + 1;
      img.onload = function(){ 
        // console.log("preloaded:" + imgObject.images[ objectIndex ].src);
        parent.preloadImage( newIndex, imgObject, cb ); 
      }; // call this function again, once the current image is loaded, to load the next image
      var loadImgSrc = imgObject.images[objectIndex].src;
      img.src = imgObject.root + "" + loadImgSrc; // load image from this url
      // parent.preloadedImages.push( img );
    } else { // once all images have been loaded
      if ( cb != null && typeof cb == 'function' ) {
        cb(); // execute callback
      }
    }
    
  };
  
  // populate this.imgArr, then set this.slidesAreLoaded to true
  this.populateArray = function( imgObject ){
    for( i=0; i < parent.count; i++ ) {
//      console.log( "loading image:" + imgObject.images[i].src );
      var slideData = imgObject.images[i];
      if ( slideData.caption ) {
        slideCaption = slideData.caption;
      } else {
        slideCaption = '';
      }
      currentSlide = {
        'src': imgObject.root + slideData.src,
        'width': slideData.width,
        'height': slideData.height,
        'caption': slideCaption
      };
      parent.imgArr.push( currentSlide ); // push this slide onto this.imgArr
    }
    // once imgArr has been fully populated:
    parent.slidesAreLoaded = true;
  };
  
  // populate images array with preloaded images object, captions, and dimensions
  this.loadImages = function ( imgObject )
  {   
    this.count = imgObject.images.length; // total number of slides
//    console.log("loading images...");
    // scope
    var parent = this;
    makeArrayWhenImgLoaded = function(){
      parent.populateArray( imgObject );
    };
    // preload images one at a time, starting with the first
    this.preloadImage( 
      0, 
      imgObject, 
      makeArrayWhenImgLoaded
    );
    this.prevSlideId = parseInt( imgObject.images.length ) - 1;
  };
    
  // create the basic HTML for the slide show and prepend it to the specified container
  this.showContainer = function ( within, cb )
  {
  this.containerId = within;
       // JR - for modularity, removed most styles because slideshows might look different from each other.
        // also removed the shadowbox wrapper div, because not all slideshows will be within shadowboxes.
    var html = '\
      <div class="slideshow-container">\
      <div class="prev-slide" style="z-index: 2;">\
        <div class="image-holder"></div>\
        <p class="caption"><!-- / --></p>\
      </div>\
      <div class="current-slide" style="z-index: 1;">\
        <div class="image-holder" style=""></div>\
        <div class="caption-holder"><div class="ss-close-button"><span>close</span></div><p class="caption"><!-- / --></p> <div class="auto-play-button"><span>play</span></div> <div class="auto-pause-button"><span>pause</span></div><div class="next-button"><!-- --></div><div class="prev-button"><!-- --></div>\
        </div>\
      </div>\
      <div class="next-slide" style="z-index: 2;">\
        <div class="image-holder"></div>\
        <p class="caption"><!-- / --></p>\
      </div>';
        // JR - for modularity, moved the shadowbox setup to this.startSlideShow()
    $( within ).html( html );
    if ( cb != null && typeof cb == 'function' ) {
      cb(); // execute callback
    }
  };
  
  
  // if our current count is outside of the img array set it to beginning or end
  this.fixImgCount = function ()
  {
    /**
     * instead of using a modulo we're just going to force it to one end or the other
     * assuming if is it less than zero then a decrement was used
     * and if greater than the length than an increment was used
     */
    this.prevSlideId = this.imgCount - 1;
    this.nextSlideId = this.imgCount + 1;
    if( this.imgCount >= this.imgArr.length )
    {
      this.imgCount = 0;
      this.prevSlideId = this.imgArr.length - 1;
    }
    if( this.imgCount < 0 )
    {
      this.imgCount = ( this.imgArr.length - 1 );
      this.nextSlideId = 0;
    }
    
    this.surroundingSlides();
  };
  
  
  // sets properties containing the previous and next slides
  this.surroundingSlides = function () {
    if( this.imgArr[ this.nextSlideId ] == null )
    {
      this.nextSlideId = 0;
    }
    if( this.imgArr[ this.prevSlideId ] == null || this.prevSlideId == -1 )
    {
      this.prevSlideId = this.imgArr.length - 1;
    }
    this.prevSlide = this.imgArr[ this.prevSlideId ];
    this.nextSlide = this.imgArr[ this.nextSlideId ];
  };
  
  
  // the next two methods preload the previous and next slides' content.  
  this.loadPrevSlide = function ()
  {
    this.fixImgCount();
    $( this.containerId + ' .prev-slide .image-holder' ).html( '<img style="display: none;" class="slide-image" alt="' + this.imgArr[ this.prevSlideId ].caption + '" src="' + this.imgArr[ this.prevSlideId ].src + '" />' );
    $( this.containerId + ' .prev-slide .caption' ).html( this.imgArr[ this.prevSlideId ].caption );
  };
  
  this.loadNextSlide = function ()
  {
    this.fixImgCount();
    $( this.containerId + ' .next-slide .image-holder' ).html( '<img style="display: none;" class="slide-image" alt="' + this.imgArr[ this.prevSlideId ].caption + '" src="' + this.imgArr[ this.nextSlideId ].src + '" />' );
    $( this.containerId + ' .next-slide .caption' ).html( this.imgArr[ this.nextSlideId ].caption );
  };
  
  this.setSlide = function ( slideId )
  {
    this.imgCount = slideId;
    this.fixImgCount();
    $( this.containerId + ' .current-slide .image-holder' ).html( '<img class="slide-image" alt="' + this.imgArr[ this.imgCount ].caption + '" src="' + this.imgArr[ this.imgCount ].src + '" />' );
    $( this.containerId + ' .current-slide .caption' ).html( this.imgArr[ this.imgCount ].caption );
    // $( this.containerId + ' div:first').css('background','url('+this.imgArr[ this.imgCount ].src+') top left no-repeat');
  };
  
  this.adjustDimensions = function ( container )
  {
    for ( i in this.imgArr ) {
      // Get the height of the highest image and set it as the container's height
      var thisHeight = parseInt(this.imgArr[i].height);
      if ( thisHeight >  parseInt( $( this.containerId ).height() ) ) {
        $( container ).css('height', thisHeight );
      }
      // Same thing, with width
      var thisWidth = parseInt(this.imgArr[i].width);
      if ( thisWidth > parseInt( $( this.containerId ).width() ) ) {
        $( container ).css('width', thisWidth );
      }
    }
  };
  
  // automated slideshow
  this.autoPlay = function ( cb, parent )
  {
    //var iterator = parentObject;
    if( typeof cb == 'function' )
      {
        cb();
      }
    this.fixImgCount();
    
    $( this.containerId + ' .auto-play-button' ).css('display','none');
    $( this.containerId + ' .auto-pause-button' ).css('display','block');
    
    this.autoPlayTimeout = setTimeout( function ()
    {
      parent.jell.autoPlay( cb, parent );
    }, 5 * 1000 );
  };
  
  this.killAutoPlay = function ( keepNav )
  {
    clearTimeout( this.autoPlayTimeout );
    if ( keepNav == true ) {
      $( this.containerId + ' .auto-play-button' ).css('display','block');
      $( this.containerId + ' .auto-pause-button' ).css('display','none');
    }
  };
  
  // called when this.slidesAreLoaded is true
  this.slidesLoadedCallback = function( container, cb ) {
    if ( this.slidesAreLoaded == true ) {
      clearInterval( this.checkIfSlidesLoaded ); // stop checking
      this.showContainer( container, cb );
    }
  };
  
  this.init = function ( slideShowObject, container, cb ) {
    // preload images and populate this.imgArr
    this.loadImages( slideShowObject );
    var parentScope = this;
    
    // wait for images to be preloaded by checking every 10 millisec:
    this.checkIfSlidesLoaded = setInterval( function(){ parentScope.slidesLoadedCallback( container, cb ) }, 10 );
    
  };

}

/*
 *
 * Fading slideshow. startSlideShow accepts an argument, "mode." If set to "gapless" the slides fade in and out without a "gap" between each other
 *
 */

function fadingSlideShow () {
  
  // initialize generic slideshow object
  this.jell = new jellSlideshow();
  
  // set to a callback function to be executed once the slideshow is ready and loaded
  this.slideShowReady = false;
  
  // used for scope resolution in accessing own methods from within jQuery methods
  var parent = this;
  
  // default fade mode is w/ gap
  this.fadeMode = function ( direction ) {
    parent.switchSlide( direction );
  };
  
  this.startSlideShow = function( slideShowObj, container, mode, slideShowSpeed, readyCallback, startImg ) {
  //console.log("starting fadingSlideshow");
    this.slideShowReady = function() { readyCallback(); };
    
    this.jell.init( slideShowObj, container, function(){ parent.customizeSlideShow( container, startImg, mode, slideShowSpeed ) } );
  };
  
  this.customizeSlideShow = function( container, startImg, mode, slideShowSpeed ) {
    // set dimensions of container element(s) based on dimensions of widest and tallest image(s)
    this.jell.adjustDimensions( container + ', ' + container + ' .slideshow-container, ' + container + ' .prev-slide, ' + container + ' .current-slide, ' + container + ' .next-slide' );
    if ( mode == 'gapless' ) {
      this.fadeMode = function ( direction ) {
        parent.noGapSwitchSlide( direction );
      };
    }
    
    // preload prev-next slides
    this.jell.loadPrevSlide();
     this.jell.loadNextSlide();
    
    // show the first slide
    this.jell.setSlide(0);
    if ( startImg != null ) {
      this.jell.setSlide( startImg );
    }
    
    // positioning the caption box correctly i.e. overlaid on top of the slide image
    $( container + ' .caption-holder' ).css(
    {
      'position':'absolute',
      'bottom':'auto'
    });
    
    $( container + ' .current-slide .image-holder,' + container + ' .current-slide' ).css(
    {
      'position': 'absolute'
    });
    
    // hide the surroundnig slides
    $( this.jell.containerId + ' .prev-slide .image-holder *,' + this.jell.containerId + ' .next-slide .image-holder *' ).css({'position':'absolute'}); 
																							 // REMOVED .css({'display':'block','position':'absolute'}).fadeOut(0);
    $( this.jell.containerId + ' .current-slide .image-holder img' ).css('display','block');
    $( this.jell.containerId + ' .next-slide .caption,' + this.jell.containerId + ' .prev-slide .caption' ).css('display','none');
    // callback function
    this.slideShowReady();
    $( this.jell.containerId + ' .current-slide .caption-holder' ).appendTo( this.jell.containerId + ' .slideshow-container' );

      $( parent.jell.containerId + ' .next-slide, ' +  parent.jell.containerId + ' .next-slide .image-holder img, ' + parent.jell.containerId + ' .prev-slide, ' +  parent.jell.containerId + ' .prev-slide .image-holder img' ).css({'position':'absolute','display':'block'}).fadeTo( 0, 0 );
  }
  
  
  // default slide fade; "direction" can be "next" or "prev"
  this.switchSlide = function ( direction ) {
    // fadeout current slide
    $( parent.jell.containerId + ' .caption-holder .caption,' + parent.jell.containerId + ' .current-slide .image-holder *' ).fadeOut( 250 );
    $( parent.jell.containerId + ' .current-slide .image-holder' ).fadeOut( 350, function ()
      {
        // replace content of current slide (While it&#146;s hidden) with content of the hidden next/prev slides
      $( parent.jell.containerId + ' .caption-holder .caption' ).html($( parent.jell.containerId + ' .' + direction + '-slide .caption' ).html());
      $( parent.jell.containerId + ' .current-slide .image-holder' ).html($( parent.jell.containerId + ' .' + direction + '-slide .image-holder' ).html());
    
    // update current slide content
	
    $( parent.jell.containerId ).css( 'background-image', 'url(' + parent.jell.imgArr[ parent.jell.imgCount ].src + ')' );

    parent.jell.setSlide( parent.jell.imgCount );
    
    // preload surrounding slides
      parent.jell.loadPrevSlide();
      parent.jell.loadNextSlide();
    
    // show current slide  
        $( parent.jell.containerId + ' .current-slide .image-holder' ).fadeIn( 350, function()
        {
			
      $( parent.jell.containerId + ' .caption-holder .caption,' + parent.jell.containerId + ' .current-slide .image-holder *' ).fadeIn( 250 );
        });
    });
  };
  
  // gapless slide fade; "direction" can be "next" or "prev"
  this.noGapSwitchSlide = function ( direction ) {
    parent.jell.fixImgCount();

	
	
    $( parent.jell.containerId ).css( 'background-image', 'url("' + parent.jell.imgArr[ parent.jell.imgCount ].src + '")' );
	
  //  $( parent.jell.containerId ).css( {'background-image': 'url(' + parent.jell.imgArr[ parent.jell.imgCount ].src + ')','background-repeat': 'no-repeat'} );
    if ( parent.jell.imgArr[ parent.jell.imgCount ].caption != '' ) {
      fadeCaption = true;
    } else {
      fadeCaption = false;
    }
    // fade in selected slide
    $( parent.jell.containerId + ' .' + direction + '-slide, ' +  parent.jell.containerId + ' .' + direction + '-slide .image-holder img' ).fadeTo( 500, 1, function(){
      // fade out current slide
      if ( fadeCaption == true ) {
        $( parent.jell.containerId + ' .caption-holder .caption' ).fadeOut( 150 );
      }

      $( parent.jell.containerId + ' .current-slide .image-holder' ).fadeTo( 150, 0, function(){
      // show current slide  
      // update current slide content      
      $( parent.jell.containerId ).css( {'background-image': 'url(' + parent.jell.imgArr[ parent.jell.imgCount ].src + ')','background-repeat': 'no-repeat'} );
      parent.jell.setSlide( parent.jell.imgCount );
      $( parent.jell.containerId + ' .' + direction + '-slide, ' +  parent.jell.containerId + ' .' + direction + '-slide .image-holder img' ).fadeTo( 0, 0 );
      
      // preload surrounding slides
      parent.jell.loadPrevSlide();
      parent.jell.loadNextSlide();
      $( parent.jell.containerId + ' .current-slide .image-holder *, ' + parent.jell.containerId + ' .current-slide .image-holder' ).fadeTo( 0, 1 );

      $( parent.jell.containerId + ' .image-holder img' ).css({'display':'block','position':'absolute'});
      
        if ( fadeCaption == true ) {
          $( parent.jell.containerId + ' .caption-holder .caption' ).html( parent.jell.imgArr[ parent.jell.imgCount ].caption ).fadeIn( 250 );
        }
      });
    });
  };
  
  this.nextSlide = function () {
    this.jell.imgCount++;

    // call to switchSlide or noGapSwitchSlide
    this.fadeMode( 'next' );
  };
  
  this.prevSlide = function () {
    this.jell.imgCount--;
    this.fadeMode( 'prev' );
  };
  
}

// Shadowbox slideshow
function shadowSlideShow () {
  
  this.jell = new jellSlideshow();
  var parent = this;
  this.slideShowReady = false;
  
  this.startSlideShow = function( slideShowObj, slideShowSpeed, readyCallback, startImg ) {
    this.slideShowReady = function() 
    { 
      readyCallback();
      this.slideShowReady = function() {};
    };
    fadeBG.fadeInBg( function()
    {
      var html = '\
        <div id="shadow-slideshow-contain-wrap">\
        </div>';
      $( 'body' ).prepend( html );
      parent.jell.showContainer( '#shadow-slideshow-contain-wrap' );
      var top = (( winDim.getHeight() / 2 ));   
      $( '#shadow-slideshow-contain-wrap .slideshow-container' ).css({
        'float': 'left', 
        'background-color': '#000000', 
        'position': 'absolute', 
        'z-index': 15, 
        'overflow': 'visible !important',
        'height': '0px',
        'width': '0px',
        'top': top + 'px',
        'left': '50%'
      });
      
      $('#shadow-slideshow-contain-wrap .ss-close-button').css('display','block');
       
      parent.jell.loadImages( slideShowObj );
      
      if ( startImg != null ) {
        parent.jell.imgCount = startImg;
      }
      
      parent.jell.loadNextSlide();
      parent.jell.loadPrevSlide();
      parent.fadeCurrentSlide(  );
      
      
      $( '#fade_bg' ).live('click', function() { 
         parent.endSlideShow(); 
      });
      
    });
    //});
  };
  
  this.fadeCurrentSlide = function(  )
  {
    parent.adjustContainer( function() {
        $( parent.jell.containerId + ' .current-slide .image-holder' ).fadeTo( 350,1, function()
        {
          $( parent.jell.containerId + ' .current-slide .caption-holder' ).fadeTo( 250,1 );
        });
      },function()
      {
        $( '#shadow-slideshow-contain-wrap .current-slide .image-holder' ).fadeTo( 250, .01 );
        $('#shadow-slideshow-contain-wrap .current-slide .caption-holder').fadeTo( 250, .01, function()
        {
          $( '#shadow-slideshow-contain-wrap .current-slide .image-holder' ).css('position','absolute');
          parent.jell.setSlide( parent.jell.imgCount );
          parent.slideShowReady();
        });
      });
  };
  
  this.adjustContainer = function ( cb, cf )
  {
    var img = parent.jell.imgArr[parent.jell.imgCount];
      if( typeof cf == 'function' )
      {
        cf();
      }
    var marg = -1 * ( img.width / 2 );
    var top = winDim.getScrollTop() + ( winDim.getHeight() / 2 ) - ( img.height / 2 );
    //*
    $( '#shadow-slideshow-contain-wrap .slideshow-container' ).animate( { 
      'width': img.width, 
      'height': img.height, 
      'marginLeft': marg, 
      'top': top 
    }, 550, function () { 
    $( '#shadow-slideshow-contain-wrap .current-slide .caption-holder' ).css(
    {
      'position':'absolute',
      'bottom':'auto',
      'marginTop': ( img.height ) - ( $('#shadow-slideshow-contain-wrap .current-slide .caption-holder').outerHeight()  )
    }); //*/
      if( typeof cb == 'function' )
      {
        cb();
      }
    });
  };
  
  this.nextSlide = function ()
  {

    parent.jell.imgCount++;
    parent.jell.fixImgCount();
    parent.fadeCurrentSlide( parent.jell.nextSlide );
          parent.jell.loadPrevSlide();
          parent.jell.loadNextSlide();
  };
  
  this.prevSlide = function ()
  {
    this.jell.imgCount++;
    this.jell.fixImgCount();
    this.fadeCurrentSlide( this.jell.prevSlide );
          parent.jell.loadPrevSlide();
          parent.jell.loadNextSlide();
  };
  
  
  this.endSlideShow = function() {
  $( '#shadow-slideshow-contain-wrap' ).fadeOut(350,function()
  {
    $( '#shadow-slideshow-contain-wrap' ).remove();
    fadeBG.fadeOutBg();
    parent.jell.imgCount = 0;
  });
  };
}

function slidingSlideShow () {
  
  this.slideShowReady = false;
  this.jell = new jellSlideshow();
    var parent = this;
  
  this.startSlideShow = function( slideShowObj, container, slideShowSpeed, readyCallback, startImg ) {
    var parent = this;
    this.slideShowReady = function() { readyCallback(); };
    this.jell.init( slideShowObj, container );
    //this.bindEvents();
    
    $( container ).wrapInner('<div class="slide-container" />');
    
    
    this.jell.adjustDimensions( container + ',' + container + ' .slide-container,' + container + ' .current-slide .image-holder' );
    
    $( container + ' .caption-holder' ).css({
//      'overflow': 'visible',
      'width': $( container ).width(),
      'marginTop': $( container + ' .slide-container' ).height() - $( container + ' .caption-holder' ).outerHeight()
    });
    var newWidth = ( $( container + ' .slideshow-container' ).width() * (this.jell.imgArr.length + 1 ) );
    $( container + ' .slideshow-container' ).css({
      'width': newWidth,
      'marginLeft':  ( -1 * $( container + ' .slide-container' ).width() )
    });
    $( container + ', ' + container + ' .slide-container' ).css({
      'overflow': 'hidden'
    });
    this.jell.loadPrevSlide();
     this.jell.loadNextSlide();
    
    this.jell.setSlide(0);
      if ( startImg != null ) {
        this.jell.setSlide(startImg);
      }
    this.prepareSurroundingSlides();
      $( this.jell.containerId + ' .current-slide .caption-holder' ).prependTo( this.jell.containerId + ' .slide-container' );
    this.slideShowReady();
  };
  
  this.prepareSurroundingSlides = function()
  {
    $( this.jell.containerId + ' .prev-slide,' + this.jell.containerId + ' .next-slide,' + this.jell.containerId + ' .current-slide,' + this.jell.containerId + ' .image-holder' ).css({
      'display': 'block',
        'float': 'left',
        'width': $( parent.jell.containerId ).width(),
        'text-align': 'left'
      });
      $( this.jell.containerId + ' .slideshow-container' ).css({
        'marginLeft':  ( -1 * $( parent.jell.containerId + ' .slide-container' ).width() )
    });
      $( this.jell.containerId + ' .image-holder img' ).css('display','inline');
  };
  
  this.slideSwitch = function( slideId )
  {
    this.jell.setSlide( slideId );
    this.jell.loadPrevSlide();
     this.jell.loadNextSlide();
    this.prepareSurroundingSlides();
  };
  
  this.nextSlide = function() 
  {
    $( parent.jell.containerId + ' .caption-holder .caption' ).fadeOut(250,function(){
      $( parent.jell.containerId + ' .caption-holder .caption' ).html( $( parent.jell.containerId + ' .next-slide .caption' ).html() );
      $( parent.jell.containerId + ' .slideshow-container' ).animate({
        'marginLeft': ( -1 * ( $( parent.jell.containerId ).width() * 2 ) )
      },400,function(){
        $( parent.jell.containerId + ' .caption-holder .caption' ).fadeIn(250);
        parent.jell.imgCount++;
        parent.slideSwitch( parent.jell.imgCount );
      });
    });
  };
  
  this.prevSlide = function() 
  {
    $( parent.jell.containerId + ' .caption-holder .caption' ).fadeOut(250,function(){
      $( parent.jell.containerId + ' .caption-holder .caption' ).html( $( parent.jell.containerId + ' .prev-slide .caption' ).html() );
      $( parent.jell.containerId + ' .slideshow-container' ).animate({
        'marginLeft': 0
      },400,function(){
        $( parent.jell.containerId + ' .caption-holder .caption' ).fadeIn(250);
        parent.jell.imgCount--;
        parent.slideSwitch( parent.jell.imgCount );
      });
    });
  };
  
}

//*/
winDim = {
  // uses jQuery to return the distance the window has been scrolled down.
  getScrollTop: function ()
  {
    return $(window).scrollTop();
  },
  // gets the full height of the window, including parts not seen
  getDocHeight: function ()
  {
    var db = document.body;
    var de = document.documentElement;
    return Math.max(
      Math.max(db.scrollHeight, de.scrollHeight),
      Math.max(db.offsetHeight, de.offsetHeight),
      Math.max(db.clientHeight, de.clientHeight)
    );
  },
  // may or may not include the scroll bar on the right
  getWidth: function ()
  {
    var x = 0;
    if (self.innerHeight) {
      x = self.innerWidth;
    } else if (document.documentElement && document.documentElement.clientHeight) {
      x = document.documentElement.clientWidth;
    } else if (document.body) {
      x = document.body.clientWidth;
    }
    return x;
  }, // end get wid
  // gets the window frame instead of the document height
  getHeight: function ()
  {
    var y = 0;
    if (self.innerHeight) {
      y = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) {
      y = document.documentElement.clientHeight;
    } else if (document.body) {
      y = document.body.clientHeight;
    }
    return y;
  } // end get ht
}; // end winDim


function customSlideShow () {
  
  // initialize generic slideshow object
  this.jell = new jellSlideshow();
  
  // set to a callback function to be executed once the slideshow is ready and loaded
  this.slideShowReady = false;
  
  // used for scope resolution in accessing own methods from within jQuery methods
  var parent = this;
  
  // contains captions with HTML added
  var captionsHtml = [];
  
  this.slideChanging = false;
  
  
  this.startSlideShow = function( slideShowObj, container, slideShowSpeed, readyCallback, startImg ) {
    this.slideShowReady = function() { readyCallback(); };
    this.slideChanging = false;
    
    this.jell.init( slideShowObj, container, function(){ parent.customizeSlideShow( container, startImg ) } );
    
  };
  
  // bind events, adjust container, manipulate DOM, etc
  this.customizeSlideShow = function( container, startImg ) {
  
    // loop through captions in imgArr, edit them by wrapping them with HTML and push them onto the captionsHtml array
    jQuery.each( this.jell.imgArr, function( index, value ) {
      var slideSlug = homeSlideShowImg.images[ index ].slug; // get slide's slug from img object
      captionsHtml.push( '<span class="slide-caption-title">' + value.caption + '</span> | <a href="/work/project/all/' + slideSlug + '" class="details">view details</a>' ); // format caption html
    });

    // set dimensions of container element(s) based on dimensions of widest and tallest image(s)
    this.jell.adjustDimensions( container + ', ' + container + ' .slideshow-container, ' + container + ' .prev-slide, ' + container + ' .current-slide, ' + container + ' .next-slide' );
    
    
    // show the first slide
    if ( startImg != null ) {
      this.jell.setSlide( startImg );
    } else {
      startImg = 0;
      this.jell.setSlide(0);
    }
    
    // preload prev-next slides
    this.jell.loadPrevSlide();
    this.jell.loadNextSlide();
    
    var captionHolder = container + ' .caption-holder';
    
    // hide the surroundnig slides
    $( this.jell.containerId + ' .prev-slide,' + this.jell.containerId + ' .prev-slide .image-holder *,' + this.jell.containerId + ' .prev-slide .image-holder,' + this.jell.containerId + ' .next-slide,' + this.jell.containerId + ' .next-slide .image-holder *,' + this.jell.containerId + ' .next-slide .image-holder' ).css( {'display':'block','position':'absolute','height':$( parent.jell.containerId ).height(),'width':$( parent.jell.containerId ).width()}).hide();
    
    
    $( this.jell.containerId + ' .next-slide .caption,' + this.jell.containerId + ' .prev-slide .caption' ).css('display','none');
    // callback function
      this.slideShowReady();
    $( captionHolder ).wrap( '<div class="caption-slideup-container" style="z-index: 4; position: absolute; margin-top: ' + ($( container + ' .slideshow-container' ).height() - 48 ) + 'px; width: ' + $( captionHolder ).outerWidth() + 'px; height: ' + $( captionHolder ).outerHeight() + 'px; overflow: hidden;" />');
    $ ( container + ' .caption-slideup-container' ).appendTo( container + ' .slideshow-container' );
    $( captionHolder).css(
        {
      'position':'static',
      'marginTop':$( captionHolder ).outerHeight()
    });
    $( captionHolder + ' .caption').css('z-index',5).wrap('<div class="caption-wrapper" />');
    
    // set slide's caption to the adjusted HTML caption
    $( captionHolder + ' .caption' ).html( captionsHtml[ startImg ] );
    
    $( container + ' .current-slide .image-holder,' + container + ' .current-slide' ).css(
    {
      'position': 'absolute'
    });
      var visibleCaption = false;
      $( container ).hover(function(){
          $( container + ' .caption-holder' ).stop( true, false ).animate(
            { 'marginTop': 0 },
            350,
            function()
            { 
              visibleCaption = true;
            }
          );
        },function(){
          $( container + ' .caption-holder' ).stop( true, false ).show().animate(
            { 'marginTop': $( container + ' .caption-holder' ).outerHeight() },
              250,
              function()
              { 
                visibleCaption = false;
              }
            );
        //  
      });
      var mouseCoords = function(ev) {
        ev = ev || window.event;
        if ( ev.pageX || ev.pageY ) {
          var mousePos = {
            x: ev.pageX,
            y: ev.pageY
          };
         
        } else {
          var mousePos = {
            x: ev.clientX + document.body.scrollLeft - document.body.clientLeft,
            y: ev.clientY + document.body.scrollTop - document.body.clientTop
          };
        }
        return mousePos;
      };
      var captionCoords = {
        topX: $(container + ' .caption-slideup-container').offset().left,
        topY: $(container + ' .caption-slideup-container').offset().top,
        btmX: $(container + ' .caption-slideup-container').offset().left + $(container + ' .caption-slideup-container').width(),
        btmY: $(container + ' .caption-slideup-container').offset().top + $(container + ' .caption-slideup-container').height()
      };
      var mouseOverCaption = false;
      var resumeSlideShow;
      $(document).mousemove(function(e){
        mp = mouseCoords(e);
        if ( mp.x >= captionCoords.topX && mp.x < captionCoords.btmX && mp.y >= captionCoords.topY && mp.y < captionCoords.btmY ) {
          if ( mouseOverCaption == false && visibleCaption == true ) {
            parent.jell.killAutoPlay(true);
            clearTimeout( resumeSlideShow );
            mouseOverCaption = true;
          }
        } else {
          if ( mouseOverCaption == true && visibleCaption == true ) {
            resumeSlideShow = setTimeout( function(){parent.jell.autoPlay( function() { parent.nextSlide(); }, parent )}, 3 * 1000 );
            mouseOverCaption = false;
          }
        
        }
      });
  };
  
  // gapless slide fade; "direction" can be "next" or "prev"
  this.noGapSwitchSlide = function ( direction ) {
  if ( this.slideChanging == false ) {
    parent.jell.fixImgCount();
    $( parent.jell.containerId ).css( 'background-image', 'url("' + parent.jell.imgArr[ parent.jell.imgCount ].src + '")' );
    $( parent.jell.containerId + ' .' + direction + '-slide, ' +  parent.jell.containerId + ' .' + direction + '-slide .slide-image,'  +  parent.jell.containerId + ' .' + direction + '-slide .image-holder ').css({'display':'block','height':$( parent.jell.containerId ).height(),'width':$( parent.jell.containerId ).width()}).hide().fadeIn( 750);//,function(){    
    // fade out current slide
      //
    $( parent.jell.containerId + ' .caption-holder .caption').fadeOut(400,function(){
    
    this.slideChanging = true;

    });
    $( parent.jell.containerId + ' .current-slide .image-holder' ).fadeOut( 750,function(){
      parent.jell.setSlide( parent.jell.imgCount );
    
    // preload surrounding slides
      parent.jell.loadPrevSlide();
      parent.jell.loadNextSlide();
              //$( parent.jell.containerId + ' .caption-holder .caption' ).html( parent.jell.imgArr[ parent.jell.imgCount ].caption ).hide();
              $( parent.jell.containerId + ' .caption-holder .caption' ).html( captionsHtml[ parent.jell.imgCount ] ).hide();
      $( parent.jell.containerId + ' .caption-holder .caption' ).fadeIn(400);

        
      this.slideChanging = false;
    $( parent.jell.containerId + ' .current-slide .slide-image, ' + parent.jell.containerId + ' .current-slide .image-holder' ).fadeIn( 0, function(){
    });
    } );
  }
  };
  
  this.nextSlide = function () {
    this.jell.imgCount++;
    this.noGapSwitchSlide( 'next' );
  };
  
  this.prevSlide = function () {
    this.jell.imgCount--;
    this.noGapSwitchSlide( 'prev' );
  };
  
}

// Argument is an object containing options for the slideshow.
function slideShow ( _slideShowOptions )
{
  
  var parentObject = this;
  
  this.slideShowStart = function ( cb ) {
    return false;
  };
  
  this.slideShowObject = null;
  
  // Default values below.
  this.slideShowOptions = {
    slideShowContents: null, // slides
    slideShowType: null, // whatever
    slideShowContainer: null,
    transitionMode: null, // or gapless - fading slideshows only
    autoPlay: false,
    startSlide: 0,
    showButtons: 'all', // or 'none', 'nav', 'play'
    clickEvent: null, // or a function to execute whenever the current slide's image is clicked
    slideShowSpeed: 500 // in milliseconds
  };
  
  
  jQuery.each( parentObject.slideShowOptions, function( name, value ) {
    if ( _slideShowOptions[name] == null ) {
      parentObject.slideShowOptions[name] = value;
    } else {
      parentObject.slideShowOptions[name] = _slideShowOptions[name];
    }
    //cl ( name + ': ' + parentObject.slideShowOptions[name] );
  });
 
  switch ( this.slideShowOptions.slideShowType ) {
    default:
    case 'fading':
      parentObject.slideShowObject = new fadingSlideShow();
      parentObject.slideShowStart = function ( cb ) 
      {
        parentObject.slideShowObject.startSlideShow( parentObject.slideShowOptions.slideShowContents, parentObject.slideShowOptions.slideShowContainer, parentObject.slideShowOptions.transitionMode, parentObject.slideShowOptions.slideShowSpeed, function() { parentObject.afterInit( cb ) }, parentObject.slideShowOptions.startSlide );
      };
      break;
    case 'customFade':
      parentObject.slideShowObject = new customSlideShow();
      parentObject.slideShowStart = function (  ) 
      {
              parentObject.slideShowObject.startSlideShow( parentObject.slideShowOptions.slideShowContents, parentObject.slideShowOptions.slideShowContainer, parentObject.slideShowOptions.slideShowSpeed, function(){ parentObject.afterInit(); }, parentObject.slideShowOptions.startSlide );
      };
      break;
    case 'sliding':
      parentObject.slideShowObject = new slidingSlideShow();
      parentObject.slideShowStart = function (  ) 
      {
        parentObject.slideShowObject.startSlideShow( parentObject.slideShowOptions.slideShowContents, parentObject.slideShowOptions.slideShowContainer, parentObject.slideShowOptions.slideShowSpeed, function(){ parentObject.afterInit(); }, parentObject.slideShowOptions.startSlide );
      };
      break;
    case 'shadow':
      parentObject.slideShowObject = new shadowSlideShow();
      parentObject.slideShowStart = function (  ) 
      {
        parentObject.slideShowObject.startSlideShow( parentObject.slideShowOptions.slideShowContents, parentObject.slideShowOptions.slideShowSpeed, function(){ parentObject.afterInit(); }, parentObject.slideShowOptions.startSlide );
      };
      break;
  }
  
  
  this.makeNav = function ()
  {
    var parent = parentObject.slideShowObject;
    if ( parentObject.slideShowOptions.showButtons == 'all' || parentObject.slideShowOptions.showButtons == 'play' || parentObject.slideShowOptions.autoPlay == true ) {
      var keepNav = true;
      $( parent.jell.containerId + ' .auto-play-button' ).css('display','block').live( 'click', function (ev)
      {
        ev.preventDefault();
        parent.jell.autoPlay( function() { parent.nextSlide(); }, parent );
      });
    } else {
      var keepNav = false;
    }
    $( parent.jell.containerId + ' .auto-pause-button' ).css('display','none').live( 'click', function (ev)
    {
      ev.preventDefault();
       parent.jell.killAutoPlay(true);
    });
    if ( parentObject.slideShowOptions.showButtons == 'all' || parentObject.slideShowOptions.showButtons == 'nav' ) {
      $( parent.jell.containerId + ' .next-button' ).css('display','block').live( 'click', function (ev)
      {
        ev.preventDefault();
        parent.jell.killAutoPlay(keepNav);
        parent.nextSlide();
      });
      $( parent.jell.containerId + ' .prev-button' ).css('display','block').live( 'click', function (ev)
      {
        ev.preventDefault();
        parent.jell.killAutoPlay(keepNav);
        parent.prevSlide( );
      });
    }
    $(  parent.jell.containerId + ' .ss-close-button' ).live( 'click', function (ev)
    {
      ev.preventDefault();
      parent.jell.killAutoPlay(keepNav);
      if ( parentObject.slideShowOptions.slideShowType == 'shadow' ) {
        parent.endSlideShow();
      }
    });
    if ( parentObject.slideShowOptions.clickEvent != null ) {
      $(  parent.jell.containerId + ' .current-slide img' ).live( 'click', function ()
      {
      var slideData = parent.jell.imgCount;
        parentObject.slideShowOptions.clickEvent( slideData );
      });
    }
  };
  
  this.afterInit = function( cb ) {
    parentObject.makeNav();
    cl ( parentObject.slideShowObject.jell.containerId + ': ready.' );
    if ( parentObject.slideShowOptions.autoPlay == true ) {
//      parentObject.slideShowObject.jell.imgCount = ( 0 );
      var autoPlayTimeout = setTimeout( 
        function(){
          parentObject.slideShowObject.jell.autoPlay( function(){
            parentObject.slideShowObject.nextSlide()
          }, parentObject.slideShowObject ) 
        }, 2000 );
      
    }
    if ( typeof cb  == "function" ) {
      cb();
    }
  };
  
  this.init = function ( cb ) {
    parentObject.slideShowStart( cb );
//    console.log("initiating");
  };

};

