/*
	====================================================================================
																					]\/[ 
																		© Mathieu Jouhet
	====================================================================================

	Hello !

	I'm a freelance graphic + web designer, have fun!
	Please note this JS is still under heavy dev. 
	Subject to inconsistencies, mistakes, typos etc.

*/

var params = new Object();

	params.debug = true;
	params.displayStats = false;
	params.frameRate = 60;

	params.onMotionEvent = {
		activated: true,
		rotateSymbols: false,
		rotateImg: false,
		rotateLogo: true
	};

	params.rotateSymbolsOnOrientationChange = true;


/*
	debugging stuff
*/
var _m = new Object();
	_m.dbug = function(w)
	{
		if(params.debug)
			_m.log(w);
	};
	_m.log = function(w)
	{
		if(window.console)
			console.log(w);
	};


var oldOrientation = window.orientation;

/*
	----------------------
*/

$(document).ready(function() {

/*
	Stats - courtesy of Mr Doobs
*/
	if(params.displayStats)
	{
		var stats = new Stats();

		// Align top-left
		stats.getDomElement().style.position = 'absolute';
		stats.getDomElement().style.left = '0px';
		stats.getDomElement().style.top = '0px';

		document.body.appendChild( stats.getDomElement() );

		setInterval( function () {
		    stats.update();
		}, 1000 / 60 );
	}



/*
	(function(window,undefined){

	    // Prepare
	    var History = window.History; // Note: We are using a capital H instead of a lower h
	    if ( !History.enabled ) {
	         // History.js is disabled for this browser.
	         // This is because we can optionally choose to support HTML4 browsers or not.
	        return false;
	    }

	    // Bind to StateChange Event
	    History.Adapter.bind(window,'statechange',function(){ // Note: We are using statechange instead of popstate
	        var State = History.getState(); // Note: We are using History.getState() instead of event.state
	        //History.log(State.data, State.title, State.url);
	    });

		//History.pushState(null, null, "test");

	})(window);
*/


	
	var lastX = $('#hire #hand').offset().left


	$("#main>nav li a").click(navigation);
	$("#btnHome").click(navigation);
	$("nav.secondary a").click(secondaryNavigation);
	intro();

		
	$(window).bind("orientationchange", updateOrientation);
	
	newOrientation = window.orientation; 

	rotate($("section:not(#works) .centered img"), newOrientation, 4);
	rotate($('.small-cog'), newOrientation, -2);
	rotate($('.large-cog'), newOrientation, 1);

	//$(window).trigger("orientationchange");
	jQuery.browser.mobile = /mobile/i.test(navigator.userAgent);

	if(!jQuery.browser.mobile && params.onMotionEvent.activated)
	{
		initDeviceOrientation();
		//removeAnimation($(".small-cog"));
		//removeAnimation($(".large-cog"));
	}
	
	$(window).resize(function(){aimHireSymbol()});
	//$(window).resize();
	
	mUpdate();
	
	
	/*
		Touch me, touch me, I wanna feel you body...
	*/
	

	$("section:has(nav.secondary)").touchwipe({
    	 wipeLeft: function(e) { 
			$target= $(e.currentTarget); 
			nextArticle($target);
		},
	     wipeRight: function(e) { 
			$target= $(e.currentTarget); 
			prevArticle($target);
		 },
	     min_move_x: 20,
	     min_move_y: 20,
	     preventDefaultEvents: window.preventDefault
	});
	
	/*
		Keyboard navigation
	*/

	$(window).keyup(function(e){
		switch(e.which)
		{
			case 39: //right
				if(!e.shiftKey && !e.altKey)
					nextArticle($("section.active"));
				else nextPage()
			break;
			case 37: //left
				if(!e.shiftKey && !e.altKey)
					prevArticle($("section.active"));
				else prevPage()
			break;
			case 38: //up
				prevPage()
			break;
			case 40: //down
				nextPage()
			break;
			default:
			break;
		}
	});

	/*
		Mousewheel navigation
	*/

	var mwNav = new Object();
	mwNav.activated = true;
	mwNav.prevTimeStamp = 0;
	mwNav.prevDirection = 0;

	$(window).mousewheel(function(event, delta, deltaX, deltaY) {
		//delta=((deltaX<0)?0-delta:delta);

		prevDirection = mwNav.prevDirection;
		prevTimeStamp = mwNav.prevTimeStamp;

		direction = ((parseFloat(delta)<0)?(1):(-1));

		if(deltaX>0 && deltaX>deltaY) direction = 1;
		if(deltaX<0 && deltaX<deltaY) direction = -1;

		if(Math.abs(delta)>0.05 && mwNav.activated)
	    if((prevTimeStamp+500)<event.timeStamp || prevDirection!=direction)
	    {
		    if(deltaY<0 && deltaX>deltaY)
		    {
		    }
		    else if(deltaY>0 && deltaX<deltaY)
		    {
		    }
		    else if(deltaX<0 && deltaX<deltaY)
		    {
		    	direction = -1;
		    }
		    else if(deltaX>0 && deltaX>deltaY)
		    {
		    	direction = 1;
		    }

		    if (direction==1) nextArticle($("section.active"));
		    else if (direction==-1) prevArticle($("section.active"));

		    mwNav.prevTimeStamp = event.timeStamp;
		    mwNav.prevDirection = direction;
		    
		}
	});
});


