/*
	Anchor Slideshow.
	A YUI implementation of the overly popular slideshow effect that can be seen on 
	http://www.beanstalkapp.com/
	http://www.icebrrg.com/
	
	TODO - 
		Extract the link click behaviour into an ActionManager
			- the action manger could work based on clicked links, 
			- timed actons
			- mouse overs
		
		Cache references to frames to avoid the lookups.
		Allow options to be passed in to control: 
			time controlled movement, frame class name, direction(vertical/horizontal), animation effect
		Check if padding on internal elements alters the height calculations.  Not a bit problem, just use frame as a non-semantic wrapper.
*/
YAHOO.namespace("Leftbrained");
//The wrapper
YAHOO.namespace("Leftbrained.FacettedPanel");
//The animation handlers
YAHOO.namespace("Leftbrained.SlideTransition");
YAHOO.namespace("Leftbrained.FadeTransition");
//The trigger handlers.
YAHOO.namespace("Leftbrained.LinkAction");
//The trigger handlers.
YAHOO.namespace("Leftbrained.TimedAction");
(function(){
	var $D = YAHOO.util.Dom;
	var $E = YAHOO.util.Event;
	var $L = YAHOO.Leftbrained;

	/***********************************************
	Move between slides on a link click.
	***********************************************/
	$L.LinkAction = function() {
		this.NAME = "LinkAction";
	};
	
	$L.LinkAction.prototype.setup = function() {	
		$E.on(document, 'click', this.processClick, null, this);
	}
	
	$L.LinkAction.prototype.setSlideshow = function(slideshow) {
		this.slideshow = slideshow;
	}
	
	$L.LinkAction.prototype.processClick = function(e) {
		var source = $E.getTarget(e);
		source = ( (!source) || (source.nodeName=="A") ) ? source : $D.getAncestorByTagName(source, 'A')
		if( (!source) || (source.nodeName!="A")) { return; }
		var anchor = new RegExp("#(.*)").exec(source.href);
		if(!anchor) { return; }

		// DOES THE LINK HAVE A CLASSNAME THAT INDICATES BEHAVIOUR?
		if($D.hasClass(source, this.slideshow.nextLinkClassName())) {
			$E.stopEvent(e);
			this.slideshow.animationManager.slideTo(this.slideshow.nextFrame());
			return;
		}

		// DOES THE LINK HAVE A CLASSNAME THAT INDICATES BEHAVIOUR?
		if($D.hasClass(source, this.slideshow.previousLinkClassName())) {
			$E.stopEvent(e);
			this.slideshow.animationManager.slideTo(this.slideshow.previousFrame());
			return;
		}
		
		// DOES THE LINK POINT TO ME?
		anchor = anchor[1];
		if(this.slideshow.hasSlideFor(anchor)) {
			$E.stopEvent(e);
			this.slideshow.animationManager.slideTo(anchor);
			return
		}	
	}
	
	$L.TimedAction = function() {
		this.NAME = "TimedAction";
	};
	
	$L.TimedAction.prototype.setup = function() {	
		YAHOO.lang.later(4000 , this , 'changeSlide', null, true);
	}
	
	$L.TimedAction.prototype.setSlideshow = function(slideshow) {
		this.slideshow = slideshow;
	}
	
	$L.TimedAction.prototype.changeSlide = function(e) {
		this.slideshow.animationManager.slideTo(this.slideshow.nextFrame());
	}
	
	/***********************************************
	Over arching manager for dealing with slides.
	***********************************************/
	$L.FacettedPanel = function(el, options) {
		this.NAME = "FacettedPanel";
		if (!el) {
			YAHOO.log('element required to create FacettedPanel instance', 'error', 'FacettedPanel');
		}
		this.init(el, options);
	};

	$L.FacettedPanel.prototype.init = function(el, options) {
		this.el = $D.get(el);
		this.frameClassName = this.el.id+"Frame";
		options = options || {};
		this.postChangeCallback = options.postChangeCallback || function(){};
		this.animationManager = new (options.animationManager || YAHOO.Leftbrained.SlideTransition);
		this.animationManager.setSlideshow(this);
		this.actionManager = new (options.actionManager || YAHOO.Leftbrained.LinkAction);	
		this.actionManager.setSlideshow(this);	
		this.billboard = $D.getFirstChild(this.el);
		this.currentFrame = null;	
	};
	
	$L.FacettedPanel.prototype.nextLinkClassName = function() {
		return this.el.id+"NextLink";
	}
	
	$L.FacettedPanel.prototype.previousLinkClassName = function() {
		return this.el.id+"PreviousLink";
	}
	

	$L.FacettedPanel.prototype.render = function() {
		this.animationManager.applyStylesToWrapper();
		this.animationManager.applyStylesToFrames();
		this.gotoFirstFrame();
		this.actionManager.setup();
	}

	$L.FacettedPanel.prototype.gotoFirstFrame = function() {
		var firstFrame = this.getFrames()[0];
		this.setCurrentFrame(firstFrame);
		this.animationManager.slideTo(firstFrame);
	}
	$L.FacettedPanel.prototype.nextFrame = function() {
		var frames = this.getFrames();
		var nextFrame = frames[0];
		for(var i=0; i<frames.length; i++) {
			var frame = frames[i];
			if((this.currentFrame == frame) && (i+1 < frames.length)) {
				nextFrame = frames[i+1];
				break;
			}
		}
		return nextFrame;
	}
	
	$L.FacettedPanel.prototype.previousFrame = function() {
		var frames = this.getFrames();
		var previousFrame = frames[frames.length-1];
		for(var i=0; i<frames.length; i++) {
			var frame = frames[i];
			if((this.currentFrame == frame) && (i-1 >= 0)) {
				previousFrame = frames[i-1];
				break;
			}
		}
		return previousFrame;
	}
	
	

	$L.FacettedPanel.prototype.setCurrentFrame = function(frame) {
		this.currentFrame = frame;
		//we'd update classes here to hightlight a nominated link if required.
		var links = $D.getElementsByClassName(this.el.id+"-nav");
		for(var i=0; i<links.length; i++) {
			if($D.hasClass(links[i], this.el.id+"-nav-"+this.currentFrame.id)) {
				$D.addClass(links[i], 'active');
			} else {
				$D.removeClass(links[i], 'active');
			}
		}
		this.postChangeCallback(frame, this.getFrames());
	}

/*
		The workhorse function, listen for all clicks and process them if they relate to my slideshow.
*/
	$L.FacettedPanel.prototype.hasSlideFor = function(id) {
		var target = $D.get(id);
		var frames = this.getFrames();
		for(var i=0; i<frames.length; i++) {
			var frame = frames[i];
			if(frame == target){ return true;}
		}
		return false;
	}

	$L.FacettedPanel.prototype.toString = function() {
	    var el = this.getEl() || {};
	    var id = el.id || el.tagName;
	    return (this.NAME + ': ' + id);
	}

	$L.FacettedPanel.prototype.getFrames = function() {
		return $D.getElementsByClassName(this.frameClassName, null, this.el);
	}

	/***********************************************
		Horizontal/Vertical slide transition manager.
	***********************************************/
	$L.SlideTransition = function(attributes) {
		this.NAME = "FacettedPanel";
		this.init(attributes);
	};

	 $L.SlideTransition.prototype.init = function(attribs) {
	 	this.attribs = attribs;
		this.slideshow = null;
		this.currentlyMoving = false;
		this.scroll = {isAnimated:function(){false;}};//spoof animation object to get us started.
	}
	
	$L.SlideTransition.prototype.getEl = function() {
		return this.slideshow.el;
	}
	
	$L.SlideTransition.prototype.setSlideshow = function(slideshow) {
		this.slideshow = slideshow;
	}
	
	$L.SlideTransition.prototype.getFrames = function(slideshow) {
		return this.slideshow.getFrames();
	}	
	$L.SlideTransition.prototype.currentFrame = function() {
		return this.slideshow.currentFrame;
	}
	
	$L.SlideTransition.prototype.applyStylesToWrapper = function() {
		var frames = this.getFrames();
		var height = 0;
		var width = 0;
		for(var i = 0; i<frames.length; i++) {
			if(frames[i].offsetHeight > height) {
				height = frames[i].offsetHeight;
			}
			if(frames[i].offsetWidth > width) {
				width = frames[i].offsetWidth;
			}
		}
		for(var i = 0; i<frames.length; i++) {
			$D.setStyle(frames[i], "height", height+"px");
			$D.setStyle(frames[i], "width", width+"px");
		}
		var styles = {'overflow':'hidden', 'width': ""+width+"px", 'height': ""+height+"px", 'position':'relative'}
		for (name in styles) {
			if (typeof styles[name] !== 'function') {
				$D.setStyle(this.getEl(), name, styles[name]);
			}		
		}
	}
	
	$L.SlideTransition.prototype.applyStylesToFrames = function() {
		var frames = this.getFrames();
		for(i in frames) {
			$D.setStyle(frames[i], 'float', 'left');
			$D.setStyle(frames[i], 'width', this.getEl().offsetWidth+"px");
		}
		$D.setStyle(this.slideshow.billboard, 'width', frames.length*(this.getEl().offsetWidth)+"px");
	}

	$L.SlideTransition.prototype.slideTo = function(id) {
		if(!this.scroll.isAnimated()) {
			var targetFrame = $D.get(id);
			var currentFrame = this.currentFrame();
			if(targetFrame == currentFrame) { return; }
			var delta = $D.getX(targetFrame) - $D.getX(currentFrame);	
			var offset = [delta, 0];	
			this.scroll = new YAHOO.util.Scroll(this.getEl(), { scroll: { by: offset } } , 1.2, YAHOO.util.Easing.easeBothStrong);
			this.scroll.animate();
			this.slideshow.setCurrentFrame(targetFrame);
		}
	}
	
	/*****************/
	$L.FadeTransition = function(attributes) {
		this.NAME = "FacettedPanel";
		this.init(attributes);
	};

	 $L.FadeTransition.prototype.init = function(attribs) {
	 	this.attribs = attribs;
		this.slideshow = null;
		this.currentlyMoving = false;
		this.scroll = {isAnimated:function(){false;}};//spoof animation object to get us started.
	}
	
	$L.FadeTransition.prototype.getEl = function() {
		return this.slideshow.el;
	}
	
	$L.FadeTransition.prototype.setSlideshow = function(slideshow) {
		this.slideshow = slideshow;
	}
	
	$L.FadeTransition.prototype.getFrames = function(slideshow) {
		return this.slideshow.getFrames();
	}	
	$L.FadeTransition.prototype.currentFrame = function() {
		return this.slideshow.currentFrame;
	}
	
	$L.FadeTransition.prototype.applyStylesToWrapper = function() {
		var frames = this.getFrames();
		var height = 0;
		var width = 0;
		for(var i = 0; i<frames.length; i++) {
			if(frames[i].offsetHeight > height) {
				height = frames[i].offsetHeight;
			}
			if(frames[i].offsetWidth > width) {
				width = frames[i].offsetWidth;
			}
		}
		for(var i = 0; i<frames.length; i++) {
			$D.setStyle(frames[i], "height", height+"px");
			$D.setStyle(frames[i], "width", width+"px");
		}
		var styles = {'overflow':'hidden', 'width': ""+width+"px", 'height': ""+height+"px", 'position':'relative'}
		for (name in styles) {
			if (typeof styles[name] !== 'function') {
				$D.setStyle(this.getEl(), name, styles[name]);
			}		
		}
	}
	
	$L.FadeTransition.prototype.applyStylesToFrames = function() {
		var frames = this.getFrames();
		for(i in frames) {
			if(i > 0) {
				new YAHOO.util.Anim(frames[i], { opacity: { to: 0 } } , 0).animate();
			}
			$D.setStyle(frames[i], "position", "absolute");
			$D.setStyle(frames[i], "top", "0");
			$D.setStyle(frames[i], "left", "0");
		}
	}

	$L.FadeTransition.prototype.slideTo = function(id) {
		if(!this.scroll.isAnimated()) {
			var targetFrame = $D.get(id);
			var currentFrame = this.currentFrame();
			if(targetFrame == currentFrame) { return; }
			$D.setStyle(targetFrame, 'zIndex', 3);
			$D.setStyle(currentFrame, 'zIndex', 2);
			this.scroll = new YAHOO.util.Anim(targetFrame, { opacity: { to: 1 } } , 1);
			this.scroll.onComplete.subscribe(function() { 
				new YAHOO.util.Anim(currentFrame, { opacity: { to: 0 } } , 0).animate();
			});
			this.scroll.animate();
			this.slideshow.setCurrentFrame(targetFrame);
		}
	}
	
	
	
}
)();
