/*
 * atvImg
 * Copyright 2015 Drew Wilson
 * http://drewwilson.com
 *
 * Version 1.2   -   Updated: Dec. 09, 2015
 *
 * atvImg = 'AppleTV Image'
 * 
 * This plug-in will automatically turn your layered Apple TV PNGs into
 * 3D parallax icons, the same way the new Apple TV treats app icons.
 * You can have any number of AppleTV Images on the page.
 *
 * An example of this plug-in can bee seen here: http://kloc.pm
 *
 * -------------------
 *
 * Here is how to setup the HTML for a single atvImg:
 * <div class="atvImg">
 * 		<img src="/images/flattened-icon.jpg">
 *
 *		<div class="atvImg-layer" data-img="/images/back.png"></div>
 *		<div class="atvImg-layer" data-img="/images/front.png"></div>
 * </div>
 * 
 * You can have any number of 'atvImg-layer' elements. So add as many
 * as your icon needs. Be sure to use 2x (retina) scale PNGs. The plug-in
 * will downscale for 1x screens. Using 2x scale PNGs is recommended
 * so the icon will appear crisp on 2x screens. 
 * Layer images should be 2x the size you want to display the icon as.
 * The plug-in will adapt the atvImg to be whatever size it's parent
 * element is. So if you set your '.atvImg' element to be 320px X 190px,
 * that is how big the icon will appear. If you set it to be 
 * 640px X 380px, that is how big it will appear. Just be sure to
 * use the correct aspect ratio for AppleTV icons.
 *
 * The <img> element in the example above is a fallback in case 
 * javascript is not allowed to run. It will be removed when the plug-in
 * is running. Put a flattened version (no layers) of you icon in there.
 * 
 * Then call the funciton in you <script> tag or JS file like this: 
 *
 * atvImg();
 *
 *
 * Just be sure you add that line after you've loaded the DOM. So put
 * it below all your page's HTML just before the closing </body> tag or
 * in a document.ready() function.
 *
 * -------------------
 *
 * This atvImg plug-in is dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * I used http://designmodo.com/apple-tv-effect as reference and
 * inspiration when creating this plug-in.
 */

