//Create namespace
YAHOO.namespace("customComponents");

//Shortcuts for YUI objects
var Dom = YAHOO.util.Dom;
var Event = YAHOO.util.Event;
var Anim = YAHOO.util.Anim;

//Create slide class
YAHOO.customComponents.SlideShowSlide = function(el, url) {
	//Make sure element exists
	var objEl = Dom.get(el);
	if (objEl != null) {
		//Store properties
		this._el = el;
		this._url = url;
		//Make sure element is set to display as block
		Dom.setStyle(this._el, "display", "block");
	} else {
		throw new Error("Slide element not found!");
	}
}

//Define slide class
YAHOO.customComponents.SlideShowSlide.prototype = {
	_el : null,

	_url : null,

	_transitionStyles : null,

	move : function(newParentEl) {
		//Move slide element to new parent
		newParentEl.appendChild(this._el);
	},

	gotoLink : function() {
		if (!YAHOO.lang.isNull(this._url)){
			window.location.href = this._url;
		}
	},

	show : function() {
		Dom.setStyle(this._el, "display", "none");
	},

	hide : function() {
		Dom.setStyle(this._el, "display", "block");
	},

	resize : function(intW, intH) {
		if (intW > 0 && intH > 0){
			this.setWidth(intW);
			this.setHeight(intH);
		}
	},

	setWidth : function(intW) {
		if (intW > 0){
			Dom.setStyle(this._el, "width", intW + "px");
		}
	},

	setHeight : function(intH) {
		if (intH > 0){
			Dom.setStyle(this._el, "height", intH + "px");
		}
	},

	setTransitionStyles : function(objStyles) {
		for (var strStyle in objStyles){
			Dom.setStyle(this._el, strStyle, objStyles[strStyle]);
		}
		this._transitionStyles = objStyles;
	},

	clearTransitionStyles : function() {
		for (var strStyle in this._transitionStyles){
			Dom.setStyle(this._el, strStyle, "");
		}
		this._transitionStyles = null;
	}
}

//Create slideshow class
YAHOO.customComponents.SlideShow = function(containerEl, objConfig) {
	//Get container
	var objC = Dom.get(containerEl);
	if (objC != null){
		//Set container and any initial config properties
		this._container = objC;
		for (var strProp in objConfig){
			switch (strProp){
				case "transitionType":
				case "slideDuration":
				case "transitionDuration":
				case "width":
				case "height":
					this["_" + strProp] = objConfig[strProp];
					break;
				default:
					break;
			}
		}
		//Initialize
		this.init();
	} else {
		throw new Error("Slideshow container not found!");
	}
};

