/**
 * @author Hollin Wilkins
 * @version 1.0
 */

ILR.namespace("SlideShow");

if( !ILR.SlideShow.LightBox ) {
	/**
	 * Provides a lightbox view of a slide show.
	 * @namespace ILR.SlideShow
	 * @class LightBox
	 * @extends YAHOO.widget.Panel
	 * @constructor
	 * @param {String} slideShowId The guid for this slide show
	 * @param {Object} userConfig The configuration object literal containing the configuration that should be set for this Overlay. See configuration documentation for more details.
	 */
	ILR.SlideShow.LightBox = function(slideShowId, userConfig) {
		ILR.SlideShow.LightBox.superclass.constructor.call(this);
		
		if( slideShowId ) {
			this._SLIDE_SHOW_ID = slideShowId;
			
			// removed www.ilr.cornell.edu from URL
			var url = "/ajaxWrapper/include.cfm?ajaxUrl=/codelib/apps/slideshow/public/ajax/lightbox.panel.cfm&slideShowId=" + this._SLIDE_SHOW_ID + "&rand=" + Math.random();
			
			YAHOO.widget.Module.prototype.HTTPInit.call(this, url, "slideShow_lightBox", userConfig);
		} else {
			// do nothing
		}
	};
	
	/**
	 * Ajax callback for handling initalizing the list of slides for a light box
	 * @property ILR.SlideShow.LightBox._InitSlidesCallback
	 * @type Object
	 * @final
	 * @static
	 * @private
	 */
	ILR.SlideShow.LightBox._InitSlidesCallback = {
		/**
		 * Handles a successful load of the slides
		 * @property ILR.SlideShow.LightBox._InitSlidesCallback.success
		 * @type Function
		 * @final
		 * @static
		 * @private
		 */
		success:function(o) {
			var slides = YAHOO.Tools.JSONParse(o.responseText);
			
			for( var i = 0; i < slides.length; ++i ) {
				this.addSlide(new ILR.SlideShow.Slide(slides[i]));
			}
			
			YAHOO.util.Dom.removeClass("navigation_start", "hidden");
			YAHOO.util.Dom.addClass("navigation_loader", "hidden");
			this._SLIDES_READY = true;
		},
		
		/**
		 * Handles a failed load of the slides
		 * @property ILR.SlideShow.LightBox._InitSlidesCallback.failure
		 * @type Function
		 * @final
		 * @static
		 * @private
		 */
		failure:function(o) {
			// do nothing
		}
	};
	
	/**
	 * Constant representing the LightBox's configuration properties
	 * @property ILR.SlideShow.LightBox._DEFAULT_CONFIG
	 * @private
	 * @final
	 * @type Object
	 */
	ILR.SlideShow.LightBox._DEFAULT_CONFIG = {
	    "SLIDE_INDEX": { 
	        key:"slideIndex", 
	        value:-1, 
	        validator:YAHOO.lang.isInteger
	    }
	};
	
	YAHOO.extend(ILR.SlideShow.LightBox, YAHOO.widget.Panel, {
		/**
		 * The guid for the slide show.
		 * @property _SLIDE_SHOW_ID
		 * @type String
		 * @private
		 */
		_SLIDE_SHOW_ID: null,
		
		/**
		 * All slides that are in the slide show.
		 * @property _SLIDES
		 * @type Array
		 * @private
		 */
		_SLIDES: null,
		
		/**
		 * Array of the index's of slides.
		 * @property _SLIDES_INDEX
		 * @type Object
		 * @private
		 */
		_SLIDES_INDEX: null,
		
		/**
		 * The body module.
		 * @property _BODY_MODULE
		 * @type YAHOO.widget.Module
		 * @private
		 */
		_BODY_MODULE: null,
		
		/**
		 * The slide image view size.
		 * @property _SLIDE_VIEW
		 * @type String
		 * @private
		 */
		_SLIDE_VIEW: "large",
		
		/**
		 * A list of indices of active slides.
		 * @property _ACTIVE_SLIDE_INDICES
		 * @type Array
		 * @private
		 */
		_ACTIVE_SLIDE_INDICES: [],
		
		/**
		 * The carousel object for moving between slides.
		 * @property _CAROUSEL
		 * @type YAHOO.extension.Carousel
		 * @private
		 */
		_CAROUSEL: null,
		
		/**
		 * How many items are visible in the carousel.
		 * @property _CAROUSEL_ITEMS
		 * @type Integer
		 * @private
		 */
		_CAROUSEL_ITEMS: 11,
		
		/**
		 * The slider that controls the speed of the slide show.
		 * @property _SPEED_SLIDER
		 * @type YAHOO.widget.Slider
		 * @private
		 */
		_SPEED_SLIDER: null,
		
		/**
		 * The width of the slider that controls the speed of the slide show.
		 * @property _SPEED_SLIDER_WIDTH
		 * @type Integer
		 * @private
		 */
		_SPEED_SLIDER_WIDTH: 114,
		
		/**
		 * The fastest speed the slide show can run at in milliseconds.
		 * @property _SPEED_FAST
		 * @type Integer
		 * @private
		 */
		_SPEED_FAST: 2000,
		
		/**
		 * The slowest speed the slide show can run at in milliseconds.
		 * @property _SPEED_SLOW
		 * @type Integer
		 * @private
		 */
		_SPEED_SLOW: 8000,
		
		/**
		 * The slide show timing interval (used when playing slide show).
		 * @property _INTERVAL
		 * @type Object
		 * @private
		 */
		_INTERVAL: null,
		
		/**
		 * Whether or not to change the interval after the next slide is displayed.
		 * @property _CHANGE_INTERVAL
		 * @type Boolean
		 * @private
		 */
		_CHANGE_INTERVAL: false,
		
		/**
		 * The time that animation effects take to complete. (should be config property)
		 * @property _TRANSITION_TIME
		 * @type Integer
		 * @private
		 */
		_TRANSITION_TIME: .4,
		
		/**
		 * Whether or not the lightbox is in the middle of a transition.
		 * @property _IN_TRANSITION
		 * @type Boolean
		 * @private
		 */
		_IN_TRANSITION: false,
		
		/**
		 * Whether all the slides are loaded and the lightbox is ready to be opened.
		 * @property _SLIDES_READY
		 * @type Boolean
		 * @private
		 */
		_SLIDES_READY: false,
		
		/**
		 * Initializes the light box.
		 * @method init
		 * @param {String} el The element ID representing the Overlay <em>OR</em>
		 * @param {HTMLElement} el The element representing the Overlay
		 * @param {Object} userConfig The configuration object literal containing the configuration that should be set for this Overlay. See configuration documentation for more details.
		 */
		init:function(el, userConfig) {
			ILR.SlideShow.LightBox.superclass.init.call(this, el/*, userConfig*/); // Note that we don't pass the user config in here yet because we only want it executed once, at the lowest subclass level
			
			this.beforeInitEvent.fire(ILR.SlideShow.LightBox);
			
			if (userConfig) {
				this.cfg.applyConfig(userConfig, true);
			}
			
			this._SLIDES_READY = false;
			
			// initialize the image module
			this._BODY_MODULE = new YAHOO.widget.Module(this.body);
			this._BODY_MODULE.hide();
			
			// initialize the carousel
			this._CAROUSEL = new YAHOO.extension.Carousel(
				"lightBox_carousel",
				{
					numVisible: this._CAROUSEL_ITEMS,
					scrollInc: this._CAROUSEL_ITEMS,
					animationSpeed: .30,
					navMargin: 42,
					prevElement: "lightBox_navigation_previous",
					nextElement: "lightBox_navigation_next",
					size: 0
				}
			);
			this._CAROUSEL.hide();
			
			// initalize the speed control slider
			this._SPEED_SLIDER = YAHOO.widget.Slider.getHorizSlider("lightBox_slider_bg", "lightBox_slider_thumb", 0, this._SPEED_SLIDER_WIDTH);
			this._SPEED_SLIDER.backgroundEnabled = false;
			this._SPEED_SLIDER.setValue(this._SPEED_SLIDER_WIDTH/2);
			this._SPEED_SLIDER.subscribe("slideEnd", this.handleOnSliderEnd, this, true);
			
			var fadeFn = function(ev) {
				this._IN_TRANSITION = true;
				
				YAHOO.widget.Effects.Appear("lightBox_information", {seconds: this._TRANSITION_TIME});
				var eff1 = new YAHOO.widget.Effects.Appear("lightBox_image", {seconds: this._TRANSITION_TIME});
				eff1.onEffectComplete.subscribe(
					function() {
						this._IN_TRANSITION = false;
					},
					this,
					true
				);
				
				this._BODY_MODULE.show();
			};
			YAHOO.util.Event.addListener("lightBox_slide_image", "load", fadeFn, this, true);
			
			YAHOO.util.Event.addListener(window, "resize", this.handleWindowResize, this, true);
			YAHOO.util.Event.addListener(document, "keydown", this.handleArrowKeys, this, true);
			
			this.switchPlayButton("pause");
			this.switchSizeButton("medium");
			this.initSlides();
			this.render();
			this.center();
			
			this.initEvent.fire(ILR.SlideShow.LightBox);
		},
		
		/**
		 * Initializes the class's configurable properties which can be changed using the LightBox's Config object (cfg).
		 * @method initDefaultConfig
		 */
		initDefaultConfig:function() {
			ILR.SlideShow.LightBox.superclass.initDefaultConfig.call(this);
		
		    // Add lightbox config properties //
		
		    var DEFAULT_CONFIG = ILR.SlideShow.LightBox._DEFAULT_CONFIG;
		
			/**
			* The index of the current slide being displayed
			* @config slideIndex
			* @type Integer
			* @default 0
			*/
		    this.cfg.addProperty(
                DEFAULT_CONFIG.SLIDE_INDEX.key,
                { 
                    handler: this.configSlideIndex, 
                    value: DEFAULT_CONFIG.SLIDE_INDEX.value, 
                    validator: DEFAULT_CONFIG.SLIDE_INDEX.validator
                } 
            );
		},
		
		/**
		 * Initializes the list of slides.
		 * @method initSlides
		 */
		initSlides:function() {
			this._SLIDES = [];
			this._SLIDES_INDEX = {};
			
			var callback = {
				success: ILR.SlideShow.LightBox._InitSlidesCallback.success,
				failure: ILR.SlideShow.LightBox._InitSlidesCallback.failure,
				scope: this
			};
			
			// removed www.ilr.cornell.edu from URL
			var url = "/ajaxWrapper/include.cfm?ajaxUrl=/codelib/apps/slideshow/public/ajax/getSlides.cfm&slideShowId=" + this._SLIDE_SHOW_ID;
			YAHOO.util.Connect.asyncRequest("GET", url, callback)
		},
		
		/**
		 * The default event handler fired when the "slideIndex" property is changed. The method controls the current slide being displayed.
		 * @method configSlideIndex
		 * @param {String} type The CustomEvent type (usually the property name)
		 * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
		 * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner.
		 */
		configSlideIndex:function(type, args, obj) {
			if( this._ACTIVE_SLIDE_INDICES.length > 0 ) {
				YAHOO.util.Dom.removeClass(this._ACTIVE_SLIDE_INDICES, "active");
				this._ACTIVE_SLIDE_INDICES = [];
			}
			
			if( args[0] >= 0 ) {
				var slide = this._SLIDES[args[0]];
				
				document.getElementById("lightBox_slide_image").src = slide.getImageLink(this._SLIDE_VIEW);
				document.getElementById("lightBox_slide_title").innerHTML = slide.title;
				document.getElementById("lightBox_slide_description").innerHTML = slide.description;
				document.getElementById("lightBox_slide_date").innerHTML = slide.date;
				document.getElementById("lightBox_slide_author").innerHTML = slide.author;
				
				this._ACTIVE_SLIDE_INDICES.push("lightBox_carousel-item-" + (args[0] + 1));
				YAHOO.util.Dom.addClass("lightBox_carousel-item-" + (args[0] + 1), "active");
			
				// scroll the carousel to the slide if it is the first
				// in a list
				if( args[0] % this._CAROUSEL_ITEMS == 0 ) {
					this._CAROUSEL.scrollTo(args[0] + 1);
				}
			}
			
			// pre-load next slide
			if( this.cfg.getProperty("slideIndex") < this._SLIDES.length - 1 ) {
				var slide = this._SLIDES[this.cfg.getProperty("slideIndex") + 1];
				if( !document.getElementById("img-" + slide.id) ) {
					var img = new Image();
					
					img.id = "img-" + slide.id;
					YAHOO.util.Dom.setStyle(img, "display", "none");
					img.src = slide.getImageLink(this._SLIDE_VIEW);
				
					document.body.appendChild(img);
				}
			}
		},
		
		/**
		 * Handles when the speed slider has changed values.
		 * @method handleOnSliderEnd
		 */
		handleOnSliderEnd:function() {
			this._CHANGE_INTERVAL = true;
		},
		
		/**
		 * Handles when the window is resized.
		 * @method handleWindowResize
		 */
		handleWindowResize:function(ev, obj) {
			var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
			
			var viewPortWidth = YAHOO.util.Dom.getClientWidth();
			
			var elementWidth = this.element.offsetWidth;
			
			var x = (viewPortWidth / 2) - (elementWidth / 2) + scrollX;
			
			this.cfg.setProperty("x", parseInt(x, 10));
		
			this.cfg.refireEvent("iframe");
		},
		
		/**
		 * Handles playing the slide show.
		 * @method handlePlay
		 * @param {Event} ev The event
		 */
		handlePlay:function(ev) {
			// Stop event if it is defined
			if( ev ) {
				YAHOO.util.Event.stopEvent(ev);
			}
			
			this.play();
		},
		
		/**
		 * Handles pausing the slide show.
		 * @method handlePause
		 * @param {Event} ev The event
		 */
		handlePause:function(ev) {
			// Stop event if it is defined
			if( ev ) {
				YAHOO.util.Event.stopEvent(ev);
			}
			
			this.pause();
		},
		
		/**
		 * Handles switching to xlarge image size.
		 * @method handleXlargeSize
		 * @param {Event} ev The event
		 */
		handleXlargeSize:function(ev) {
			// Stop event if it is defined
			if( ev ) {
				YAHOO.util.Event.stopEvent(ev);
			}
			
			this.changeSize("xlarge");
		},
		
		/**
		 * Handles switching to large image size.
		 * @method handleLargeSize
		 * @param {Event} ev The event
		 */
		handleLargeSize:function(ev) {
			// Stop event if it is defined
			if( ev ) {
				YAHOO.util.Event.stopEvent(ev);
			}
			
			this.changeSize("large");
		},
		
		/**
		 * Handles left and right arrow keys to move between slide.
		 * @method handleArrowKeys
		 * @param {Event} ev The event
		 */
		handleArrowKeys:function(ev) {
			if( this.cfg.getProperty("visible") ) {
				
				// left arrow
				if( ev.keyCode == 37 ) {
					this.pause();
					this.previousSlide();
				}
				
				// right arrow
				if( ev.keyCode == 39 ) {
					this.pause();
					this.nextSlide();
				}
			}
		},
		
		/**
		 * Display the light box.
		 * @method show
		 * @param {ILR.SlideShow.Slide} slide The first slide to display
		 */
		show:function(slide) {
			if( !this._SLIDES_READY ) {
				return;
			}
			
			var index = 0;
			
			if( slide ) {
				index = this._SLIDES_INDEX[slide.id];
			}
			
			if( this.cfg.getProperty("slideIndex") != index ) {
				this.cfg.setProperty("slideIndex", index);
			}
			
			// deal with abnormal display modules
			this._CAROUSEL.show();
			
			scroll(0,0);
			ILR.SlideShow.LightBox.superclass.show.call(this);
			
			this.play();
		},
		
		/**
		 * Hide the light box.
		 * @method hide
		 */
		hide:function() {
			if( !this._IN_TRANSITION ) {
				// deal with abnormal display modules
				this._BODY_MODULE.hide();
				this._CAROUSEL.hide();
				
				this.pause();
				
				ILR.SlideShow.LightBox.superclass.hide.call(this);
			} else {	
				this.pause();
				
				obj = this;
				
				var hideFn = function() {
					obj.hide();
				}
				
				setTimeout(hideFn,this._TRANSITION_TIME * 1000);
			}
		},
		
		/**
		 * Adds a slide to the list of slides in the slide show.
		 * @method addSlide
		 * @param {ILR.SlideShow.Slide} slide The slide to add to the show
		 */
		addSlide:function(slide) {
			this._SLIDES.push(slide);
			this._SLIDES_INDEX[slide.id] = this._SLIDES.length - 1;
			
			if( (this._SLIDES.length - 1) % this._CAROUSEL_ITEMS == 0 ) {
				this._CAROUSEL.size += this._CAROUSEL_ITEMS;
			}
			
			var li = document.createElement("li");
			var a = document.createElement("a");
			var img = document.createElement("img");
			
			li.id = "lightBox_carousel-item-" + this._SLIDES.length;
			YAHOO.util.Dom.addClass(li, "carouselItem");
			
			a.href = "";
			
			img.src = slide.getImageLink("thumbnail");
			img.alt = "A photo";
			
			li.appendChild(a);
			a.appendChild(img);
			
			document.getElementById("lightBox_navigation_slides").appendChild(li);
			
			var wrapFn = function(ev) {
				/* stop the event */
				YAHOO.util.Event.stopEvent(ev);
				
				this.pause();
				this.switchSlide(slide);
			};
			YAHOO.util.Event.addListener(li, "click", wrapFn, this, true);
		},
		
		/**
		 * Switch slide show light box to another slide.
		 * @method switchSlide
		 * @param {ILR.SlideShow.Slide} slide The slide to switch to
		 */
		switchSlide:function(slide) {
			if( this._SLIDES_INDEX[slide.id] >= this._SLIDES.length - 1 ) {
				this.pause();
			}
			
			this._IN_TRANSITION = true;
			YAHOO.widget.Effects.Fade("lightBox_information", {seconds: this._TRANSITION_TIME});
			var eff1 = new YAHOO.widget.Effects.Fade("lightBox_image", {seconds: this._TRANSITION_TIME});
			eff1.onEffectComplete.subscribe(
				function() {
					this.cfg.setProperty("slideIndex", this._SLIDES_INDEX[slide.id]);
					this._IN_TRANSITION = false;
				},
				this,
				true
			);
		},
		
		/**
		 * Switches to the next slide.
		 * @method nextSlide
		 */
		nextSlide:function() {
			this.switchSlide(this._SLIDES[this.cfg.getProperty("slideIndex") + 1]);
		},
		
		/**
		 * Switches to the previous slide.
		 * @method previousSlide
		 */
		previousSlide:function() {
			if( this.cfg.getProperty("slideIndex") > 0 ) {
				this.switchSlide(this._SLIDES[this.cfg.getProperty("slideIndex") - 1]);
			}
		},
		
		/**
		 * Gets the current speed of the slide show.
		 * @method getSpeed
		 * @return {Integer} The current speed per slide in milliseconds
		 */
		getSpeed:function() {
			var offset = this._SPEED_SLIDER_WIDTH - this._SPEED_SLIDER.getValue();
			offset *= ((this._SPEED_SLOW - this._SPEED_FAST)/this._SPEED_SLIDER_WIDTH);
			
			return this._SPEED_FAST + offset;
		},
		
		/**
		 * Plays the slide show (automatically cycles through photos until end).
		 * @method play
		 */
		play:function() {
			if( this.cfg.getProperty("slideIndex") >= this._SLIDES.length - 1 ) {
				this.switchSlide(this._SLIDES[0]);
			}
			
			if( this._INTERVAL ) {
				this._CHANGE_INTERVAL = true;
			}
			
			var obj = this;
			var wrapFn = function() {
				if( obj._CHANGE_INTERVAL ) {
					if( obj._INTERVAL ) {
						window.clearInterval(obj._INTERVAL);
					}
					obj._CHANGE_INTERVAL = false;
					obj.play();
				}
				
				obj.nextSlide();
			};
			this._INTERVAL = window.setInterval(wrapFn, this.getSpeed());
			
			this.switchPlayButton("play");
		},
		
		/**
		 * Pause the slide show.
		 * @method pause
		 */
		pause:function() {
			if( this._INTERVAL ) {
				window.clearInterval(this._INTERVAL);
			}
			
			this.switchPlayButton("pause");
		},
		
		/**
		 * Switches between different sizes of images
		 * @method changeSize
		 * @param {String} view The view to change the images to
		 */
		changeSize:function(view) {
			this._SLIDE_VIEW = view;
			this.switchSizeButton(view);
			this.switchSlide(this._SLIDES[this.cfg.getProperty("slideIndex")]);
		},
		
		/**
		 * Switch the state of the play button.
		 * @method switchPlayButton
		 * @param {String} state The state that the slide show will be in
		 */
		switchPlayButton:function(state) {
			var playButton = document.getElementById("lightBox_play");
			YAHOO.util.Event.removeListener(playButton, "click");
			
			switch( state ) {
				case "play":
					YAHOO.util.Dom.removeClass(playButton, "play");
					YAHOO.util.Dom.addClass(playButton, "pause");
					YAHOO.util.Event.addListener(playButton, "click", this.handlePause, this, true);
					break;
				case "pause":
				default:
					YAHOO.util.Dom.removeClass(playButton, "pause");
					YAHOO.util.Dom.addClass(playButton, "play");
					playButton.src = "/codelib/apps/slideshow/images/carousel/play.gif";
					YAHOO.util.Event.addListener(playButton, "click", this.handlePlay, this, true);
			}
		},
		
		/**
		 * Switch the state of the size button.
		 * @method switchSizeButton
		 * @param {String} state The size of image to display
		 */
		switchSizeButton:function(state) {
			var sizeButton = document.getElementById("lightBox_size");
			YAHOO.util.Event.removeListener(sizeButton, "click");
			
			switch( state ) {
				case "xlarge":
					YAHOO.util.Dom.removeClass(sizeButton, "enlarge");
					YAHOO.util.Dom.addClass(sizeButton, "delarge");
					YAHOO.util.Event.addListener(sizeButton, "click", this.handleLargeSize, this, true);
					break;
				case "large":
				default:
					YAHOO.util.Dom.removeClass(sizeButton, "delarge");
					YAHOO.util.Dom.addClass(sizeButton, "enlarge");
					YAHOO.util.Event.addListener(sizeButton, "click", this.handleXlargeSize, this, true);
			}
		}
	});
}