// -----------------------------------------------------------------------------------
//
//	Slideshow v1.00
//	by Lloyd Briggs - http://www.egekko.com
//	Last Modification: 2/1/11
//
//	For more information, visit:
//	http://
//
// -----------------------------------------------------------------------------------
/*

  Table of Contents
  -----------------
  Configuration

  Slideshow Class Declaration
  - initialize()
  - buildObject()
  - buildBottomNav()
  - buildControls()
  - buildImageNav()
  - buildThumbnail(imageIndex, callback)
  - buildImage()
  - buildCanvas()
  - updateImage()
  - updateThumbnail(thumbContainer, config)
  - updateBottomNav()
  - setNativeState()
  - setFullScreenState()
  - start()
  - stop()
  - getPageSize()

  Function Calls
  - document.observe


  CSS DESIGN TIPS:
  ----------------
  Remove dotted image border: 
    a { outline: none; }
    :focus { -moz-outline-style: none; }

*/
// -----------------------------------------------------------------------------------


//
//  Configurational Defaults
//
SlideShowOptions = Object.extend({
  // Control box button path (used for control box images)
  // play.png // stop.png // skip_forward.png // skip_backward.png // fullscreen.png
  buttonDir:          'http://localhost/development/egekko.com/js/slideshow/images/',

  // General Attributes:
  width:              400,              // int, width of the object
  height:             400,              // int, height of the object
  border:             false,            // bool, display object border
  borderColor:        '#ff0',           // string, object border color
  backgroundColor:    '#000',           // string, object background color
  imageNav:           false,            // bool, display NEXT and PREV nav

  // Overlay Options:
  useOverlay:         false,
  overlayColor:       'transparent',
  overlayImage:       'url(data:image/gif;base64,AAAA)',
  overlayOpacity:     .5,

  // Bottom Navigation Options:
  bottomNav:          false,            // bool, display bottom image nav
  maxThumbs:          10,               // int, maximum number of thumbnails
  navHeight:          75,               // int, bottom nav height
  navColor:           '#444',           // string, image nav background color
  navImageBorder:     false,            // bool, display active thumbnail border
  navBorderColor:     '#ff0',           // string, active thumbnail border color

  // Animation Options:
  animation:          false,            // bool, display animations
  animationSpeed:     4,                // float, animation speed

  // Auto Play Options:
  autoPlay:           false,            // bool, sets the slideshow auto play
  autoPlaySpeed:      4,                // int, auto play speed

  // Control Box Options:
  useControls:        false,            // bool, display the button control box
  controlHeight:      50,               // int, control button height
  usePlayButtons:     false,            // bool, display play and stop buttons
  useFullscreen:      false             // bool, display fullscreen button
}, window.SlideShowOptions || {});

//
// Add SlideShow object to the global namespace.
//
var SlideShow = Class.create();

