// 
// Simple Slide Show
//
// Author: 	Andrew Waer (awaer@einsteinindustries.com)
// Date: 	September 2008
// 

EI.namespace('SimpleSlideShow');

// The SimpleSlideShow constructor creates a new slide show.
//
// Requires: Prototype 1.6+
//
// Parameters:
//
//   slideShowElement:  The element (or string id of an element) to use for displaying the slide show, should be a <div>
//   imagesElement:     The element (or string id of an element) to search for slide show images
//   options:           Hash of key/value pairs, e.g. { height: '300px' }
// 
// Additional notes:
// 
//   Image height is adjusted to fit the height of the stage; default dimensions are 400x300. 
// 
//   To customize the look/feel, use these selectors:
// 
//    .simpleSlideShow_stage
//    .simpleSlideShow_description
//    .simpleSlideShow_navigation
//    .simpleSlideShow_prev, .simpleSlideShow_prev span
//    .simpleSlideShow_next, .simpleSlideShow_next span
//    .simpleSlideShow_index
// 

EI.SimpleSlideShow = function(slideShowElement, imagesElement, options) {

	var self = this;

	var _options           = options || {}

	var _slideShowElem     = $(slideShowElement);
	var _imagesElem        = $(imagesElement);
	var _stageElem         = (new Element('p')).addClassName('simpleSlideShow_stage');
	var _navigationElem    = (new Element('p')).addClassName('simpleSlideShow_navigation');
	var _descriptionElem   = (new Element('p')).addClassName('simpleSlideShow_description');
	var _currentImageElem  = null;
	var _currentIndex = 0;
	var _slideShowImages   = null;
	var _stageDefaultSize  = { 
		height: _options.height || '100%',
		width:  _options.width  || '100%'
	};

	// Searches element passed in constructor for any image tags & populates slide show images array
	// 
	var findSlideShowImages = function() {
		if (_imagesElem) {
			_imagesElem.hide();
			_slideShowImages = _imagesElem.select('img');
			return true;
		}
		return false;
	}

	// Setup essential elements for slide show display & navigation
	// 
	var buildSlideShowElements = function() {

		if (_slideShowElem) {
			_slideShowElem.appendChild(_stageElem);
			_slideShowElem.appendChild(_navigationElem);
			_slideShowElem.appendChild(_descriptionElem);

			buildSlideShowNavigation();

			_stageElem.setStyle(_stageDefaultSize);
		}
	}

	// Setup navigation elements and attach behavior for changing slide show image
	// 
	var buildSlideShowNavigation = function() {
		_navigationElem.update(
			'<a href="' + getPrevImage().readAttribute('src') + '" title="Previous Image" class="simpleSlideShow_prev"><span>&laquo; Prev</span></a>' + 
			' <span class="simpleSlideShow_index"></span> ' +
			'<a href="' + getNextImage().readAttribute('src') + '" title="Next Image" class="simpleSlideShow_next"><span>Next &raquo;</span></a>'
		);

		_navigationElem.down('a', 0).observe('click', function(e) {
			self.displayPreviousImage();
			Event.stop(e);
		});
		_navigationElem.down('a', 1).observe('click', function(e) {
			self.displayNextImage();
			Event.stop(e);
		});

		// Hide the navigation if only one image in our slideshow
		if (_slideShowImages.length == 1) {
			_navigationElem.hide();
		// Otherwise, attach nextImage behavior to images
		} else {
			_slideShowImages.each(function(item){
				item.observe('click', function(e) {
					self.displayNextImage();
					Event.stop(e);
				});
			});
		}
	}

	// Prepares slideshow & loads first image
	//
	var startSlideShow = function() {
		if (findSlideShowImages()) {
			buildSlideShowElements();

			if (_slideShowImages) {
				displayCurrentImage();
			}
		}
	}

	// Updates stage, navigation & description with current slide show image
	// 
	var displayCurrentImage = function() {
		_currentImageElem = getImageElem(_currentIndex);

		// Render (hidden) so we can find its dimensions before displaying
		_currentImageElem.setStyle({ visibility: 'hidden' });

		self.updateNavigation();
		self.updateDescription();

		_stageElem.update( _currentImageElem );
		fitImageToStage();

		// Now display image, after we've resized to fit stage
		_currentImageElem.setStyle({ visibility: 'visible' });
	}

	// Determine longest side of image and set to match stage
	// 
	var fitImageToStage = function() {
		var style = {};
		var imageDimensions = _currentImageElem.getDimensions();
		var stageDimensions = _stageElem.getDimensions();
		var imageRatio = imageDimensions.width / imageDimensions.height;
		var stageRatio = stageDimensions.width / stageDimensions.height;
		var sideToFix = stageRatio > imageRatio ? 'height' : 'width';
		style[sideToFix] = stageDimensions[sideToFix] + 'px';
		// Set width or height to fit image inside container
		_currentImageElem.setStyle(style);
		// Vertically-align image
		_currentImageElem.setStyle({
			marginTop: Math.max(0, (stageDimensions.height - _currentImageElem.getHeight()) / 2) + 'px'
		});
	}

	// Returns next image element from slide show images array
	// 
	var getNextImage = function() {
		return getImageElem( _currentIndex + 1 );
	}

	// Returns previous image element from slide show images array
	//
	var getPrevImage = function() {
		return getImageElem( _currentIndex - 1 );
	}

	// Returns image element from slide show images array
	//
	//   index:   (integer) index of image element
	// 
	var getImageElem = function(index) {
		return _slideShowImages[Math.abs(index) % _slideShowImages.length];
	}

	// Updates href attribute of navigation with image element src attribute values
	// 
	this.updateNavigation = function() {
		_navigationElem.down('a', 0).writeAttribute({ href: getPrevImage().readAttribute('src') })
		_navigationElem.down('a', 1).writeAttribute({ href: getNextImage().readAttribute('src') })
		$$('.simpleSlideShow_index')[0].update( 
			(_slideShowImages.indexOf(_currentImageElem) + 1) + ' of ' + _slideShowImages.length 
		);
	}

	// Updates description with alt attribute of current slide show image
	// 
	this.updateDescription = function() {
		_descriptionElem.update( _currentImageElem.readAttribute('alt') );
	}

	// Updates slide show stage with next image in images array
	// 
	this.displayNextImage = function() {
		_currentIndex += 1;
		displayCurrentImage();
	}

	// Updates slide show stage with previous image in images array
	// 
	this.displayPreviousImage = function() {
		_currentIndex -= 1;
		displayCurrentImage();
	}

	// Initializes slide show
	// 
	var initialize = function() {
		Event.observe(window, 'load', function() {
			startSlideShow();
		})
	}();	
}