//Define slideshow class
YAHOO.customComponents.SlideShow.prototype = {
	_container : null,

	_hiddenSlides : null,

	_currentSlideContainer : null,

	_nextSlideContainer : null,

	_slides : [],

	_currentSlide : -1,

	_nextSlide : -1,

	_playing : false,

	_slideDuration : 20000,

	_transitionDuration : 2000,

	_transitionType : "none",

	_width : null,

	_height : null,

	_cAnim : null,

	_validTransitions : ["wipeLeft", "wipeRight", "wipeUp", "wipeDown", "fade"],

	init : function() {
		//Hide container while manipulating the DOM
		Dom.setStyle(this._container, "display", "none");
		Dom.setStyle(this._container, "position", "relative");
		Dom.setStyle(this._container, "width", this._width + "px");
		Dom.setStyle(this._container, "height", this._height + "px");

		//Create containers for current and next slides
		this._nextSlideContainer = this._createSlideContainer();
		this._container.appendChild(this._nextSlideContainer);
		this._currentSlideContainer = this._createSlideContainer();
		this._container.appendChild(this._currentSlideContainer);

		//Create container for hiding slides
		this._hiddenSlides = document.createElement("div");
		Dom.setStyle(this._hiddenSlides, "display", "none");
		this._container.appendChild(this._hiddenSlides);

		//Get all the slides
		var arrSlides = Dom.getElementsByClassName("yui-slideshow-slide", null, this._container);
		var strLink = null;
		var objParent = null;

		for (var intI = 0; intI < arrSlides.length ; intI++){
			//Get the slide's parent to see if it was wrapped in a link
			objParent = arrSlides[intI].parentNode;
			//If the slide is wrapped in a link, set the link as the slide's target and remove the link
			if (objParent.tagName.toLowerCase() == "a"){
				//Get the link target and remove
				strLink = objParent.getAttribute("href");
				//Move slide to link's parent before removing link from doc tree
				objParent.parentNode.appendChild(arrSlides[intI]);
				objParent.parentNode.removeChild(objParent);
			}
			//Add slide and reset vars for next slide el
			this.addSlide(arrSlides[intI], strLink);
			strLink = null;
			objParent = null;
		}

		//Show container
		Dom.setStyle(this._container, "display", "block");

		//Listen for clicks on container
		Event.addListener(this._container, "click", this._handleSlideClick, this, true);
	},
	
	addSlide : function(el, strLink) {
		//Move the slide element to the hidden container
		this._hiddenSlides.appendChild(el);
		
		//Create slide and add to array to track slides
		objSlide = new YAHOO.customComponents.SlideShowSlide(el, strLink);
		objSlide.resize(this._width, this._height);
		this._slides.push(objSlide);
	},

	nextSlide : function() {
		//Make sure we have some slides
		var intSlides = this._slides.length;
		if (intSlides > 0){
			var nIndex;
			//Determine next slide's index
			if (intSlides == 1){
				nIndex = -1;
			} else if (this._currentSlide < intSlides - 1){
				nIndex = this._currentSlide + 1;
			} else {
				nIndex = 0;
			}
		
			//Make sure we have a next slide to go to
			if (nIndex != -1){
				this.gotoSlide(nIndex);
			}
		}
	},

	previousSlide : function() {
		//Make sure we have some slides
		var intSlides = this._slides.length;
		if (intSlides > 0){
			var pIndex;
			//Determine previous slide's index
			if (intSlides == 1){
				pIndex = -1;
			} else if (this._currentSlide == 0){
				pIndex = intSlides - 1;
			} else {
				pIndex = this._currentSlide - 1;
			}
		
			//Make sure we have a previous slide to go to
			if (pIndex != -1){
				this.gotoSlide(pIndex);
			}
		}
	},

	gotoSlide : function(index) {
		//Make sure the slide exists
		if (this._slides[index]){
			//Move the next slide into position
			this._slides[index].move(this._nextSlideContainer);

			//Set next slide property
			this._nextSlide = index;

			//Do transition between slides
			switch (this._transitionType){
				case "none":
					//Go immediately to end of transtion
					this._endTranstion();
					break;
				case "random":
					//Pick a random transition
					var t = this._validTransitions[(Math.floor(Math.random() * this._validTransitions.length))];
					//Start the transition
					this._startTransition(t);
					break;
				default:
					//Start the transition
					this._startTransition(this._transitionType);
					break;
			}
		}
	},

	_startTransition : function(trans) {
		if (trans){
			//Setup animation objects
			this._cAnim = new Anim(this._currentSlideContainer);
			this._cAnim.duration = this._transitionDuration / 1000;
			
			switch (trans){
				case "wipeLeft":
					this._cAnim.attributes.width = { to : 1 };
					this._cAnim.onComplete.subscribe(this._handleTransitionComplete, this, true);
					this._cAnim.animate();
					break;
				case "wipeRight":
					this._slides[this._currentSlide].setTransitionStyles({
						position : "absolute",
						right : "0"
					});
					this._cAnim.attributes.width = { to : 1 };
					this._cAnim.attributes.left = { to : this._width };
					this._cAnim.onComplete.subscribe(this._handleTransitionComplete, this, true);
					this._cAnim.animate();
					break;
				case "wipeDown":
					this._slides[this._currentSlide].setTransitionStyles({
						position : "absolute",
						bottom : "0"
					});
					this._cAnim.attributes.height = { to : 1 };
					this._cAnim.attributes.top = { to : this._height };
					this._cAnim.onComplete.subscribe(this._handleTransitionComplete, this, true);
					this._cAnim.animate();
					break;
				case "wipeUp":
					this._cAnim.attributes.height = { to : 1 };
					this._cAnim.onComplete.subscribe(this._handleTransitionComplete, this, true);
					this._cAnim.animate();
					break;
				case "fade":
					this._cAnim.attributes.opacity = { to : 0 };
					this._cAnim.onComplete.subscribe(this._handleTransitionComplete, this, true);
					this._cAnim.animate();
					break;
				default:
					//Transition was of unknown type, so go immediately to end of transtion
					this._endTransition();
					break;
			}
		}

	},

	_endTransition : function() {
		//Swap current and next containers in doc tree
		this._container.insertBefore(this._nextSlideContainer, this._currentSlideContainer);
		//Move current slide to hidden container and remove that container
		this._slides[this._currentSlide].move(this._hiddenSlides);
		this._container.removeChild(this._currentSlideContainer);

		//Clear any styles on that slide
		this._slides[this._currentSlide].clearTransitionStyles();

		//Swap current and next slide container refs
		this._currentSlideContainer = this._nextSlideContainer;

		//Replace next slide container with a fresh container
		var objNewC = this._createSlideContainer();
		this._container.insertBefore(objNewC, this._currentSlideContainer);
		this._nextSlideContainer = objNewC;

		//Update current slide
		this._currentSlide = this._nextSlide;
		this._nextSlide = -1;

		//Start next timer if playing
		if (this._playing){
			var me = this;
			window.setTimeout(function() {
				me._handleSlideTimer.apply(me);
			}, this._slideDuration);
		}
	},

	_handleTransitionComplete : function(e) {
		//Remove listeners
		this._cAnim.onComplete.unsubscribeAll();
		//End transition
		this._endTransition();
	},

	play : function() {
		//See if we are playing already
		if (!this._playing){
			//Make sure we have slides
			if (this._slides.length > 0){
				//See if this is our first play
				if (this._currentSlide == -1 ){
					this._currentSlide = 0;
					//Move current slide into position
					this._slides[this._currentSlide].move(this._currentSlideContainer);
				}
				this._playing = true;
				//Start timer til next slide
				var me = this;
				window.setTimeout(function() {
					me._handleSlideTimer.apply(me);
				}, this._slideDuration);
			}
		}
	},

	stop : function() {
		this._playing = false;
	},

	_handleSlideTimer : function() {
		//Make sure we're still playing
		if (this._playing){
			this.nextSlide();
		}
	},

	_createSlideContainer : function() {
		var d;
		d = document.createElement("div");
		this._resetSlideContainer(d);
		return d;
	},

	_resetSlideContainer : function(d) {
		Dom.setStyle(d, "position", "absolute");
		Dom.setStyle(d, "left", "0");
		Dom.setStyle(d, "top", "0");
		Dom.setStyle(d, "width", this._width + "px");
		Dom.setStyle(d, "height", this._height + "px");
		Dom.setStyle(d, "overflow", "hidden");
		Dom.setStyle(d, "opacity", 1.0);
		Dom.setStyle(d, "background-color", "transparent");
	},

	_handleSlideClick : function(e){
		this._slides[this._currentSlide].gotoLink();
	}
};