var intro=function()
{
	$("html").removeClass("intro");
	$("html").addClass("intro");
	

	newOrientation = 0;
	rotate($("section .centered img"),newOrientation, -1);
	rotate($('.small-cog'), newOrientation, -2);
	rotate($('.large-cog'), newOrientation, 1);				
}

var nextPage = function(){
	$li = $("nav.main li");
	max = $li.length;
	index = $li.find("a.active").parent().index();
	target = index+1;
	target = (target<max)?target:0;
	$li.eq(target).find("a").click();
}

var prevPage = function(){
	$li = $("nav.main li");
	max = $li.length;
	index = $li.find("a.active").parent().index();
	target = index-1;
	target = (target>=0)?target:max-1;
	$li.eq(target).find("a").click();	
}

var nextArticle=function($target){
	
	/*
		Set Style for Slides
	*/
		$actual = $target.find("article:not(.inactive)");
		$prev = $actual.prevAll("article").addClass("dontMove");
		$prev.andSelf().removeClass('right').addClass("left");
		$next = $actual.nextAll("article").addClass("dontMove").removeClass('left').addClass("right");
	/*
		Update indicators and do the clikety clicq
	*/
	$a=$target.find("nav a"); 
		last=$a.last().index(); 
		index=$a.parent().find("a.active").index();
		
		if((index===last))
		{
			$target.find("article").each(function(i,w){
				$w=$(w);
				if(i!=last) $w.addClass("dontMove").removeClass("left").addClass("right");
				
			});
		}
		
		setTimeout("$a.eq(((index===last)?0:index+1)).trigger({type: 'click', dontUpdatePosition: true})",10) ;
}


var prevArticle=function($target){
	/*
		Update slides position and trigger a click on the right secondary nav button
	*/
	
	/*
		Set Style for Slides
	*/
		$actual = $target.find("article:not(.inactive)");
		$prev = $actual.prevAll("article").addClass("dontMove").removeClass('right').addClass("left");
		$next = $actual.nextAll("article").addClass("dontMove");
		$next.andSelf().removeClass('left').addClass("right");

	/*
		Update indicators and do the clikety clicq
	*/
	$a=$target.find("nav a"); 
		last=$a.last().index(); 
		index=$a.parent().find("a.active").index();
		
		if((index===0)) // last one in this direction
		{
			$target.find("article").each(function(i,w){ 
				$w=$(w);
				if(i!=0) $w.addClass("dontMove").removeClass("right").addClass("left");
			});
		}
					
		setTimeout("$a.eq((index-1)).trigger({type: 'click', dontUpdatePosition: true})", 10) ;
}	


var secondaryNavigation = function(e)
{
	$this = $(this);

	$prevSelected = $this.siblings(".active");
	
	$articles = $this.parent().parent().children("article");

	$thisArticle = $articles.eq($this.index());
	$thisParent = $thisArticle.parent("section");

	$prevArticle = $articles.eq($prevSelected.index())


		$pendulum = $thisParent.find(".pendulum");
		$pendulum.data("pendulumActive", false);
		$pendulum.data("mAngle", 0);	
  		clearTimeout($pendulum.data("timeout"));

	if(!e.dontUpdatePosition) // if we have to update positions before doing anything else
	{

		$thisArticle.prevAll(".inactive").addClass("dontMove");
		$thisArticle.prevAll().removeClass("right").addClass("left");


		$thisArticle.nextAll(".inactive").addClass("dontMove");
		$thisArticle.nextAll().removeClass("left").addClass("right");
		
		if($prevSelected.index()<$this.index())
		{
			$thisArticle.addClass("dontMove").removeClass("left").addClass("right")
		} else if($prevSelected.index()>$this.index())
		{
			$thisArticle.addClass("dontMove").removeClass("right").addClass("left")			
		}
		
		// we can now call back the nav function with a	short delay so moved elements will effectively be moved
		setTimeout("$this.trigger({type: 'click', dontUpdatePosition: true})", 10);

	} else
	{
		if(!e.justSwitchToPage)
		{
			$articles.addClass("dontMove");
			$thisArticle.removeClass("dontMove");
			$prevArticle.removeClass("dontMove");
			setTimeout("$this.trigger({type: 'click', dontUpdatePosition: true, justSwitchToPage: true})", 10);
		} else
		{
			if($("#works").hasClass("active"))
			{
				newOrientation = window.orientation||0;
				if($this.index()==0) 
				{ // Works first slide
					newOrientation += 90;
				} else{
					newOrientation = 0;
				}
				rotate($('section .small-cog'), newOrientation, -1.33333);
				rotate($('section .large-cog'), newOrientation, 1);		
			}

			if(!e.dontTrack)
			{
				page = $thisParent.attr("id")+"/"+$thisArticle.find(".analyticsInfo").text();
				trackPageview(page);
			}

			$this.parent().children().removeClass("active");
			$this.addClass("active");
		
			$articles.addClass("inactive");
			$thisArticle.removeClass("inactive").removeClass("dontMove");

		}
	}
	e.preventDefault();
};

