/**
 *  Lightbox Extension
 *
 *  this file extends the lightbox script with
 *    - slideshow functionality
 *    - and navigational elements moved to bottomNav container
 *
 *  @author:  tommy(at)profi(dot)it
 *  @since:   05.09.2008 15:57:35
 *
 */

var Lightbox = Class.create(Lightbox, {
  // new property determines, if slideshow is running
  slideshowRun: false,
  // added slideshow timer property
  slideshowTimer: undefined,

  initialize: function($super) {
    // call super class method
    $super();

    // modify controls
    this.modifyControls();
    // add new observers for new or modified controls
    this.addControlObservers();
    // add controls to object scope, this will make the controls accessable by this.[controlName].[property]
    this.controlsToObject();
  },

  /**
   * modifies controls of the lightbox skeleton
   *
   */
  modifyControls: function() {
    // remove original prevLink and nextLink elements
    $$('#prevLink, #nextLink').invoke('remove');
    // insert slideshow, previous and next text links and replace the close link image with a text label
    $('bottomNav').insertBefore(Builder.node('a', { id: 'slideshowLink', href: '#' }, LightboxOptions.labelSlideshowStart), $('bottomNavClose'));
    $('bottomNav').insertBefore(Builder.node('a', { id: 'prevLink', href: '#' }, LightboxOptions.labelPrevious), $('bottomNavClose'));
    $('bottomNav').insertBefore(Builder.node('a', { id: 'nextLink', href: '#' }, LightboxOptions.labelNext), $('bottomNavClose'));
    $('bottomNavClose').update(LightboxOptions.labelClose);
  },

  /**
   * add observers to new controls
   *
   */
  addControlObservers: function() {
		// added slideshowLink observer
		$('slideshowLink').observe('click', (function(event) { event.stop(); this.slideShow(); }).bind(this));
		// need to specify this here, in order we remove the original elements and create new ones
		$('prevLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage - 1); }).bindAsEventListener(this));
		$('nextLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage + 1); }).bindAsEventListener(this));
  },

  /**
   * moves controls to object scope, to make them accessible via this.[controlName].[property]
   *
   */
  controlsToObject: function() {
    var th = this;
    (function() {
        var ids = 'slideshowLink';
        $w(ids).each(function(id){ th[id] = $(id); });
    }).defer();
  },

  /* maybe we need to override this method because lightboxTop is not centered */
  //
  //  start()
  //  Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
  //
  start: function(imageLink) {

      $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'hidden' });

      // stretch overlay to fill page and fade in
      var arrayPageSize = this.getPageSize();
      $('overlay').setStyle({ width: arrayPageSize[0] + 'px', height: arrayPageSize[1] + 'px' });

      new Effect.Appear(this.overlay, { duration: this.overlayDuration, from: 0.0, to: LightboxOptions.overlayOpacity });

      this.imageArray = [];
      var imageNum = 0;

      if ((imageLink.rel == 'lightbox')){
          // if image is NOT part of a set, add single image to imageArray
          this.imageArray.push([imageLink.href, imageLink.title]);
      } else {
          // if image is part of a set..
          this.imageArray =
              $$(imageLink.tagName + '[href][rel="' + imageLink.rel + '"]').
              collect(function(anchor){ return [anchor.href, anchor.title]; }).
              uniq();

          while (this.imageArray[imageNum][0] != imageLink.href) { imageNum++; }
      }

      // calculate top and left offset for the lightbox
      var arrayPageScroll = document.viewport.getScrollOffsets();
      //var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 10);
      // upper lightbox edge sticks at upper viewport edge...
      var lightboxTop = arrayPageScroll[1]; // + ((arrayPageScroll[1] - this.lightbox.getHeight()) / 2);
      var lightboxLeft = arrayPageScroll[0];
      this.lightbox.setStyle({ top: lightboxTop + 'px', left: lightboxLeft + 'px' }).show();

      this.changeImage(imageNum);
  },

  /**
   * overridden changeImage method
   *
   */
  changeImage: function(imageNum) {
    this.activeImage = imageNum; // update global var

    // hide elements during transition
    if (LightboxOptions.animate) this.loading.show();
    this.lightboxImage.hide();
    this.hoverNav.hide();
    this.prevLink.hide();
    this.nextLink.hide();
    // added hiding of slideshow link - tommy@profi.it 19.08.2008 16:25:46
    this.slideshowLink.hide();

    // HACK: Opera9 does not currently support scriptaculous opacity and appear fx
    this.imageDataContainer.setStyle({opacity: .0001});
    this.numberDisplay.hide();

    var imgPreloader = new Image();

    // once image is preloaded, resize image container

    imgPreloader.onload = (function(){
      // set img element src
      this.lightboxImage.src = this.imageArray[this.activeImage][0];

      // check if size of image + border + data container height is taller than viewport size
      var overallSize = imgPreloader.height + (LightboxOptions.borderSize * 2) + $('imageDataContainer').getHeight();
      if (overallSize > document.viewport.getHeight())
      {
        var oldHeight = imgPreloader.height;
        this.lightboxImage.height = imgPreloader.height = document.viewport.getHeight() - (LightboxOptions.borderSize * 2) - $('imageDataContainer').getHeight();
        this.lightboxImage.width = imgPreloader.width = imgPreloader.width / (oldHeight / imgPreloader.height);
      }
      // else, reset to constraints of image
      else
      {
        this.lightboxImage.height = imgPreloader.height;
        this.lightboxImage.width = imgPreloader.width;
      }

      this.resizeImageContainer(imgPreloader.width, imgPreloader.height);
    }).bind(this);
    imgPreloader.src = this.imageArray[this.activeImage][0];
  },

  /**
   * overridden updateNav method
   *
   */
  updateNav: function($super) {
    $super();

    // keep prev and next link elements hidden if slideshow is still running...
    if (this.slideshowRun)
    {
      this.prevLink.hide();
      this.nextLink.hide();
    }

    // added displaying of slideshowLink()
    if (this.imageArray.length > 1) this.slideshowLink.show();
  },

  /**
   * overridden resizeImageContainer method
   *
   */
  resizeImageContainer: function(imgWidth, imgHeight) {
    // get current width and height
    var widthCurrent  = this.outerImageContainer.getWidth();
    var heightCurrent = this.outerImageContainer.getHeight();

    // get new width and height
    var widthNew  = (imgWidth  + LightboxOptions.borderSize * 2);
    var heightNew = (imgHeight + LightboxOptions.borderSize * 2);

    // scalars based on change from old to new
    var xScale = (widthNew  / widthCurrent)  * 100;
    var yScale = (heightNew / heightCurrent) * 100;

    // calculate size difference between new and old image, and resize if necessary
    var wDiff = widthCurrent - widthNew;
    var hDiff = heightCurrent - heightNew;

    if (hDiff != 0) new Effect.Scale(this.outerImageContainer, yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'});
    if (wDiff != 0) new Effect.Scale(this.outerImageContainer, xScale, {scaleY: false, duration: this.resizeDuration, delay: this.resizeDuration});

    // if new and old image are same size and no scaling transition is necessary,
    // do a quick pause to prevent image flicker.
    var timeout = 0;
    if ((hDiff == 0) && (wDiff == 0)){
        timeout = 100;
        if (Prototype.Browser.IE) timeout = 250;
    }

    (function(){
        // this is not needed any more, because we don't display the links in the hoverNav,
        // instead we make a text link navigation in the bottom area
        //this.prevLink.setStyle({ height: imgHeight + 'px' });
        //this.nextLink.setStyle({ height: imgHeight + 'px' });
        this.imageDataContainer.setStyle({ width: widthNew + 'px' });

        this.showImage();
    }).bind(this).delay(timeout / 1000);
  },

  /**
   * overriden showImage method
   *
   */
  /*
  showImage: function($super) {
    $super();

    // calculate top and left offset for the lightbox
    var arrayPageScroll = document.viewport.getScrollOffsets();
    //var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 10);
    var lightboxTop = arrayPageScroll[1] + ((arrayPageScroll[1] - this.lightbox.getHeight()) / 2);
    var lightboxLeft = arrayPageScroll[0];
    this.lightbox.setStyle({ top: lightboxTop + 'px', left: lightboxLeft + 'px' }).show();
  },
  */

  end: function($super) {
    // call super class method
    $super();
    // toggle slideshow if its running...
    if (this.slideshowRun)
    {
      this.slideShow();
    }
  },

  /**
   * new method: slide show functionality
   *
   */
  slideShow: function() {
    // start slideshow
    if (!this.slideshowRun)
    {
      this.slideshowRun = true;
      this.slideshowLink.update(LightboxOptions.labelSlideshowStop);
      // hide prev/next links
      this.prevLink.hide();
      this.nextLink.hide();

      // create timer
      this.slideshowTimer = new PeriodicalExecuter(function(pe) {
        this.showNext();
        //pe.stop();
      }.bind(this), LightboxOptions.slideShowTimeout);
    }
    // stop slideshow
    else
    {
      this.slideshowRun = false;
      this.slideshowLink.update(LightboxOptions.labelSlideshowStart);
      // show prev/next links
      this.prevLink.show();
      this.nextLink.show();

      // destroy timer
      if (this.slideshowTimer)
        this.slideshowTimer.stop();
    }
  },

  /**
   * new method: show next image in list (slideshow functionality)
   *
   */
  showNext: function() {
    if (this.imageArray.length > 1)
    {
      // loop condition:
      // stop slideshow, if no loop defined AND active image is last one in imageArray and startImage is 0 OR activeImage + 1 equals startImage
      /*
      if (!this.options.get('loop') && ((this.activeImage == this.imageArray.length - 1 && this.startImage == 0) || (this.activeImage + 1 == this.startImage)))
      {
        return this.end();
      }
      */

      if (this.activeImage == this.imageArray.length - 1)
      {
        this.changeImage(0);
      }
      else
      {
        this.changeImage(this.activeImage + 1);
      }
    }
  }
});
