/* Middlebury Waveform and Carousel effects */
/* by White Whale Web Services */

var settings = {
	
	},
	ie6 = $.browser.msie&&$.browser.version<7, // are we in IE6?
	ie8 = $.browser.msie&&$.browser.version>=8&&$.browser.version<=9;
$(function() { // on DOM ready
	if(header) $('#header').width($('#header').width()).css('float','left');
	var homepage = $('body').is('#homepage'),
		waveform = $('#waveform'),
		waveformHeight = waveform.height(),
		header= $('#header').html(),
		stories = $('#stories').removeClass('nojs').empty().css('opacity',0).show(), // immediately hide the waveform and empty it
		pointer = $('<div id="bar_pointer"></div>').appendTo('body'), // the pointer
		pointerArrow = $('<div id="bar_pointer_arrow"></div>'), // and its arrow
		pointerWidth = 0, // and its width
		windowWidth, // the window width
		wordmark = $('#wordmark'); // the wordmark
	if(ie6) pointer.add(pointerArrow).css('visibility','hidden'); // in IE6, hide the pointer arrow
	var bar_color = 0;
	if(window.waveformStories) {
		$.each(waveformStories,function(index,details) { // with each story (from JSON)
			bar_color++;
			if(bar_color==4) bar_color = 1;
			var story = $('<li id="story'+details.id+'_bar" class="'+(details.image ? '' : 'disabled ')+'bar"><div class="bar_contents"><div class="bar_title"><div style="width:'+details.width+'px;">'+details.title+'</div></div><div class="bar_target"><div class="bar_color bar_color'+bar_color+'" style="'+(details.color ? 'background-color:'+details.color +';' : '')+'height:'+details.height+'px;"><div class="bar_image_bw" style="margin-top:-'+(details.height/2)+'px;"></div><div class="bar_image" style="margin-top:-'+(details.height/2)+'px;"></div></div></div><div class="bar_text"><div style="width:'+details.width+'px;">'+details.text+'</div></div></div>').appendTo(stories);  // add the story bar
			story.find('.bar_contents').css('padding-'+(index%2==0 ? 'top' : 'bottom'),(Math.floor(Math.random()*6)*5));
			$.extend(details,{ // precache elements we'll need to recall
				content_height : story.find('.bar_contents').outerHeight(), // the total height of the contents
				bar_title : story.find('.bar_title'), // the headline
				bar : story.find('.bar_color'), // the bar color
				bar_image_bw : story.find('.bar_image_bw'), // the BW image div
				bar_image : story.find('.bar_image'), // the color image div
				bar_text : story.find('.bar_text') // the caption
			});
			if(!details.color) details.color = details.bar.css('background-color');
			if(details.content_height>waveformHeight) {
				var overflow = details.content_height-waveformHeight;
				details.bar.css('height',Math.max(details.height-overflow,10));
			}
			story.find('.bar_target').hover(function(e) { // onmouseenter
				if(!story.is('.open,:animated,.disabled')) {
					details.bar.stop(true).animate(ie8 ? {paddingLeft:'3px',paddingRight:'3px',marginLeft:'-3px',marginRight:'-3px',backgroundColor:'#fff'} : {padding:3,margin:-3,backgroundColor:'#fff'},200); // glow
					pointerWidth = pointer.text(details.title).show().width(); // show the pointer, set its text, and store its width
					pointerArrow.appendTo(story).show();
				}
			},function() { // onmouseleave
				if(!story.is('.open,:animated')) {
					details.bar.stop(true).animate({padding:0,margin:0,backgroundColor:details.color},200); // reset glow
				}
				pointer.add(pointerArrow).hide();
			}).bind('mousemove mouseenter',function(e) { // onmousemove
				var pointerX = e.clientX-30,
					pointerY = e.clientY-50,
					offsetTop = waveform.offset().top-$().scrollTop(),
					arrowLeft;
				if(pointerY<offsetTop-25) { pointerY = offsetTop-25; }
				if(pointerX<0) pointerX = 0;
				else if(pointerX+pointerWidth>windowWidth-12) {
					pointerX = windowWidth-12-pointerWidth;
				}
				pointer.css({left:pointerX,top:pointerY});
				pointerArrow.css({top:(pointerY-offsetTop+25)});
			}).click(function() { // onclick
				if(!story.is('.open')) {
					var open = stories.find('.open'); // find any open story
					if(open.length) open.closeStory(); 
					details.bar.animate({padding:0,margin:0,backgroundColor:details.color},200); // reset glow
					pointer.add(pointerArrow).hide(); // hide pointer and arrow
					story.openStory();
				}
			});
			if(ie6) details.bar.attr('title',details.bar_title.text()); // in IE6, add a title attribute
			story.data('details',details); // store the details data for later
		});
//		stories.css({position:'static',backgroundColor:'blue'});
//		stories.parent().css({position:'static',backgroundColor:'red'});
		stories.find('.bar_title,.bar_text,.bar_glow,.bar_image_bw,.bar_image').css('opacity',0); // fade out hidden features
		stories.find('.bar_contents:odd').css('bottom',0); // make stories alternate top vs. bottom attachment
		if(header) stories.children().eq(Math.ceil(stories.children().length/2)-1).after('<li id="header" class="bar">'+header+'</li>');	
		$(window).resize(function() { // on window resize
			windowWidth = $(window).width();
			if(homepage) { // if this is the homepage
				var windowHeight = $(window).height(), // get the window height
					waveformRoom = windowHeight-361, // how much room is left for the waveform? 361 is the combined height of the other elements on the homepage
					waveformHeightNew = Math.max(Math.min(waveformRoom,300),200);
				if(waveformHeightNew!=waveformHeight) { // if we need to resize the waveform
					waveform.height(waveformHeightNew); // resize it
					waveformHeight = waveformHeightNew; // store the waveform height
					$.each(waveformStories,function(index,details) { // then with each story
						if(details.content_height>waveformHeight) { // if it's taller than the waveform
							var overflow = details.content_height-waveformHeight; // calculate the overflow
							details.bar.css('height',Math.max(details.height-overflow,10)); // and shrink the bar
						} else if(details.bar) { // otherwise
							details.bar.css('height',details.height); // reset its height
						}
					});
				} 
				nudgeFooter();
			}
		}).resize(); // and do it now
		stories.css('opacity',1);
		if($.browser.msie&&$.browser.version>=8) stories.width(1520);
		waveform.slider();
		var permalinked = $(window.location.hash+'_bar'); // check whether a story corresponds to the hash tag
		if(permalinked.length) { // if it exists
			permalinked.openStory(); // show it
		}
	}
	var carousel = $('#carousel');
	if(carousel.length) {
		if($.browser.msie&&$.browser.version<8) {
			carousel.html('<ul id="carousel_features"><li></li><li style="width:400px;">Sorry, we’re also working out kinks in the carousel during this preview phase. It should look great in IE8, but we’ve disabled it for older IE versions.</li><li></li><li></li><li></li></ul>');
		} else {
			carousel.slider();
		}
		$('#content').append('<div id="carousel_arrow"/>');
	}
});