var navigation=function(e){
	
	$prevLiSelected = $("nav li a.active").parent();
	index = $prevLiSelected.index();

		
	var elm = $(this),
	 	id = elm.attr("id"),
		previous = $("section.active"),
		next;

	previous.find("nav.secondary a").eq(0).trigger({type: 'click', dontUpdatePosition: true, dontTrack: true});
		
	
	if(previous.attr("id") != id)
	{
		newOrientation = window.orientation||0;

		switch(id){
			case "btnHome":
			case "btnHome2":
				next=$("#home");
				trackPageview('home');
				break;
			case "btnWorks":
				next=$("#works");
				trackPageview('works');	
				newOrientation += 90;		
				break;
			case "btnBlog":
				next=$("#blog");
				trackPageview('blog');
				break;
			case "btnDemos":
				next=$("#demos");
				trackPageview('home');
				break;
			case "btnAbout":
				next=$("#about");
				trackPageview('about');
				break;
			case "btnHire":
				next=$("#hire");
				trackPageview('hire');
				break;
			default:
				break;
		}		


		
		// do the tango !
		if(previous.attr("id") != next.attr("id"))
		{
			$("nav li a").removeClass("active");
			$(this).addClass("active");

			previous.removeClass("active").addClass("inactive");	
			next.addClass("active").removeClass("inactive");

			$pendulum = previous.find(".pendulum");
			$pendulum.data("pendulumActive", false);
			$pendulum.data("mAngle", 0);			
	  		clearTimeout($pendulum.data("timeout"));

			rotate($('section .small-cog'), newOrientation, -1.33333);
			rotate($('section .large-cog'), newOrientation, 1);		
	  	}
	}
	
	e.preventDefault();
};


/*
	================================
			Orientation Fun
	================================
*/

	var updateOrientation = function(e)
	{
		newOrientation = window.orientation; 
		$img = $("section:not(#works, #hire) .centered img, #btnHome img");

		//alert("Old : "+oldOrientation+" - New : "+newOrientation + " - "+$img.css("-webkit-transform")	);
		rotate($img, newOrientation, 4);
		rotate($('.small-cog'), newOrientation, -2);
		rotate($('.large-cog'), newOrientation, 1);

		$img = $("section .centered img, .small-cog, .large-cog");

		oldOrientation = newOrientation;
	}


	var initDeviceOrientation = function () {

		if (window.DeviceOrientationEvent) {
			// Listen for the deviceorientation event and handle the raw data
			window.addEventListener('deviceorientation', function(eventData) {
				// gamma is the left-to-right tilt in degrees, where right is positive
				var tiltLR = eventData.gamma;
				
				// beta is the front-to-back tilt in degrees, where front is positive
				var tiltFB = eventData.beta;
				
				// alpha is the compass direction the device is facing in degrees
				var dir = eventData.alpha
				
				// deviceorientation does not provide this data
				var motUD = null;
				
				// call our orientation event handler
				deviceOrientationHandler(tiltLR, tiltFB, dir, motUD);
				}, false);
		} else if (window.OrientationEvent) {
			window.addEventListener('MozOrientation', function(eventData) {
				// x is the left-to-right tilt from -1 to +1, so we need to convert to degress
				var tiltLR = eventData.x * 90;
				
				// y is the front-to-back tilt from -1 to +1, so we need to convert to degress
				// We also need to invert the value so tilting the device towards us (forward) 
				// results in a positive value. 
				var tiltFB = eventData.y * -90;
				
				// MozOrientation does not provide this data
				var dir = null;
				
				// z is the vertical acceleration of the device
				var motUD = eventData.z;
				
				deviceOrientationHandler(tiltLR, tiltFB, dir, motUD);
				}, false);
		} else {
		}
	};

	var deviceOrientationHandler = function(tiltLR, tiltFB, dir, motionUD) {
		sensitivity = 3;

		newOrientation = false;

		if (((tiltLR)>sensitivity || tiltLR<-sensitivity) )
		{
			if(Math.round(tiltLR)%sensitivity == 0)
				newOrientation = Math.round(tiltLR);
		}else{	
			newOrientation = 0;
		}

		/* Do we have to udpate rotation ? */

		if(newOrientation!==false && newOrientation!=oldOrientation )
		{
			if(params.onMotionEvent.rotateLogo)
				rotate($("#btnHome img"),newOrientation, -1);
			if(params.onMotionEvent.rotateSymbols)
				rotate($("section:not(#works, #hire) .centered img"),newOrientation, -1);
			if(params.onMotionEvent.rotateImg)
				rotate($("section > article:not(.centered) img"),newOrientation, -1);
	
			rotate($('.active .small-cog'), newOrientation, -1.333333);
			rotate($('.active .large-cog'), newOrientation, 1);	

			oldOrientation = newOrientation;
		}
	};
		