SlideShow.prototype = {
  imageArray: [],
  activeImage: undefined,
  
  // initialize(obj, config)
  //   Arguments:
  //     obj - typically, a div element.
  //     config - annonymous object with configuaration values
  //       - imageFolder:       string, URL path to image directory
  //       - imageArray:        array, list of image names
  //       - activeImage:       int, active image index number
  //       - width:             int, object width
  //       - height:            int, object height
  //       - backgroundColor    string, object background color
  //       - border:            bool, display object border
  //       - borderColor:       string, object border color
  //       - imageNav:          bool, display image overlay navigation
  //       - bottomNav:         bool, display thumbnail navigation
  //       - maxThumbs:         int, maxium number of thumbnails
  //       - navHeight:         int, thumbnail nav height
  //       - navColor:          string, thumbnail background color
  //       - navImageBorder:    bool, display borders around active thumbnail
  //       - navBorderColor:    string, active thumbnail border color
  //       - animation:         bool, display animations
  //       - animationSpeed:    float, animation speed
  //       - autoPlay:          bool, sets the slideshow auto play
  //       - autoPlaySpeed:     int, auto play speed (miliseconds)
  //       - useControls:       bool, display the button control box
  //       - controlHeight:     int, control button height
  //       - usePlayButtons:    bool, display play and stop buttons
  //       - useFullscreen:     bool, display fullscren button
  //       - imageClick:		function, main image 'click' event handler
  //
  //   Object Instatiation and Use:
  //     var ss = new Element('div');
  //     new SlideShow(ss, {
  //       imageFolder: 'http://www.domain.com/images/slideShow01/',
  //       imageArray: ['0001.jpg','0002.jpg']
  //     });
  //     document.insert(ss);
  initialize: function(obj, config) {
    if (typeof obj != 'object')
      throw new Error('SlideShow: object not defined');
    if (typeof config != 'object')
      throw new Error('SlideShow: config not defined');
    if (config.imageFolder == 'undefined')
      throw new Error('SlideShow: config.imageFolder is undefined');
    if (config.imageArray == 'undefined')
      throw new Error('SlideShow: config.imageArray is undefined');

    // Define element containers
    this.imageContainer   = undefined;
    this.navContainer     = undefined;
    this.controls         = undefined;

    // Define config
    this.config           = config;

    // Define imageFolder and imageArray
    this.imageFolder      = this.config.imageFolder;
    this.imageArray       = this.config.imageArray;
    this.totalImages      = this.config.imageArray.length;

    // Define optional/configuration data members
    this.buttonDir        = SlideShowOptions.buttonDir;
    this.activeImage      = this.config.activeImage || 0;
    this.maxWidth         = this.config.width || SlideShowOptions.width;
    this.maxHeight        = this.config.height || SlideShowOptions.height;
    this.bgColor          = this.config.backgroundColor || SlideShowOptions.backgroundColor;
    this.border           = this.config.border || SlideShowOptions.border;
    this.borderColor      = this.config.borderColor || SlideShowOptions.borderColor;
    this.imageNav         = this.config.imageNav || SlideShowOptions.imageNav;
    this.useOverlay       = this.config.useOverlay || SlideShowOptions.useOverlay;
    this.overlayColor     = this.config.overlayColor || SlideShowOptions.overlayColor;
    this.overlayOpacity   = this.config.overlayOpacity || SlideShowOptions.overlayOpacity;
    this.overlayBg        = this.config.overlayImage || SlideShowOptions.overlayImage;
    this.bottomNav        = this.config.bottomNav || SlideShowOptions.bottomNav;
    this.maxThumbs        = this.config.maxThumbs || SlideShowOptions.maxThumbs;
    this.navHeight        = this.config.navHeight || SlideShowOptions.navHeight;
    this.navColor         = this.config.navColor || SlideShowOptions.navColor;
    this.navImageBorder   = this.config.navImageBorder || SlideShowOptions.navImageBorder;
    this.navBorderColor   = this.config.navBorderColor || SlideShowOptions.navBorderColor;
    this.animation        = this.config.animation || SlideShowOptions.animation;
    this.animationSpeed   = this.config.animationSpeed || SlideShowOptions.animationSpeed;
    this.autoPlay         = this.config.autoPlay || SlideShowOptions.autoPlay;
    this.autoPlaySpeed    = this.config.autoPlaySpeed || SlideShowOptions.autoPlaySpeed;
    this.useControls      = this.config.useControls || SlideShowOptions.useControls;
    this.controlHeight    = this.config.controlHeight || SlideShowOptions.controlHeight;
    this.usePlayButtons   = this.config.usePlayButtons || SlideShowOptions.usePlayButtons;
    this.useFullscreen    = this.config.useFullscreen || SlideShowOptions.useFullscreen;
    this.imageClick       = this.config.imageClick || undefined;

    // Define animation defaults
    if (Prototype.Browser.IE) this.animation = false;
    if (this.animationSpeed > 10) this.animationSpeed = 10;
    else if (this.animationSpeed < 0) this.animationSpeed = 0;

    // Define iterators and timers
    this.play           = undefined;
    this.autoPlaySpeed  = this.autoPlaySpeed * 1000;
    this.animationSpeed = this.animationSpeed * .15;

    // Define imageHeight
    this.imageHeight = (this.bottomNav)
      ? this.maxHeight - this.navHeight
      : this.maxHeight;

    // Load 10 thumbnails max
    if (this.maxThumbs > 10) this.maxThumbs = 10;

    // Define object container and set style attributes
    this.container = obj;
    this.container.setStyle({
      width:            this.maxWidth + 'px',
      height:           this.maxHeight + 'px',
      position:         'relative',
      backgroundColor:  this.bgColor,
      border:           (this.border) ? '1px solid ' + this.borderColor : ''
    });

    // Build Object
    this.buildObject();
  },

  //
  // buildObject()
  //
  buildObject: function() {
    if (this.bottomNav) this.buildBottomNav();
    else this.updateImage(this.activeImage);
  },

  //
  // buildBottomNav()
  //
  buildBottomNav: function() {
    // Define navContainer element
    if (typeof this.navContainer == 'undefined') {
      this.navContainer = new Element('div');
      this.navContainer.setStyle({
        margin:           'auto',
        width:            (this.maxWidth - 8) + 'px',
        height:           (this.navHeight - 10) + 'px',
        position:         'absolute',
        top:              (this.maxHeight - this.navHeight) + 'px',
        left:             '0px',
        padding:          '5px 4px',
        backgroundColor:  this.navColor
      });
      // Add navContainer element to the object container element
      this.container.insert(this.navContainer);
    }

    // Build controls
    if (this.useControls && typeof this.controls == 'undefined') {
      this.buildControls();
      document.observe('slideShow:controlsDisplayed', (function(event) {
        event.stop();
        this.buildBottomNav();
      }).bindAsEventListener(this));
      return;
    }

    // Define thumbWidth data member
    this.thumbWidth = (this.useControls)
      ? (((this.maxWidth - 10) - (this.controls.getWidth() + 10)) - (this.maxThumbs * 5)) / this.maxThumbs
      : ((this.maxWidth - 10) - (this.maxThumbs * 5)) / this.maxThumbs;

    // Define navImages object member array
    this.navImages = new Array();

    // Define indexHigh, maxLoad, thumbsLoaded
    var indexHigh, maxLoad, thumbsLoaded = 0;
    if (this.totalImages <= this.maxThumbs * 2) {
      indexHigh = this.totalImages - 1;
      maxLoad = this.totalImages;
    } else {
      indexHigh = this.maxThumbs * 2;
      maxLoad = this.maxThumbs * 2;
    }

    // Build thumbnails
    for (var i = 0; i <= indexHigh; i++) {
      (function(counter){
        this.buildThumbnail(counter, (function(){
          thumbsLoaded++;
          if (thumbsLoaded == maxLoad)
            this.navContainer.fire('slideShow:navLoaded');
        }).bind(this));
      }).bind(this)(i);
    }

    // Define slideShow:navLoaded event listener
    // invoked when thumbsLoaded is equal to maxLoad
    document.observe('slideShow:navLoaded', (function(event) {
      // Stop observing the event
      document.stopObserving('slideShow:navLoaded');

      // Define bottomNavLoaded
      this.bottomNavLoaded  = true;

      // Define thumbnailContainer element for thumbnails
      this.thumbnailContainer = new Element('div');
      this.thumbnailContainer.setStyle({
        margin:           'auto',
        width:            'auto',
        height:           'auto',
        position:         'relative',
        left:             (this.navImageBorder) ? '2px' : '1px'
      });
      // Add thumbnailContainer element to navContainer element
      this.navContainer.insert(this.thumbnailContainer);

      // Define navWidthi, maxWidth
      var navWidth = 0;
      var maxWidth = (this.useControls)
        ? (this.maxWidth - 10) - (this.controls.getWidth() - 10)
        : this.maxWidth - 10;

      // Add thumbnails elements to the thumbnailContainer element
      for (var i = 0; i < maxLoad; i++) {
        // Add each navImages element to the thumbnailContainer element
        this.thumbnailContainer.insert(this.navImages[i]);

        // Update thumbnail
        navWidth += this.navImages[i].getWidth() + 5;
        this.updateThumbnail(this.navImages[i], {
          border: (this.navImageBorder && i == this.activeImage) ? true : false,
          visible: (navWidth <= maxWidth) ? true : false
        });
      }

      // this.thumbnailContainer animation and invokation of updateImage()
      if (! this.animation) {
        this.thumbnailContainer.show();
        this.updateImage(this.activeImage);
      } else {
        this.thumbnailContainer.style.display = 'none';
        this.thumbnailContainer.appear({
          from: 0.05,
          to: 1.0,
          duration: this.animationSpeed,
          afterFinish: (function() { this.updateImage(this.activeImage); }).bind(this)
        });
      }
    }).bindAsEventListener(this));
  },

  //
  // buildControls()
  //
  buildControls: function() {
    // Define buttonHeight and container
    var buttonHeight  = this.controlHeight;
    var container     = undefined;

    // if navContainer is defined
    //   use the navContainer element as the container
    if (typeof this.navContainer != 'undefined')
      container = this.navContainer;
    else
      container = this.container;

    // Define control container element and set style
    this.controls = new Element('div');
    this.controls.setStyle({
      margin:           'auto',
      width:            'auto',
      height:           buttonHeight + 'px',
      position:         'absolute',
      bottom:           '10px',
      right:            '10px',
      textAlign:        'right',
      display:          'none'
    });
    // Add control element to object container element
    container.insert({bottom:this.controls});

    // define loadPlayButton function
    var loadPlayButton = (function() {
      var play = new Image();
      play.onload = (function() {
        play.setStyle({
          margin: 'auto 10px auto auto',
          width: play.height * (buttonHeight / play.height) + 'px',
          height: buttonHeight
        });
        this.controls.insert(play);
        if (this.autoPlay)
          play.setOpacity(.35);
        else
          play.style.cursor = 'pointer';
        play.observe('click', (function(event) {
          event.stop();
          if (this.autoPlay) return;
          this.start();
        }).bindAsEventListener(this));
        loadStopButton();
      }).bind(this);
      play.src = this.buttonDir + 'play.png';
      this.playButton = play;
    }).bind(this);

    // define loadStopButton function
    var loadStopButton = (function() {
      var stop = new Image();
      stop.onload = (function() {
        stop.setStyle({
          margin: 'auto 10px auto auto',
          width: stop.width * (buttonHeight / stop.height) + 'px',
          height: buttonHeight
        });
        this.controls.insert({bottom:stop});
        if (! this.autoPlay)
          stop.setOpacity(.35);
        else
          stop.style.cursor = 'pointer';
        stop.observe('click', (function(event) {
          event.stop();
          if (! this.autoPlay) return;
          this.stop();
        }).bindAsEventListener(this));
        loadPreviousButton();
      }).bind(this);
      stop.src = this.buttonDir + 'stop.png';
      this.stopButton = stop;
    }).bind(this);

    // define loadPreviousButton function
    var loadPreviousButton = (function() {
      var previous = new Image();
      previous.onload = (function() {
        previous.setStyle({
          margin: 'auto 10px auto auto',
          width: previous.width * (buttonHeight / previous.height) + 'px',
          height: buttonHeight + 'px',
          cursor: 'auto'
        });
        this.controls.insert({bottom:previous});
        previous.setOpacity(.5);
        previous.observe('click', (function(event) {
          event.stop();
          if (this.activeImage == 0) return;
          if (this.autoPlay) this.stop();
          this.updateImage(this.activeImage - 1);
        }).bindAsEventListener(this));
        loadNextButton();
      }).bind(this);
      previous.src = this.buttonDir + 'skip_backward.png';
      this.previousButton = previous;
    }).bind(this);

    // define loadNextButton function
    var loadNextButton = (function() {
      var nextButton = new Image();
      nextButton.onload = (function() {
        nextButton.setStyle({
          margin: 'auto',
          width: nextButton.width * (buttonHeight / nextButton.height) + 'px',
          height: buttonHeight + 'px',
          cursor: 'pointer'
        });
        this.controls.insert({bottom:nextButton});
        nextButton.observe('click', (function(event) {
          event.stop();
          if (this.autoPlay) this.stop();
          if (this.activeImage == this.imageArray.length - 1) return;
          this.updateImage(this.activeImage + 1);
        }).bindAsEventListener(this));
        if (this.useFullscreen)
          loadStateChangeButtons();
        else
          this.controls.fire('slideShow:controlsLoaded');
      }).bind(this);
      nextButton.src = this.buttonDir + 'skip_forward.png';
      this.nextButton = nextButton;
    }).bind(this);

    // Define loadStateChangeButtons function
    var loadStateChangeButtons = (function() {
    	var loadFullScreenButton = (function(){
    		this.fullScreenButton = new Image();
    		this.fullScreenButton.id = 'slideShow:fsButton';
    		this.fullScreenButton.onload = (function(){
    			this.fullScreenButton.setStyle({
    				margin:		'auto auto auto 10px',
    				width:		this.fullScreenButton.width * (buttonHeight / this.fullScreenButton.height) + 'px',
    				height:		buttonHeight + 'px',
    				cursor:		'pointer'
    			});
        		this.controls.insert({bottom:this.fullScreenButton});
        		this.fullScreenButton.observe('click', (function(event){
        			event.stop();
        			this.setFullScreenState();
        		}).bindAsEventListener(this));
        		this.controls.fire('slideShow:controlsLoaded');
    		}).bind(this);
    		this.fullScreenButton.src = this.buttonDir + 'fullscreen.png';
    	}).bind(this);
    	
    	this.nativeStateButton = new Image();
    	this.nativeStateButton.id = 'slideShow:nsButton';
    	this.nativeStateButton.onload = (function(){
    		this.nativeStateButton.setStyle({
    			margin:		'auto auto auto 10px',
    			width:		this.nativeStateButton.width * (buttonHeight / this.nativeStateButton.height) + 'px',
    			height:		buttonHeight,
    			cursor:		'pointer',
    			display:	'none'
    		});
    		this.controls.insert({bottom:this.nativeStateButton});
    		this.nativeStateButton.observe('click', (function(event){
    			event.stop();
    			this.setNativeState();
    		}).bindAsEventListener(this));
    		loadFullScreenButton();
    	}).bind(this);
    	this.nativeStateButton.src = this.buttonDir + 'nativestate.png';
    }).bind(this);

    // Build the buttons
    if (this.usePlayButtons) loadPlayButton();
    else loadPreviousButton();

    // add event listener 'controlIsLoaded' to document
    document.observe('slideShow:controlsLoaded', (function(event) {
      event.stop();
      if (this.animation)
        this.controls.appear({
          from:         0.05,
          to:           (this.bottomNav) ? 1 : .5,
          duration:     this.animationSpeed,
          afterFinish:  (function() {
                          this.controls.fire('slideShow:controlsDisplayed');
                        }).bind(this)
        });
      else {
        this.controls.setStyle({
          display: 'block'
        });
        this.controls.fire('slideShow:controlsDisplayed');
      }
    }).bindAsEventListener(this));
  },

  //
  // buildImageNav()
  //
  buildImageNav: function() {
    var prevNav = new Element('div');
    prevNav.id = this.imageArray[this.activeImage] + '_prevNav';
    prevNav.setStyle({
      width:            parseInt(this.imageContainer.getWidth() / 2) + 'px',
      height:           parseInt(this.imageContainer.getHeight()) + 'px',
      position:         'absolute',
      top:              '0px',
      left:             '0px',
      cursor:           'pointer',
      backgroundImage:  'url(data:image/gif;base64,AAAA)'
    });

    var nextNav = new Element('div');
    nextNav.id = this.imageArray[this.activeImage] + '_nextNav';
    nextNav.setStyle({
      width:            parseInt(this.imageContainer.getWidth() / 2) + 'px',
      height:           parseInt(this.imageContainer.getHeight()) + 'px',
      position:         'absolute',
      top:              '0px',
      right:            '0px',
      cursor:           'pointer',
      backgroundImage:  'url(data:image/gif;base64,AAAA)'
    });

    var prevButton = new Element('div');
    prevButton.setStyle({
      margin:           'auto',
      width:            '70px',
      height:           '25px',
      position:         'absolute',
      top:              '50px',
      left:             '0px',
      color:            '#000',
      lineHeight:       '25px',
      fontSize:         '18px',
      textTransform:    'uppercase',
      textAlign:        'center',
      backgroundColor:  '#fff',
      display:          'none'
    });
    prevButton.insert('prev');
    new Effect.Opacity(prevButton, {
      from:     0.5,
      to:       0.5,
      duration: 0.0
    });

    var nextButton = new Element('div');
    nextButton.setStyle({
      margin:           'auto',
      width:            '70px',
      height:           '25px',
      position:         'absolute',
      top:              '50px',
      right:            '0px',
      color:            '#000',
      lineHeight:       '25px',
      fontSize:         '18px',
      textTransform:    'uppercase',
      textAlign:        'center',
      backgroundColor:  '#fff',
      display:          'none'
    });
    nextButton.insert('next');
    new Effect.Opacity(nextButton, {
      from: .5,
      to: .5,
      duration: 0
    });

    prevNav.insert(prevButton);
    nextNav.insert(nextButton);
    this.imageContainer.insert(prevNav);
    this.imageContainer.insert(nextNav);

    nextNav.observe('mouseover', function(event){
      var target = Event.element(event);
      nextButton.show();
    });
    nextNav.observe('mouseout', function(event){
      var target = Event.element(event);
      nextButton.hide();
    });
    prevNav.observe('mouseover', function(event){
      var target = Event.element(event);
      prevButton.show();
    });
    prevNav.observe('mouseout', function(event){
      var target = Event.element(event);
      prevButton.hide();
    });
  },

  //
  // buildThumbnail(imageIndex)
  //
  buildThumbnail: function(imageIndex, callback) {
    // Define thumbnail container and style attributes
    var thumbContainer = new Element('div');
    thumbContainer.setStyle({
      margin:           'auto 5px auto auto',
      position:         'relative',
      cssFloat:         'left',
      backgroundColor:  '#000',
      textAlign:        'center',
      cursor:           'pointer'
    });
    if (this.thumbnailContainer != undefined)
      this.thumbnailContainer.insert({ bottom: thumbContainer });

    // Define onclick event handler for thumbnail container
    thumbContainer.observe('click',(function(event){
      event.stop();
      if (this.autoPlay) this.stop();
      this.updateImage(imageIndex);
    }).bindAsEventListener(this));

    var imageLoader = new Image();
    imageLoader.onload = (function(){
      setTimeout((function(){ // FireFox
        if (! Prototype.Browser.IE)
          this.buildCanvas({
            image: imageLoader,
            container: thumbContainer,
            maxWidth: this.thumbWidth - 12,
            maxHeight: this.navHeight - 22
          });
        else
          this.buildImage({
            image: imageLoader,
            container: thumbContainer,
            maxWidth: this.thumbWidth - 12,
            maxHeight: this.navHeight - 22
          });

        thumbContainer.setStyle({
          width:  this.thumbWidth + 'px',
          height: (this.navHeight - 13) + 'px'
        });

        this.navImages[imageIndex] = thumbContainer;

        if (thumbContainer.visible()) this.updateThumbnail(thumbContainer,{visible:true,border:false});
        if (this.bottomNavLoaded) thumbContainer.hide();
        if (typeof callback == 'function') callback();
      }).bind(this), 500);
    }).bind(this);
    imageLoader.src = this.imageFolder + this.imageArray[imageIndex];
  },

  //
  // buildImage(img)
  //
  buildImage: function(args) {
    var image       = args.image;
    var container   = args.container;
    var maxWidth    = args.maxWidth;
    var maxHeight   = args.maxHeight;

    // resize image
    if (image.width > maxWidth) {
      image.height = parseInt(image.height * (maxWidth / image.width));
      image.width = maxWidth;
      if (image.height > maxHeight) {
        image.width = parseInt(image.width * (maxHeight / image.height));
        image.height = maxHeight;
      }
    }
    else if (image.height > maxHeight) {
      image.width = parseInt(image.width * (maxHeight / image.height));
      image.height = maxHeight;
    }

    image.style.border = '0px';

    // reposition image if image height is less than max height
    if (image.height < maxHeight)
      container.style.top = (maxHeight - image.height) / 2;

    // set container width/height style attributes
    container.style.width = image.width + 'px';
    container.style.height = image.height + 'px';

    // add image to container
    container.insert({top:image});
  },
  
  //
  // buildCanvas(img)
  //
  buildCanvas: function(args, callback) {
    var image       = args.image;
    var container   = args.container;
    var maxWidth    = args.maxWidth;
    var maxHeight   = args.maxHeight;

    // define canvas
    var canvas      = new Element('canvas');
    if (typeof G_vmlCanvasManager != 'undefined')
      G_vmlCanvasManager.initElement(canvas);

    if (image.width > maxWidth) {
      canvas.width = maxWidth;
      canvas.height = parseInt(image.height * (maxWidth / image.width));
      if (canvas.height > maxHeight) {
        canvas.width = parseInt(image.width * (maxHeight / image.height));
        canvas.height = maxHeight;
      }
    }
    else if (image.height > maxHeight) {
      canvas.width = parseInt(image.width * (maxHeight / image.height));
      canvas.height = maxHeight;
    }
    else {
      canvas.width = image.width;
      canvas.height = image.height;
    }

    // define context and draw image into canvas
    var context = canvas.getContext('2d');
    try {
      context.drawImage(image, 0, 0, canvas.width, canvas.height);
    } catch(e) {
      if (typeof callback == 'function') callback();
      return;
    };

    // reposition canvas if canvas height is less than max height
    if (canvas.height < maxHeight)
      container.style.top = parseInt((maxHeight - canvas.height) / 2) + 'px';

    // define container width and height attributes
    container.style.width = canvas.width + 'px';
    container.style.height = canvas.height + 'px';

    // insert canvas into container
    container.insert(canvas);

    // return true
    return true;
  },

  //
  // updateImage(imageIndex)
  //
  updateImage: function(imageIndex) {
    // define image index
    if (imageIndex < 0)
      imageIndex = this.imageArray.length - 1;
    else if (imageIndex > this.imageArray.length - 1)
      imageIndex = 0;

    // define active image
    this.activeImage = imageIndex;

    // Build Controls
    if (this.useControls && typeof this.controls == 'undefined') {
      this.buildControls();
      document.observe('slideShow:controlsDisplayed', (function(event) {
        this.updateImage(this.activeImage);
      }).bindAsEventListener(this));
      return;
    }

    // remove image container
    if (typeof this.imageContainer != 'undefined') {
      // update the bottom nav
      if (this.bottomNavLoaded) this.updateBottomNav();

      // Remove the old image and add the new image
      if (! this.animation) {
        this.imageContainer.remove();
        this.imageContainer = undefined;
      }
      else {
        this.imageContainer.fade({
          from: 1.0,
          to: 0.0,
          duration: this.animationSpeed,
          afterFinish: (function(){
            this.imageContainer.remove();
            this.imageContainer = undefined;
            this.updateImage(imageIndex);
          }).bind(this)
        });
        return;
      }
    }

    // define image container and set style attributes
    this.imageContainer = new Element('div');
    this.imageContainer.setStyle({
      margin:       'auto',
      position:     'relative',
      display:      'none'
    });
    if (typeof this.imageClick == 'function')
    	this.imageContainer.setStyle({cursor:'pointer'});
    // add image container to object container
    this.container.insert({top:this.imageContainer});

    // Image callback event handler
    this.imageContainer.observe('click', (function(event) {
      event.stop();
      if (typeof this.imageClick == 'function') this.imageClick();
    }).bindAsEventListener(this));

    // build image
    var imageLoader = new Image();
    imageLoader.onload = (function() {
      if (! Prototype.Browser.IE) {
        if (! this.buildCanvas({
                image:      imageLoader,
                container:  this.imageContainer,
                maxWidth:   this.maxWidth,
                maxHeight:  this.imageHeight
              }, (function(){this.updateImage(this.activeImage);}).bind(this)))
          return;
      }
      else {
        this.buildImage({
          image:      imageLoader,
          container:  this.imageContainer,
          maxWidth:   this.maxWidth,
          maxHeight:  this.imageHeight
        });
      }

      // Animation
      if (!this.animation)
        this.imageContainer.style.display = 'block';
      else
        this.imageContainer.appear({
          from: 0.05,
          to: 1.0,
          duration: this.animationSpeed
        });

      if (this.useOverlay) {
        var overlay = new Element('div');
        overlay.setStyle({
          margin:           'auto',
          width:            this.imageContainer.getWidth() + 'px',
          height:           this.imageContainer.getHeight() + 'px',
          position:         'absolute',
          top:              '0px',
          left:             '0px',
          backgroundColor:  this.overlayColor,
          backgroundImage:  this.overlayBg
        });

        overlay.setOpacity(this.overlayOpacity);

        this.imageContainer.insert({top:overlay});
      }

      // if imageNav is true and browser is not MobileSafari
      //   > build the image nav
      // (overlaty next and prev buttons)
      if (this.imageNav && ! Prototype.Browser.MobileSafari) {
        this.buildImageNav();
        $(this.imageArray[this.activeImage] + '_prevNav').observe('click', (function(event){
          //event.stop();
          if (this.autoPlay) this.stop();
          this.updateImage(this.activeImage - 1);
        }).bindAsEventListener(this));
        $(this.imageArray[this.activeImage] + '_nextNav').observe('click', (function(event){
          //event.stop();
          if (this.autoPlay) this.stop();
          this.updateImage(this.activeImage + 1);
        }).bindAsEventListener(this));
      }

      // if autoPlay is true and play iterator is undefiend
      //  > define play as an interfal function that
      //    invokes updateImage
      if (this.autoPlay && this.play == undefined) {
        this.play = setInterval((function(){
          this.updateImage(this.activeImage + 1);
        }).bind(this), this.autoPlaySpeed);
      }

      // Fire 'slideShow:loaded' event
      if (! this.objectLoaded) {
        this.objectLoaded = true;
        this.container.fire('slideShow:loaded');
      }
    }).bind(this);
    imageLoader.src = this.imageFolder + this.imageArray[this.activeImage];
  },

  //
  // updateThumbnail()
  //
  updateThumbnail: function(thumbContainer, config) {
    var thumb = thumbContainer.firstDescendant();

    thumbContainer.setStyle({top:'0px'});

    if (thumb.getHeight() < thumbContainer.getHeight()) {
      thumb.absolutize();
      thumb.setStyle({
        top: parseInt((thumbContainer.getHeight() - thumb.getHeight()) / 2) + 'px'
      });
    }

    if (config.visible) thumbContainer.show(); else thumbContainer.hide();
    if (config.border)thumbContainer.setStyle({border:'1px solid ' + this.navBorderColor});
    else thumbContainer.setStyle({border:'0px'});
  },

  //
  // updateBottomNav()
  //
  updateBottomNav: function() {
    // Define visible thumb variables
    //-------------------------------
    var firstVisibleThumb, lastVisibleThumb, visibleThumbs = 0;
    for (var i = 0; i < this.navImages.length; i++) {
      if (! this.navImages[i]) continue;
      if (this.navImages[i].visible()) {
        visibleThumbs++;
        lastVisibleThumb = i;
        if (firstVisibleThumb == undefined)
          firstVisibleThumb = i;
      }
    }

    // Set the navImage border style property
    //---------------------------------------
    if (this.navImageBorder) {
      for (var i = firstVisibleThumb; i <= lastVisibleThumb; i++) {
        if (this.navImageBorder) {
          this.updateThumbnail(this.navImages[i], {
            border: (this.activeImage == i) ? true : false,
            visible: true
          });
        }
      }
    }

    // Preload additional thumbnails
    //------------------------------
    var indexHigh = lastVisibleThumb + this.maxThumbs;
    for (var i = lastVisibleThumb + 1; i < indexHigh; i++) {
      if (this.navImages[i] == undefined &&
          indexHigh < this.totalImages) {
        this.navImages[i] = new Element('div');
        this.buildThumbnail(i);
      }
    }

    // Display and Hide navImage elements based on navigation
    //-------------------------------------------------------
    // last visible is active, but not last overall
    if (this.activeImage == lastVisibleThumb && this.navImages[this.activeImage].next()) {
      this.navImages[this.activeImage - (this.maxThumbs - 1)].hide();
      this.navImages[this.activeImage].next().show();
    }
    // first visible is active, but not first overall)
    else if (this.activeImage == lastVisibleThumb - (this.maxThumbs - 1) &&
             this.activeImage > 0) {
      this.navImages[lastVisibleThumb].hide();
      this.navImages[this.activeImage].previous().show();
    }
    // last thumbnail is active
    else if (this.activeImage == this.navImages.length - 1) {
      for (var i = this.navImages.length - 1; i >= 0; i--) {
        if (i < this.navImages.length - this.maxThumbs)
          this.navImages[i].hide();
        else
          this.navImages[i].show();
      }
    }
    // first thumbnail is active
    else if (this.activeImage == 0) {
      for (var i = 0; i < this.navImages.length; i++) {
        if (! this.navImages[i]) continue;
        if (i < this.maxThumbs)
          this.navImages[i].show();
        else
          this.navImages[i].hide();
      }
    }

    // update visible thumbs for fullscreen and native state changes
    //--------------------------------------------------------------
    if (visibleThumbs != this.maxThumbs) {
      // visible thumbs is less than max thumbs
      if (visibleThumbs < this.maxThumbs) {
        // Display additional thumbnails
        for (i = firstVisibleThumb, j = lastVisibleThumb; visibleThumbs < this.maxThumbs; visibleThumbs++) {
          if (this.navImages[j].next()) {
            this.navImages[j].next().show();
            j++;
          } else if (this.navImages[i].previous()) {
            this.navImages[i].previous().show();
            --i;
          }
        }
      }
      // visible thumbs is greater than max thumbs
      else {
        for (i = firstVisibleThumb, j = lastVisibleThumb; visibleThumbs > this.maxThumbs; --visibleThumbs) {
          if (j > this.activeImage + 1) {
            this.navImages[j].hide();
            --j;
          } else {
            this.navImages[i].hide();
            i++;
          }
        }
        visibleThumbs = 0;
        firstVisibleThumb, lastVisibleThumb = undefined;
        for (i = 0; i < this.navImages.length; i++)
          if (this.navImages[i].visible()) {
            visibleThumbs++;
            lastVisibleThumb = i;
            if (firstVisibleThumb == undefined) firstVisibleThumb = i;
          }
        while (visibleThumbs > this.maxThumbs) {
          if (this.navImages[lastVisibleThumb].visible() && this.activeImage != lastVisibleThumb)
            this.navImages[lastVisibleThumb].hide();
          else
            this.navImages[firstVisibleThumb].hide();
          --visibleThumbs;
        }
      }
    }

    // Update controls object
    //-----------------------
    if (this.useControls) {
      if (this.activeImage == 0) {
        this.previousButton.setStyle({cursor:'auto'});
        this.previousButton.setOpacity(.5);
      } else if (this.activeImage == this.totalImages - 1) {
        this.nextButton.setStyle({cursor:'auto'});
        this.nextButton.setOpacity(.5);
      } else {
        this.previousButton.setStyle({cursor:'pointer'});
        this.previousButton.setOpacity(1);
        this.nextButton.setStyle({cursor:'pointer'});
        this.nextButton.setOpacity(1);
      }
    }
  },

  //
  // setNativeState()
  //
  setNativeState: function() {
	// Update state change buttons
	this.nativeStateButton.hide();
	this.fullScreenButton.show();
	
    // Redefine global size data members for rebuild
    this.maxWidth       = this.config.width || SlideShowOptions.width;
    this.maxHeight      = this.config.height || SlideShowOptions.height;
    this.imageHeight    = (this.bottomNav) ? this.maxHeight - this.navHeight : this.maxHeight;
    this.maxThumbs      = this.config.maxThumbs || SlideShowOptions.maxThumbs;

    // Redefine object container style attributes for rebuild
    this.container.setStyle({
      margin:           'auto',
      width:            this.maxWidth + 'px',
      height:           this.maxHeight + 'px',
      position:         'relative',
      top:              'auto',
      left:             'auto'
    });

    // Redefine navContainer object element style attributes for rebuild
    if (this.bottomNav)
      this.navContainer.setStyle({
        width: this.maxWidth - 8 + 'px',
        top: this.maxHeight - this.navContainer.getHeight() + 'px'
      });

    // Remove the screenOverlay object element
    this.screenOverlay.remove();

    // Hide the imageContainer and navContainer object elements
    this.imageContainer.hide();
    if (this.bottomNav) this.navContainer.hide();

    // Add object container element to original parent element
    if (typeof this.previousSibling != 'undefined')
      this.previousSibling.insert({
        after: this.container
      });
    else
      this.parentElement.insert({
        top: this.container
      });

    // invoke updateImage object method
    this.updateImage(this.activeImage);

    // Display the navContainer
    if (this.bottomNav) {
      if (! this.animation)
        this.navContainer.show();
      else
        this.navContainer.appear({
          from:       0.05,
          to:         1.0,
          duration:   this.animationSpeed
        });
    }
  },

  //
  // setFullScreenState()
  //
  setFullScreenState: function() {
    // Define screenWidth and screenHeight
    var pageSize      = this.getPageSize();
    var screenWidth   = pageSize[0];
    var screenHeight  = pageSize[1];

    // Define parentElement data member
    this.parentElement = this.container.getOffsetParent();
    this.previousSibling = this.container.previous();

    // Define screenOverlay element
    this.screenOverlay = new Element('div');
    this.screenOverlay.setStyle({
      margin:           'auto',
      width:            screenWidth + 'px',
      height:           screenHeight + 'px',
      position:         'absolute',
      top:              '0px',
      left:             '0px',
      backgroundColor:  '#000',
      display:          'none'
    });
    this.screenOverlay.observe('click',function(event){event.stop();});

    // Add screenOverlay to body element
    document.body.insert({bottom:this.screenOverlay});

    // Define onOverlayLoad event handler
    var onOverlayLoaded = (function() {
      // Redefine global size data members for rebuild
      var viewport        = document.viewport.getDimensions();
      this.maxWidth       = viewport.width - 20;
      this.maxHeight      = viewport.height - 20;
      this.imageHeight    = (this.bottomNav)
        ? viewport.height - (20 + this.navHeight)
        : viewport.height - 20;

      // Define object container style attributes for rebuild
      var viewOffsets = document.viewport.getScrollOffsets();
      this.container.setStyle({
        margin:           'auto',
        width:            this.maxWidth + 'px',
        height:           this.maxHeight + 'px',
        position:         'absolute',
        top:              (viewOffsets.top + 10) + 'px',
        left:             '10px'
      });
      // Add the object container element to the bottom of document body
      // to sit directly over the overLay element
      document.body.insert({bottom:this.container});

      // Redefine object member maxThumbs to increase thumbnail display
      for (var i = (this.thumbWidth + 5) * (this.maxThumbs + 1);
           i <= (this.maxWidth - (this.controls.getWidth() + 20));
           i += this.thumbWidth) this.maxThumbs++;

      // Hide the object elements (imageContainer and navContainer)
      // for rebuilding
      this.imageContainer.hide();
      if (this.bottomNav) this.navContainer.hide();

      // Redefine object element navContainer style attributes (rebuild)
      if (this.bottomNav)
        this.navContainer.setStyle({
          width: this.maxWidth - 8 + 'px',
          top: viewport.height - (20 + this.navContainer.getHeight()) + 'px'
        });

      // Invoke object method updateImage (rebuild)
      this.updateImage(this.activeImage);
      
      // Update state change buttons
      this.fullScreenButton.hide();
      this.nativeStateButton.show();

      // Display object element navContainer
      if (this.bottomNav) {
        if (! this.animation)
          this.navContainer.show();
        else
          this.navContainer.appear({
            from:       0.05,
            to:         1.0,
            duration:   this.animationSpeed
          });
      }
    }).bind(this);

    // Load the overlay and invoke onOverlayLoaded event handler
    this.screenOverlay.appear({
      from:         0.10,
      to:           0.80,
      duration:     .75,
      afterFinish:  onOverlayLoaded
    });
  },

  //
  // start()
  // auto play function
  start: function(imageIndex) {
    this.autoPlay = true;
  
    if (typeof this.controls != 'undefined' && this.usePlayButtons) {
      var playButton = this.controls.firstDescendant();
      playButton.setOpacity(.35);
      playButton.style.cursor = 'auto';
  
      var stopButton = playButton.next();
      stopButton.setOpacity(1);
      stopButton.style.cursor = 'pointer';
    }
  
    this.updateImage(imageIndex || this.activeImage + 1);
  },
  
  //
  // stop()
  // auto play function
  stop: function() {
    this.autoPlay = false;
    clearInterval(this.play);
    this.play = undefined;
  
    if (typeof this.controls != 'undefined' && this.usePlayButtons) {
      var playButton = this.controls.firstDescendant();
      playButton.setOpacity(1);
      playButton.style.cursor = 'pointer';
  
      var stopButton = playButton.next();
      stopButton.setOpacity(.35);
      stopButton.style.cursor = 'auto';
    }
  },

  //
  // getPageSize()
  //
  getPageSize: function() {
    var xScroll, yScroll;
    
    if (window.innerHeight && window.scrollMaxY) {  
      xScroll = window.innerWidth + window.scrollMaxX;
      yScroll = window.innerHeight + window.scrollMaxY;
    } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
      xScroll = document.body.scrollWidth;
      yScroll = document.body.scrollHeight;
    } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
      xScroll = document.body.offsetWidth;
      yScroll = document.body.offsetHeight;
    }
    
    var windowWidth, windowHeight;
    
    if (self.innerHeight) {  // all except Explorer
      if(document.documentElement.clientWidth){
        windowWidth = document.documentElement.clientWidth; 
      } else {
        windowWidth = self.innerWidth;
      }
      windowHeight = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
      windowWidth = document.documentElement.clientWidth;
      windowHeight = document.documentElement.clientHeight;
    } else if (document.body) { // other Explorers
      windowWidth = document.body.clientWidth;
      windowHeight = document.body.clientHeight;
    }  
    
    // for small pages with total height less then height of the viewport
    if(yScroll < windowHeight){
      pageHeight = windowHeight;
    } else { 
      pageHeight = yScroll;
    }
  
    // for small pages with total width less then width of the viewport
    if(xScroll < windowWidth){  
      pageWidth = xScroll;    
    } else {
      pageWidth = windowWidth;
    }

    return [pageWidth,pageHeight];
  }
};

