// -----------------------------------------------------------------------------------
//
// Lightbox Slideshow v1.1
// by Justin Barkhuff - http://www.justinbarkhuff.com/lab/lightbox_slideshow/
//  Updated: 2007-08-15
//
// Largely based on Lightbox v2.02
// by Lokesh Dhakar - http://huddletogether.com/projects/lightbox2/
// 3/31/06
//
// Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
//
// The code inserts html at the bottom of the page that looks similar to this:
//
// <div id="overlay"></div>
// <div id="lightbox">
//  <div id="outerImageContainer">
//   <div id="imageContainer">
//    <img id="lightboxImage" />
//    <div id="hoverNav">
//     <a href="javascript:void(0);" id="prevLinkImg">&laquo; prev</a>
//     <a href="javascript:void(0);" id="nextLinkImg">next &raquo;</a>
//    </div>
//    <div id="loading">
//     <a href="javascript:void(0);" id="loadingLink">loading</a>
//    </div>
//   </div>
//  </div>
//  <div id="imageDataContainer">
//   <div id="imageData">
//    <div id="imageDetails">
//     <span id="caption"></span>
//     <span id="numberDisplay"></span>
//     <span id="detailsNav">
//      <a id="prevLinkDetails" href="javascript:void(0);">&laquo; prev</a>
//      <a id="nextLinkDetails" href="javascript:void(0);">next &raquo;</a>
//      <a id="slideShowControl" href="javascript:void(0);">stop slideshow</a>
//     </span>
//    </div>
//    <div id="close">
//     <a id="closeLink" href="javascript:void(0);">close</a>
//    </div>
//   </div>
//  </div>
// </div>
//
// -----------------------------------------------------------------------------------
 
//
// Lightbox Object
//
 