/*
	===============================
		Time based animations
	===============================
*/

/*
	RequestAnimFrame
*/	
var requestAnimFrame = (function() {
  return window.requestAnimationFrame ||
     window.webkitRequestAnimationFrame ||
     window.mozRequestAnimationFrame ||
     window.oRequestAnimationFrame ||
     window.msRequestAnimationFrame ||
     function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
       window.setTimeout(callback, 1000/params.frameRate);
     };
})();
 
var mUpdate = function()
{
	aimHireSymbol(true);
	trackVelocity();
	requestAnimFrame(mUpdate);
}

/*
	Used to trigger the pendulum effect and simulate gravity + friction on slide
*/

var trackVelocity = function()
{
	$(".trackVelocity").each(function(i,e){
		
		e = $(e);
		x = e.offset().left;
		lastX = e.data("lastX");


		delta = x-lastX;
		v = delta * params.frameRate;


		$pendulumObject = e.find(".pendulum");

		if(lastX>x)
		{
			mAngle = $pendulumObject.data("mAngle");
			direction = -1;
			
			if($pendulumObject.data("pendulumActive")!=true) 
			{
				mAngle = (mAngle?mAngle:0);
				mAngle += v/180;
				mAngle = Math.max(mAngle, -90)
				rotate($pendulumObject, mAngle, 1);

				$pendulumObject.data("mAngle", mAngle);
			}

			mAngle = (mAngle ? mAngle: direction*90);
			$pendulumObject.data("startAngle", mAngle);
			
		}
		else if(lastX<x)
		{
			mAngle = $pendulumObject.data("mAngle");
			direction = 1;
			
			if($pendulumObject.data("pendulumActive")!=true) 
			{
				mAngle = (mAngle?mAngle:0);
				mAngle += v/180;
				mAngle = Math.min(mAngle, 90)
				rotate($pendulumObject, mAngle, 1);

				$pendulumObject.data("mAngle", mAngle);
			}

			mAngle = (mAngle ? mAngle: direction*90);
			$pendulumObject.data("startAngle", mAngle);
		}

		
		if(!lastX  ||  lastX != x )
		{
							
			e.data("lastX", x);
		} 

		// pendulumize !
		if (x<$(window).width() && x>$(window).width()/4 && e.parent().hasClass("active") && (e.hasClass("active") || !e.hasClass("inactive") ) && Math.abs(delta)<30 && $pendulumObject.data("pendulumActive")!=true)
		{
			$pendulumObject.data("mAngle", 0);

			startAngle = $pendulumObject.data("startAngle");
			startAngle = (startAngle ? startAngle : 90);

			
			$pendulumObject.data("pendulumActive", true);
			var sim = new PendulumSim(1, 9.80665*10, Math.PI*startAngle/180, 1000/params.frameRate, 2, .06, $pendulumObject, function (elem, angle) {
				rotate(elem,angle*180/Math.PI,1);
				prev=angle;
			});	
			
		}		
	});
};