$.fn.extend({
	slider : function(s) {
		var self = this;
		s = s || { };
		if(typeof s === 'object') { // if s is an object, we're initializing
			s = $.extend({ // initialize settings with their defaults
				startPos : 'center', // pixel value or 'center' to start the strip centered
				edgeWidth : 0.25, // width of hover area on right and left edges for scrolling (portion of frame)
				maxSpeed : 15, // maximum speed (pixels per frame)
				fps : 60, // frames per second
				refreshRate : 100, // how often to listen for a mouse move event
				threshold : 20, // how many pixels does the mouse have to have moved to register the change?
				accelerate : 3, // the speed is exponentially modified by the mouse position % ^ accelerate; at the far edge it will move 100% speed
				decelerate : 0.3, // the speed is exponentially modified by distance-to-end % ^ decelerate, so it slows down toward the destination
				drift : 100 // how many pixels should we drift if the mouse leaves the slider
			},s);
			var strip = { // variables we'll store for later re-use
					settings : s, // settings
					el : self.children().eq(0), // the strip element
					offset : 0, // the strip's current offset
					speed : 0 // the initial speed is 0
				},
				lastX=-100,
				lastTime=0,
				leftEdge,
				rightEdge;
			strip.width = strip.el.width(), // store the width of the strip
			strip.originalWidth = strip.width; // and the original width
			strip.el.width(strip.width); // fix the strip's width with an inline style
			$(window).resize(function() { // re-calculate the hover areas on resize
				strip.frameWidth = self.width();	// the frame width
				leftEdge = s.edgeWidth*strip.frameWidth; // the move-the-slider-left region
				rightEdge = strip.frameWidth-(s.edgeWidth*strip.frameWidth); // the move-the-slider-right region
				strip.rightEnd = -1*(strip.width-strip.frameWidth); // the right end of the strip
				self.data('strip'); // re-store the data
			}).resize(); // and do it now
			if(typeof s.startPos === 'string') { // if centering
				strip.offset = -1*((strip.width-strip.frameWidth)/2); // calculate the center
			} else {
				strip.offset = s.startPos; // set to the start pos
			}
			strip.el.css('left',strip.offset); // position the strip
			self.data('strip',strip); // and finally, store the data
			// Attach mouseover behavior
			self.mousemove(function(e) {
				var strip = self.data('strip'), // get the strip data, as it may have changed
					curX = e.clientX,
					curTime = (new Date).getTime(),
					modifier;
				if(Math.abs(curX-lastX)<settings.threshold||curTime-lastTime<settings.refreshRate) return; //  if the mouse has moved less than the threshold or less than the refresh rate has elapsed, don't fire
				lastX = curX;
				lastTime = curTime;
				if(curX<leftEdge) { // if moving left
					modifier = Math.pow((leftEdge-curX)/leftEdge,strip.settings.accelerate); // calculate the speed modifier
					destination = 0; // we're moving toward the far left edge
				} else if(curX>rightEdge) { // if moving right
					modifier = Math.pow((curX-rightEdge)/(strip.frameWidth-rightEdge),strip.settings.accelerate); // calculate the speed modifier
					destination = strip.rightEnd; // we're moving toward the far right edge
				} else { // otherwise
					destination = strip.offset; // the destination is the current location
					modifier = 0; // and the speed should be 0!
				}
				if(strip.width<strip.frameWidth) { // if the strip is narrower than the window
					destination = -1*((strip.width-strip.frameWidth)/2); // always move to the center
				}
				self.slider('slideTo',destination,strip.settings.maxSpeed * modifier);
			}).mouseleave(function(e) { // on mouse exit
				var strip = self.data('strip'); // get the strip data
				if(e.clientX<leftEdge) { // if moving left
					destination = strip.offset+strip.settings.drift;
				} else if(e.clientX>rightEdge) { // otherwise if moving right					
					 destination = strip.offset-strip.settings.drift;
				}
				self.slider('slideTo',destination);
			});
		} else { // otherwise, we're performing a command
			if(s=='slideTo') { // we're scrolling to a point
				var strip = self.data('strip'), // get the strip data
					destination = arguments[1];	// and destination
				if(destination<strip.rightEnd) { // if the destination is further than the right edge
					destination = strip.rightEnd; // set the destination to the right edge
				} else if(destination>0) { // otherwise, if it's further than the left edge
					destination = 0; // set it to the right edge
				}
				strip.speed = typeof(arguments[2])==='number' ? arguments[2]*(destination<strip.offset ? -1 : 1) : strip.speed; // we're moving at the last speed if none was specified
				self.data('strip',strip); // re-store the strip data
				clearInterval(strip.animation);  // halt any previous animation
				if(strip.speed!=0) {
					// REVISIT
					var header = $('#header'),
						title = header.find('h1 img').css('position','relative');
					// /REVISIT
					strip.animation = setInterval(function() { // start the animation
						var distance = Math.abs(destination-strip.offset),
							modifier = Math.pow(distance/strip.width,strip.settings.decelerate), // strip decelerates as the destination approaches
							step = strip.speed*modifier; // how many pixels to move the strip
						strip.offset+=step; // move the strip that much in the given direction
						if(distance<Math.abs(step)) { // if the destination is less than the next step
							strip.offset=destination; // we're at the destination
							clearInterval(strip.animation); // and should stop animating
						}
						strip.el.css('left',strip.offset); // and set the offset
						self.data('strip',strip); // re-store the strip data
						title.css('left',strip.offset*0.3);
					},1000/strip.settings.fps); // run the function FPS times per second
				}
			}
		}
		return this;
	},
	openStory : function() {
		var story = this.addClass('open'), // mark the story as open
			details = story.data('details');
		if(ie6) { // in IE6
			var img = new Image();
			$(img).appendTo(details.bar_image).attr('src','/images/bars/'+details.image+'.jpg').attr('alt',details.title).width(details.width).height(details.height); // append the image
			details.bar_image.stop().css('opacity',1); // and show it
		} else { // in modern browsers
			var img = new Image();
			$(img).appendTo(details.bar_image_bw) // append the BW image
				.load(function() { // and onload
					details.bar_image_bw.fadeTo(500,0.5,function() { // fade it in
						var imgColor =  new Image();
						$(imgColor).appendTo(details.bar_image) // then append the full image
							.load(function() { // and onload
								details.bar_image.fadeTo(750,1); // fade it in
							}).attr('src','/images/bars/'+details.image+'.jpg').attr('alt',details.title).width(details.width).height(details.height);		
					});
				}).attr('src','/images/bars/'+details.image+'_bw.jpg').attr('alt',details.title).width(details.width).height(details.height);
		}
		var slider = story.parent().parent().parent(), // get the slider element
			strip = slider.data('strip'); // get the strip data
		strip.width = strip.originalWidth+details.width-12; // make the strip wider
		strip.rightEnd = -1*(strip.width-strip.frameWidth); // and set its new right end
		strip.el.animate({width:strip.width},1000); // widen the slider
		slider.data('strip',strip); // restore the strip data with the new width
		story.animate({width:details.width},1000); // slide the story open
		details.bar_title.add(details.bar_text).fadeTo(1500,0.9); // fade in headline, text
		details.bar_text.find('div').animate({top:0},1000,'easeOutSine'); // drop down text
		window.location.hash = 'story'+details.id; // set the hash for permalinking
		return this; // return the original element for chaining
	},
	closeStory : function() {
		var story = this.removeClass('open'),
			details = story.data('details');
		details.bar_image.add(details.bar_image_bw).stop(true).find('img').unbind('load'); // stop any animations and remove any upcoming load events
		details.bar_image.fadeTo(500,0,function() { // fade out the full image
			details.bar_image.empty(); // and remove it
			details.bar_image_bw.fadeTo(500,0,function() { // fade out the BW image
				details.bar_image_bw.empty(); // and remove it
			});
		}); 
		details.bar_title.add(details.bar_text).fadeTo(500,0); // fade out headline, text
		details.bar_text.find('div').animate({top:'-30px'},1000,'easeOutSine'); // fade out and slide up text
		story.animate({width:'14px'},1000); // slide the story closed
		return this; // return the original element for chaining
	}
});