var Lightbox = { 
 activeImage : null,
 badObjects : ['select','object','embed'],
 container : null,
 enableSlideshow : null,
 groupName : null,
 imageArray : [],
 options : null,
 overlayDuration : null,
 overlayOpacity : null,
 playSlides : null,
 refTags : ['a','area'],
 relAttribute : null,
 resizeDuration : null,
 slideShowTimer : null,
 startImage : null,
 
 //
 // initialize()
 // Constructor sets class properties and configuration options and
 // inserts html at the bottom of the page which is used to display the shadow 
 // overlay and the image container.
 //
 initialize: function(options) {
  if (!document.getElementsByTagName){ return; }
  
  this.options = $H({
   animate : true, // resizing animations
   autoPlay : false, // should slideshow start automatically
   borderSize : 10, // if you adjust the padding in the CSS, you will need to update this variable
   containerID : document, // lightbox container object
   enableSlideshow : true, // enable slideshow feature
   googleAnalytics : false, // track individual image views using Google Analytics
   imageDataLocation : 'south', // location of image caption information
   initImage : '', // ID of image link to automatically launch when upon script initialization
   loop : true, // whether to continuously loop slideshow images
   overlayDuration : .2, // time to fade in shadow overlay
   overlayOpacity : .8, // transparency of shadow overlay
   prefix : '', // ID prefix for all dynamically created html elements
   relAttribute : 'lightbox', // specifies the rel attribute value that triggers lightbox
   resizeSpeed : 7, // controls the speed of the image resizing (1=slowest and 10=fastest)
   showGroupName : false, // show group name of images in image details
   slideTime : 4, // time to display images during slideshow
   strings : { // allows for localization
    closeLink : 'close',
    loadingMsg : 'loading',
    nextLink : 'next &raquo;',
    prevLink : '&laquo; prev',
    startSlideshow : 'start slideshow',
    stopSlideshow : 'stop slideshow',
    numDisplayPrefix : 'Image',
    numDisplaySeparator : 'of'
   }
        }).merge(options);
  
  if(this.options.animate){
   this.overlayDuration = Math.max(this.options.overlayDuration,0);
   this.options.resizeSpeed = Math.max(Math.min(this.options.resizeSpeed,10),1);
   this.resizeDuration = (11 - this.options.resizeSpeed) * 0.15;
  }else{
   this.overlayDuration = 0;
   this.resizeDuration = 0;
  }
  
  this.enableSlideshow = this.options.enableSlideshow;
  this.overlayOpacity = Math.max(Math.min(this.options.overlayOpacity,1),0);
  this.playSlides = this.options.autoPlay;
  this.container = $(this.options.containerID);
  this.relAttribute = this.options.relAttribute;
  this.updateImageList();
  
  var objBody = this.container != document ? this.container : document.getElementsByTagName('body').item(0);
  
  var objOverlay = document.createElement('div');
  objOverlay.setAttribute('id',this.getID('overlay'));
  objOverlay.style.display = 'none';
  objBody.appendChild(objOverlay);
  Event.observe(objOverlay,'click',this.end.bindAsEventListener(this));
  
  var objLightbox = document.createElement('div');
  objLightbox.setAttribute('id',this.getID('lightbox'));
  objLightbox.style.display = 'none';
  objBody.appendChild(objLightbox);
  
  var objImageDataContainer = document.createElement('div');
  objImageDataContainer.setAttribute('id',this.getID('imageDataContainer'));
  objImageDataContainer.className = this.getID('clearfix');
 
  var objImageData = document.createElement('div');
  objImageData.setAttribute('id',this.getID('imageData'));
  objImageDataContainer.appendChild(objImageData);
 
  var objImageDetails = document.createElement('div');
  objImageDetails.setAttribute('id',this.getID('imageDetails'));
  objImageData.appendChild(objImageDetails);
 
  var objCaption = document.createElement('span');
  objCaption.setAttribute('id',this.getID('caption'));
  objImageDetails.appendChild(objCaption);
 
  var objNumberDisplay = document.createElement('span');
  objNumberDisplay.setAttribute('id',this.getID('numberDisplay'));
  objImageDetails.appendChild(objNumberDisplay);
 
  var objDetailsNav = document.createElement('span');
  objDetailsNav.setAttribute('id',this.getID('detailsNav'));
  objImageDetails.appendChild(objDetailsNav);
 
  var objPrevLink = document.createElement('a');
  objPrevLink.setAttribute('id',this.getID('prevLinkDetails'));
  objPrevLink.setAttribute('href','javascript:void(0);');
  objPrevLink.innerHTML = this.options.strings.prevLink;
  objDetailsNav.appendChild(objPrevLink);
  Event.observe(objPrevLink,'click',this.showPrev.bindAsEventListener(this));
  
  var objNextLink = document.createElement('a');
  objNextLink.setAttribute('id',this.getID('nextLinkDetails'));
  objNextLink.setAttribute('href','javascript:void(0);');
  objNextLink.innerHTML = this.options.strings.nextLink;
  objDetailsNav.appendChild(objNextLink);
  Event.observe(objNextLink,'click',this.showNext.bindAsEventListener(this));
 
  var objSlideShowControl = document.createElement('a');
  objSlideShowControl.setAttribute('id',this.getID('slideShowControl'));
  objSlideShowControl.setAttribute('href','javascript:void(0);');
  objDetailsNav.appendChild(objSlideShowControl);
  Event.observe(objSlideShowControl,'click',this.toggleSlideShow.bindAsEventListener(this));
 
  var objClose = document.createElement('div');
  objClose.setAttribute('id',this.getID('close'));
  objImageData.appendChild(objClose);
 
  var objCloseLink = document.createElement('a');
  objCloseLink.setAttribute('id',this.getID('closeLink'));
  objCloseLink.setAttribute('href','javascript:void(0);');
  objCloseLink.innerHTML = this.options.strings.closeLink;
  objClose.appendChild(objCloseLink); 
  Event.observe(objCloseLink,'click',this.end.bindAsEventListener(this));
 
  if(this.options.imageDataLocation == 'north'){
   objLightbox.appendChild(objImageDataContainer);
  }
 
  var objOuterImageContainer = document.createElement('div');
  objOuterImageContainer.setAttribute('id',this.getID('outerImageContainer'));
  objLightbox.appendChild(objOuterImageContainer);
 
  var objImageContainer = document.createElement('div');
  objImageContainer.setAttribute('id',this.getID('imageContainer'));
  objOuterImageContainer.appendChild(objImageContainer);
 
  var objLightboxImage = document.createElement('img');
  objLightboxImage.setAttribute('id',this.getID('lightboxImage'));
  objImageContainer.appendChild(objLightboxImage);
 
  var objHoverNav = document.createElement('div');
  objHoverNav.setAttribute('id',this.getID('hoverNav'));
  objImageContainer.appendChild(objHoverNav);
 
  var objPrevLinkImg = document.createElement('a');
  objPrevLinkImg.setAttribute('id',this.getID('prevLinkImg'));
  objPrevLinkImg.setAttribute('href','javascript:void(0);');
  objHoverNav.appendChild(objPrevLinkImg);
  Event.observe(objPrevLinkImg,'click',this.showPrev.bindAsEventListener(this));
  
  var objNextLinkImg = document.createElement('a');
  objNextLinkImg.setAttribute('id',this.getID('nextLinkImg'));
  objNextLinkImg.setAttribute('href','javascript:void(0);');
  objHoverNav.appendChild(objNextLinkImg);
  Event.observe(objNextLinkImg,'click',this.showNext.bindAsEventListener(this));
 
  var objLoading = document.createElement('div');
  objLoading.setAttribute('id',this.getID('loading'));
  objImageContainer.appendChild(objLoading);
 
  var objLoadingLink = document.createElement('a');
  objLoadingLink.setAttribute('id',this.getID('loadingLink'));
  objLoadingLink.setAttribute('href','javascript:void(0);');
  objLoadingLink.innerHTML = this.options.strings.loadingMsg;
  objLoading.appendChild(objLoadingLink);
  Event.observe(objLoadingLink,'click',this.end.bindAsEventListener(this));
  
  if(this.options.imageDataLocation != 'north'){
   objLightbox.appendChild(objImageDataContainer);
  }
  
  if(this.options.initImage != ''){
   this.start($(this.options.initImage));
  }
 },
 
 //
 // updateImageList()
 // Loops through specific tags within 'container' looking for 
 // 'lightbox' references and applies onclick events to them.
 //
 updateImageList: function(){
  var el, els, rel;
  for(var i=0; i < this.refTags.length; i++){
   els = this.container.getElementsByTagName(this.refTags[i]);
   for(var j=0; j < els.length; j++){
    el = els[j];
    rel = String(el.getAttribute('rel'));
    if (el.getAttribute('href') && (rel.toLowerCase().match(this.relAttribute))){
     el.onclick = function(){Lightbox.start(this); return false;}
    }
   }
  }
 },
  
 //
 // start()
 // Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
 //
 start: function(imageLink) { 
 
  this.hideBadObjects();
 
  // stretch overlay to fill page and fade in
  var pageSize = this.getPageSize();
  $(this.getID('overlay')).setStyle({height:pageSize.pageHeight+'px'});
  new Effect.Appear(this.getID('overlay'), { duration: this.overlayDuration, from: 0, to: this.overlayOpacity });
 
  this.imageArray = [];
  this.groupName = null;
  
  var rel = imageLink.getAttribute('rel');
  var imageTitle = '';
  
  // if image is NOT part of a group..
  if(rel == this.relAttribute){
   // add single image to imageArray
   imageTitle = imageLink.getAttribute('title') ? imageLink.getAttribute('title') : '';
   this.imageArray.push({'link':imageLink.getAttribute('href'), 'title':imageTitle});   
   this.startImage = 0;
  } else {
   // if image is part of a group..
   var els = this.container.getElementsByTagName(imageLink.tagName);
   // loop through anchors, find other images in group, and add them to imageArray
   for (var i=0; i<els.length; i++){
    var el = els[i];
    if (el.getAttribute('href') && (el.getAttribute('rel') == rel)){
     imageTitle = el.getAttribute('title') ? el.getAttribute('title') : '';
     this.imageArray.push({'link':el.getAttribute('href'),'title':imageTitle});
     if(el == imageLink){
      this.startImage = this.imageArray.length-1;
     }
    }
   }
   // get group name
   this.groupName = rel.substring(this.relAttribute.length+1,rel.length-1);
  }
 
  // calculate top offset for the lightbox and display 
  var pageScroll = this.getPageScroll();
  var lightboxTop = pageScroll.y + (pageSize.winHeight / 15);
 
  $(this.getID('lightbox')).setStyle({top:lightboxTop+'px'}).show();
  this.changeImage(this.startImage);
 },
 
 //
 // changeImage()
 // Hide most elements and preload image in preparation for resizing image container.
 //
 changeImage: function(imageNum){ 
  this.activeImage = imageNum;
 
  this.disableKeyboardNav();
  this.pauseSlideShow();
 
  // hide elements during transition
  $(this.getID('loading')).show();
  $(this.getID('lightboxImage')).hide();
  $(this.getID('hoverNav')).hide();
  $(this.getID('imageDataContainer')).hide();
  $(this.getID('numberDisplay')).hide();
  $(this.getID('detailsNav')).hide();
  
  var imgPreloader = new Image();
  
  // once image is preloaded, resize image container
  imgPreloader.onload=function(){
   $(Lightbox.getID('lightboxImage')).src = imgPreloader.src;
   Lightbox.resizeImageContainer(imgPreloader.width,imgPreloader.height);
  }
  imgPreloader.src = this.imageArray[this.activeImage].link;
  
  if(this.options.googleAnalytics){
   urchinTracker(this.imageArray[this.activeImage].link);
  }
 },
 
 //
 // resizeImageContainer()
 //
 resizeImageContainer: function(imgWidth,imgHeight) {
  // get current height and width
  var cDims = $(this.getID('outerImageContainer')).getDimensions();
 
  // scalars based on change from old to new
  var xScale = ((imgWidth  + (this.options.borderSize * 2)) / cDims.width) * 100;
  var yScale = ((imgHeight  + (this.options.borderSize * 2)) / cDims.height) * 100;
 
  // calculate size difference between new and old image, and resize if necessary
  var wDiff = (cDims.width - this.options.borderSize * 2) - imgWidth;
  var hDiff = (cDims.height - this.options.borderSize * 2) - imgHeight;
 
  if(!( hDiff == 0)){ new Effect.Scale(this.getID('outerImageContainer'), yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'}); }
  if(!( wDiff == 0)){ new Effect.Scale(this.getID('outerImageContainer'), xScale, {scaleY: false, delay: this.resizeDuration, duration: this.resizeDuration}); }
 
  // if new and old image are same size and no scaling transition is necessary, 
  // do a quick pause to prevent image flicker.
  if((hDiff == 0) && (wDiff == 0)){
   if(navigator.appVersion.indexOf('MSIE')!=-1){ this.pause(250); } else { this.pause(100);} 
  }
 
  $(this.getID('prevLinkImg')).setStyle({height:imgHeight+'px'});
  $(this.getID('nextLinkImg')).setStyle({height:imgHeight+'px'});
  $(this.getID('imageDataContainer')).setStyle({width:(imgWidth+(this.options.borderSize * 2))+'px'});
 
  this.showImage();
 },
 
 //
 // showImage()
 // Display image and begin preloading neighbors.
 //
 showImage: function(){
  $(this.getID('loading')).hide();
  new Effect.Appear(this.getID('lightboxImage'), { duration: 0.5, queue: 'end', afterFinish: function(){ Lightbox.updateDetails(); } });
  this.preloadNeighborImages();
 },
 
 //
 // updateDetails()
 // Display caption, image number, and bottom nav.
 //
 updateDetails: function() {
  $(this.getID('caption')).show();
  $(this.getID('caption')).update(this.imageArray[this.activeImage].title);
  
  // if image is part of set display 'Image x of y' 
  if(this.imageArray.length > 1){
   var num_display = this.options.strings.numDisplayPrefix + ' ' + eval(this.activeImage + 1) + ' ' + this.options.strings.numDisplaySeparator + ' ' + this.imageArray.length;
   if(this.options.showGroupName && this.groupName != ''){
    num_display += ' '+this.options.strings.numDisplaySeparator+' '+this.groupName;
   }
   $(this.getID('numberDisplay')).update(num_display).show();
   if(!this.enableSlideshow){
    $(this.getID('slideShowControl')).hide();
   }
   $(this.getID('detailsNav')).show();
  }
  
  new Effect.Parallel(
   [ new Effect.SlideDown( this.getID('imageDataContainer'), { sync: true }), 
     new Effect.Appear(this.getID('imageDataContainer'), { sync: true }) ], 
   { duration:.65, afterFinish: function() { Lightbox.updateNav();} } 
  );
 },
 
 //
 // updateNav()
 // Display appropriate previous and next hover navigation.
 //
 updateNav: function() {
  if(this.imageArray.length > 1){
   $(this.getID('hoverNav')).show();
   if(this.enableSlideshow){
    if(this.playSlides){
     this.startSlideShow();
    } else {
     this.stopSlideShow();
    }
   }
  }
  this.enableKeyboardNav();
 },
 //
 // startSlideShow()
 // Starts the slide show
 //
 startSlideShow: function(){
  this.playSlides = true;
  this.slideShowTimer = new PeriodicalExecuter(function(pe){ Lightbox.showNext(); pe.stop(); },this.options.slideTime);
  $(this.getID('slideShowControl')).update(this.options.strings.stopSlideshow);
 },
 
 //
 // stopSlideShow()
 // Stops the slide show
 //
 stopSlideShow: function(){
  this.playSlides = false;
  if(this.slideShowTimer){
   this.slideShowTimer.stop();
  }
  $(this.getID('slideShowControl')).update(this.options.strings.startSlideshow);
 },
 
 //
 // stopSlideShow()
 // Stops the slide show
 //
 toggleSlideShow: function(){
  if(this.playSlides){
   this.stopSlideShow();
  }else{
   this.startSlideShow();
  }
 },
 
 //
 // pauseSlideShow()
 // Pauses the slide show (doesn't change the value of this.playSlides)
 //
 pauseSlideShow: function(){
  if(this.slideShowTimer){
   this.slideShowTimer.stop();
  }
 },
 
 //
 // showNext()
 // Display the next image in a group
 //
 showNext : function(){
  if(this.imageArray.length > 1){
   if(!this.options.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);
   }
  }
 },
 
 //
 // showPrev()
 // Display the next image in a group
 //
 showPrev : function(){
  if(this.imageArray.length > 1){
   if(this.activeImage == 0){
    this.changeImage(this.imageArray.length - 1);
   }else{
    this.changeImage(this.activeImage-1);
   }
  }
 },
 
 //
 // showFirst()
 // Display the first image in a group
 //
 showFirst : function(){
  if(this.imageArray.length > 1){
   this.changeImage(0);
  }
 },
 
 //
 // showFirst()
 // Display the first image in a group
 //
 showLast : function(){
  if(this.imageArray.length > 1){
   this.changeImage(this.imageArray.length - 1);
  }
 },
 
 //
 // enableKeyboardNav()
 //
 enableKeyboardNav: function() {
  document.onkeydown = this.keyboardAction; 
 },
 
 //
 // disableKeyboardNav()
 //
 disableKeyboardNav: function() {
  document.onkeydown = '';
 },
 
 //
 // keyboardAction()
 //
 keyboardAction: function(e) {
  if (e == null) { // ie
   keycode = event.keyCode;
  } else { // mozilla
   keycode = e.which;
  }
 
  key = String.fromCharCode(keycode).toLowerCase();
  
  if(key == 'x' || key == 'o' || key == 'c'){ // close lightbox
   Lightbox.end();
  } else if(key == 'p' || key == '%'){ // display previous image
   Lightbox.showPrev();
  } else if(key == 'n' || key =='\''){ // display next image
   Lightbox.showNext();
  } else if(key == 'f'){ // display first image
   Lightbox.showFirst();
  } else if(key == 'l'){ // display last image
   Lightbox.showLast();
  } else if(key == 's'){ // toggle slideshow
   if(Lightbox.imageArray.length > 0 && Lightbox.options.enableSlideshow){
    Lightbox.toggleSlideShow();
   }
  }
 },
 
 //
 // preloadNeighborImages()
 // Preload previous and next images.
 //
 preloadNeighborImages: function(){
  var nextImageID = this.imageArray.length - 1 == this.activeImage ? 0 : this.activeImage + 1;
  nextImage = new Image();
  nextImage.src = this.imageArray[nextImageID].link
 
  var prevImageID = this.activeImage == 0 ? this.imageArray.length - 1 : this.activeImage - 1;
  prevImage = new Image();
  prevImage.src = this.imageArray[prevImageID].link;
 },
 
 //
 // end()
 //
 end: function() {
  this.disableKeyboardNav();
  this.pauseSlideShow();
  $(this.getID('lightbox')).hide();
  new Effect.Fade(this.getID('overlay'), { duration:this.overlayDuration });
  this.showBadObjects();
 },
 
 //
 // showBadObjects()
 //
 showBadObjects: function (){
  var els;
  var tags = Lightbox.badObjects;
  for(var i=0; i<tags.length; i++){
   els = document.getElementsByTagName(tags[i]);
   for(var j=0; j<els.length; j++){
    $(els[j]).setStyle({visibility:'visible'});
   }
  }
 },
 
 //
 // hideBadObjects()
 //
 hideBadObjects: function (){
  var els;
  var tags = Lightbox.badObjects;
  for(var i=0; i<tags.length; i++){
   els = document.getElementsByTagName(tags[i]);
   for(var j=0; j<els.length; j++){
    $(els[j]).setStyle({visibility:'hidden'});
   }
  }
 },
  
 //
 // pause(numberMillis)
 // Pauses code execution for specified time. Uses busy code, not good.
 // Code from http://www.faqts.com/knowledge_base/view.phtml/aid/1602
 //
 pause: function(numberMillis) {
  var now = new Date();
  var exitTime = now.getTime() + numberMillis;
  while(true){
   now = new Date();
   if (now.getTime() > exitTime)
    return;
  }
 },
 
 //
 // getPageScroll()
 // Returns array with x,y page scroll values.
 // Core code from - quirksmode.org
 //
 getPageScroll: function(){
  var x,y;
  if (self.pageYOffset) {
   x = self.pageXOffset;
   y = self.pageYOffset;
  } else if (document.documentElement && document.documentElement.scrollTop){  // Explorer 6 Strict
   x = document.documentElement.scrollLeft;
   y = document.documentElement.scrollTop;
  } else if (document.body) {// all other Explorers
   x = document.body.scrollLeft;
   y = document.body.scrollTop;
  }
  return {x:x,y:y};
 },
 
 //
 // getPageSize()
 // Returns array with page width, height and window width, height
 // Core code from - quirksmode.org
 // Edit for Firefox by pHaez
 //
 getPageSize: function(){
  var scrollX,scrollY,windowX,windowY,pageX,pageY;
  if (window.innerHeight && window.scrollMaxY) { 
   scrollX = document.body.scrollWidth;
   scrollY = window.innerHeight + window.scrollMaxY;
  } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
   scrollX = document.body.scrollWidth;
   scrollY = document.body.scrollHeight;
  } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
   scrollX = document.body.offsetWidth;
   scrollY = document.body.offsetHeight;
  }
  
  if (self.innerHeight) { // all except Explorer
   windowX = self.innerWidth;
   windowY = self.innerHeight;
  } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
   windowX = document.documentElement.clientWidth;
   windowY = document.documentElement.clientHeight;
  } else if (document.body) { // other Explorers
   windowX = document.body.clientWidth;
   windowY = document.body.clientHeight;
  } 
  
  pageY = (scrollY < windowY) ? windowY : scrollY; // for small pages with total height less then height of the viewport
  pageX = (scrollX < windowX) ? windowX : scrollX; // for small pages with total width less then width of the viewport
 
  return {pageWidth:pageX,pageHeight:pageY,winWidth:windowX,winHeight:windowY};
 },
 
 //
 // getID()
 // Returns formatted Lightbox element ID
 //
 getID: function(id){
  return this.options.prefix+id;
 }
}
 
// -----------------------------------------------------------------------------------
 
Event.observe(window,'load',function(){ Lightbox.initialize(); });