function atvImg(){

	var d = document,
		de = d.documentElement,
		bd = d.getElementsByTagName('body')[0],
		htm = d.getElementsByTagName('html')[0],
		win = window,
		imgs = d.querySelectorAll('.atvImg'),
		totalImgs = imgs.length,
		supportsTouch = 'ontouchstart' in win || navigator.msMaxTouchPoints;

	if(totalImgs <= 0){
		return;
	}

	// build HTML
	for(var l=0;l<totalImgs;l++){

		var thisImg = imgs[l],
			layerElems = thisImg.querySelectorAll('.atvImg-layer'),
			orgImg = thisImg.querySelectorAll('.atvImg-original'),
			totalLayerElems = layerElems.length;

		if(totalLayerElems <= 0){
			continue;
		}

		while(thisImg.firstChild) {
			thisImg.removeChild(thisImg.firstChild);
		}
	
		var containerHTML = d.createElement('div'),
			shineHTML = d.createElement('div'),
			shadowHTML = d.createElement('div'),
			layersHTML = d.createElement('div'),
			layers = [];

		thisImg.id = 'atvImg__'+l;
		containerHTML.className = 'atvImg-container';
		shineHTML.className = 'atvImg-shine';
		shadowHTML.className = 'atvImg-shadow';
		layersHTML.className = 'atvImg-layers';

		for(var i=0;i<totalLayerElems;i++){
			var layer = d.createElement('div'),
					imgSrc = layerElems[i].getAttribute('data-img');
			layer.innerHTML = layerElems[i].innerHTML;
			layer.className = 'atvImg-rendered-layer';
			layer.setAttribute('data-layer',i);
			if (imgSrc) {
				layer.style.backgroundImage = 'url('+imgSrc+')';
			}
			layersHTML.appendChild(layer);

			layers.push(layer);
		}
		layersHTML.appendChild(orgImg[0]);
		containerHTML.appendChild(shadowHTML);
		containerHTML.appendChild(layersHTML);
		containerHTML.appendChild(shineHTML);
		thisImg.appendChild(containerHTML);

		var w = thisImg.clientWidth || thisImg.offsetWidth || thisImg.scrollWidth;
		thisImg.style.transform = 'perspective('+ w*3 +'px)';

		if(supportsTouch){
			win.preventScroll = false;

        (function(_thisImg,_layers,_totalLayers,_shine) {
					thisImg.addEventListener('touchmove', function(e){
						if (win.preventScroll){
							e.preventDefault();
						}
						window.requestAnimationFrame(function(){
							processMovement(e,true,_thisImg,_layers,_totalLayers,_shine);		
						});
					});
		      thisImg.addEventListener('touchstart', function(e){
		        win.preventScroll = true;
						processEnter(e,_thisImg);		
					});
					thisImg.addEventListener('touchend', function(e){
						win.preventScroll = false;
						processExit(e,_thisImg,_layers,_totalLayers,_shine);		
					});
        })(thisImg,layers,totalLayerElems,shineHTML);
	  } else {
	    	(function(_thisImg,_layers,_totalLayers,_shine) {
	    		
					thisImg.addEventListener('mousemove', function(e){
						window.requestAnimationFrame(function(){
						processMovement(e,false,_thisImg,_layers,_totalLayers,_shine);	
						});	
					});
		      thisImg.addEventListener('mouseenter', function(e){
						processEnter(e,_thisImg);		
					});
					thisImg.addEventListener('mouseleave', function(e){
						processExit(e,_thisImg,_layers,_totalLayers,_shine);		
					});
	      })(thisImg,layers,totalLayerElems,shineHTML);
	  }
	}

	function processMovement(e, touchEnabled, elem, layers, totalLayers, shine){

		var bdst = bd.scrollTop || htm.scrollTop,
			bdsl = bd.scrollLeft,
			pageX = (touchEnabled)? e.touches[0].pageX : e.pageX,
			pageY = (touchEnabled)? e.touches[0].pageY : e.pageY,
			offsets = elem.getBoundingClientRect(),
			w = elem.clientWidth || elem.offsetWidth || elem.scrollWidth, // width
			h = elem.clientHeight || elem.offsetHeight || elem.scrollHeight, // height
			wMultiple = 320/w,
			offsetX = 0.52 - (pageX - offsets.left - bdsl)/w, //cursor position X
			offsetY = 0.52 - (pageY - offsets.top - bdst)/h, //cursor position Y
			dy = (pageY - offsets.top - bdst) - h / 2, //@h/2 = center of container
			dx = (pageX - offsets.left - bdsl) - w / 2, //@w/2 = center of container
			yRotate = (offsetX - dx)*(0.03 * wMultiple), //rotation for container Y
			xRotate = (dy - offsetY)*(0.07 * wMultiple), //rotation for container X
			imgCSS = 'rotateX(' + xRotate + 'deg) rotateY(' + yRotate + 'deg)', //img transform
			arad = Math.atan2(dy, dx), //angle between cursor and center of container in RAD
			angle = arad * 180 / Math.PI - 90; //convert rad in degrees

		//get angle between 0-360
		if (angle < 0) {
			angle = angle + 360;
		}

		//container transform
		if(elem.querySelectorAll('.atvImg-container')[0].className.indexOf(' over') != -1){
			imgCSS += ' scale3d(1.013,1.013,1.013)';
		}
		elem.querySelectorAll('.atvImg-container')[0].style.transform = imgCSS;
		
		//gradient angle and opacity for shine
		shine.style.background = 'linear-gradient(' + angle + 'deg, rgba(255,255,255,' + (pageY - offsets.top - bdst)/h * 0.4 + ') 0%,rgba(255,255,255,0) 40%)';
		shine.style.transform = 'translateX(' + (offsetX * totalLayers) - 0.1 + 'px) translateY(' + (offsetY * totalLayers) - 0.1 + 'px)';	

		//parallax for each layer
		var revNum = totalLayers;
		for(var ly=0;ly<totalLayers;ly++){
			layers[ly].style.transform = 'translateX(' + (offsetX * revNum) * ((ly * 2.5) / wMultiple) + 'px) translateY(' + (offsetY * totalLayers) * ((ly * 2.5) / wMultiple) + 'px)';
			revNum--;
		}
	}

	function processEnter(e, elem){
		elem.querySelectorAll('.atvImg-container')[0].className += ' over';
	}

	function processExit(e, elem, layers, totalLayers, shine){

		var container = elem.querySelectorAll('.atvImg-container')[0];

		container.className = container.className.replace(' over','');
		container.style.transform = '';
		shine.style.cssText = '';
		
		for(var ly=0;ly<totalLayers;ly++){
			layers[ly].style.transform = '';
		}
		setTimeout(function() {
			container.style.transform = '';
			shine.style.cssText = '';
		}, 100);
	}

}