/*
 Pendulum animation with pseudo friction
*/

  function PendulumSim(length_m, gravity_mps2, initialAngle_rad, timestep_ms, mass, friction, $elem, callback) {
  	if($elem.data("pendulumActive")!=false)
  	{
  		clearTimeout($elem.data("timeout"));
	    var prev=0;

	    var velocity = 0;
	    var angle = initialAngle_rad;
	    //var k = -gravity_mps2*mass/length_m;
	    var k = -mass*gravity_mps2/length_m;

	    var timestep_s = timestep_ms / 1000;


	    var updatePendulum = function () {
	      var acceleration = k * Math.sin(angle);
	      velocity += acceleration * timestep_s;
	      velocity -= velocity * friction;
	      angle    += velocity * timestep_s;

	      if($elem.data("pendulumActive")!=false)
		      if(velocity>0.0001 || velocity<-0.0001) {
		        callback($elem, angle);
		        $elem.data("timeout", setTimeout(updatePendulum, timestep_ms));
		      } else{
		      	rotate($elem, 0, 1);
		      }
	    };

	    return setTimeout(updatePendulum, timestep_ms);
		}
  }

/*
 Permanently aim hire hand at contact info
*/

var aimHireSymbol = function(output)
{
	$c = $("#contact");
	co = $c.offset();
	ll1 = parseInt($c.css("right"))+$c.outerWidth()/2;
	ll2 = co.top+$c.outerHeight()/2;
	
	$s = $('#hire #hand');
	sHeight = $s.innerHeight();
	sWidth = $s.innerWidth();
	o = $s.offset();
	l1 = ($("#main").outerWidth()-(o.left+sWidth/2))-ll1;
	l2 = (o.top+sHeight/2)-ll2;
	//hyp = calcHypotenuse(l1,l2);
	angle = calcAngleFromSides(l2,l1);
	calcangle=(angle>0)?(90-angle):-90-angle;
	rotate($("#hire #hand img"),calcangle,1);


}

/*
	=====================================
				Helpers & utils
	=====================================
*/

var trackPageview = function(page)
{
	page = $.trim(page);
	pageTracker._trackPageview(page);
}

var calcHypotenuse = function (side1, side2)
{
	return Math.sqrt(Math.pow(side1,2)+Math.pow(side2,2));
}

var calcAngleFromSides = function(side1, side2)
{
	return (Math.atan(side1/side2)*(180/Math.PI));
}


var rotate = function($img, newOrientation, factor)
{
	$img.css("-webkit-transform", "rotate("+(newOrientation*factor)+"deg)");
	$img.css("-moz-transform", "rotate("+(newOrientation*factor)+"deg)");
	$img.css("-o-transform", "rotate("+(newOrientation*factor)+"deg)");
	$img.css("-ms-transform", "rotate("+(newOrientation*factor)+"deg)");
	$img.css("transform", "rotate("+(newOrientation*factor)+"deg)");		
}


var removeAnimation = function($elem)
{
	var obj = new Object();
	
	obj.webkit =  $elem.css("-webkit-transition-property")+" "+$elem.css("-webkit-transition-timing-function")+" "+$elem.css("-webkit-transition-duration");
	obj.moz =  $elem.css("-moz-transition-property")+" "+$elem.css("-moz-transition-timing-function")+" "+$elem.css("-moz-transition-duration");
	obj.o =  $elem.css("-o-transition-property")+" "+$elem.css("-o-transition-timing-function")+" "+$elem.css("-o-transition-duration");
	obj.ms =  $elem.css("-ms-transition-property")+" "+$elem.css("-ms-transition-timing-function")+" "+$elem.css("-ms-transition-duration");
	obj.standard = $elem.css("transition-property")+" "+$elem.css("transition-timing-function")+" "+$elem.css("transition-duration");

	$elem.css("-webkit-transition-property", "none");
	$elem.css("-webkit-transition-timing-function", "none");
	$elem.css("-webkit-transition-duration", "none");

	$elem.css("-moz-transition-property", "none");
	$elem.css("-moz-transition-timing-function", "none");
	$elem.css("-moz-transition-duration", "none");

	$elem.css("-o-transition-property", "none");
	$elem.css("-o-transition-timing-function", "none");
	$elem.css("-o-transition-duration", "none");

	$elem.css("-ms-transition-property", "none");
	$elem.css("-ms-transition-timing-function", "none");
	$elem.css("-ms-transition-duration", "none");

	$elem.css("transition-property", "none");
	$elem.css("transition-timing-function", "none");
	$elem.css("transition-duration", "none");
	
	return obj;
}

var restoreAnimation = function($elem, obj)
{
	$elem.css("-webkit-transition", obj.webkit);
	$elem.css("-moz-transition", obj.moz);
	$elem.css("-o-transition", obj.o);
	$elem.css("-ms-transition", obj.ms);
	$elem.css("transition", obj.standard);	
}	




		

