
var RADIANS = Math.PI /180;
var UI_HIDE_TIMEOUT = 10; /*seconds*/
var FLASH_DURATION = 4; /*seconds*/

(function($) {
	var gallery,
		about;
	
	var settings = {
		drawing: {
			fadeSpeed: 0.05
		}
	}
	
	var globals = {
		nChanges: 0,
		firstUrlChange: true,
		loading: null,
		mouse :{
			x:0,
			y:0
		}
	}
		
	$.fn.loadImage = function(callback) {
		return $(this).each(function() {
			var link = $(this).text('');
			if(link.hasClass("loaded") || link.hasClass("loading")) {
				callback();
				return;
			}
			link.addClass('loading');
			
			var image = $('<img src="'+$(this).attr('href')+'" />');
			
			image.load(function() {
				link.css({
						 'background': 'url('+image.attr('src')+') no-repeat 50% 50%',
						 'background-size' : 'cover',
						 '-moz-background-size' : 'cover',
						 'filter': 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + image.attr('src') + '", sizingMethod="scale")',
						 '-ms-filter': 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + image.attr('src') + '", sizingMethod="scale")'
				});
				link.addClass('loaded');
				link.removeClass('loading');
				callback();
			});
		});
	}
	
	var ChasingLoader = function(settings){
		var mouseX = 0,mouseY = 0;
		var interval;
		var direction = true;
	
		var progress  = 0;
		var progress2 = 0;
		var active = false;
		var pathObj = null;
		
		var width = settings.width || 5;
		var radius = settings.radius || 40;
		var color = settings.color || "#000";
		var paper = settings.paper || new Raphael(0,0,1000,800);
		
		var parent = settings.parent || document.body;
		var watchElement = null;
		
		$(parent).bind("mousemove",function(e){
			mouseX = e.pageX;
			mouseY = e.pageY;
		});
		var draw = function(){
			if(active){
				var angle = (progress/100*360) + 90
					angle2 = (progress2/100*360) + 90
					tailLength = 40,
					path = getPath(mouseX,mouseY, radius,radius-width, angle,angle2);
					
				if(pathObj){
					pathObj.attr({
											"path" : path,
											"stroke": color,
											"stroke-width": width
										});
				}
				else{
					pathObj = paper.path(path);
				}
			}
		};
		var getPath = function(cx, cy, r1,r2, startAngle, endAngle) {
			var a1 = Math.cos(-startAngle * RADIANS),
				a2 = Math.cos(-endAngle * RADIANS),
				a3 = Math.sin(-startAngle * RADIANS),
				a4 = Math.sin(-endAngle * RADIANS),
				x1 = cx + r1 * a1,
				x2 = cx + r1 * a2,
				y1 = cy + r1 * a3,
				y2 = cy + r1 * a4;
			
			return ["M", x1, y1, 
					  "A", r1, r1, 0, +(startAngle - endAngle < 180), 0, x2, y2];
		};
	
		var advanceProgress = function(){
			if(watchElement != null && watchElement.hasClass("loaded")) {
				stop();
			}
			else {
				if(progress > 99 && direction){
					direction = !direction;
					progress = 100;
					progress2 = 0;
				}
				if(progress2 > 99 && !direction){
					direction =!direction;
					progress = 0;
					progress2 = 0;
				}
				if(!direction) {
					progress2 += 0.6;
				}
				else
				{
					progress += 0.6;
				}
				draw();
			}
		}
		
		var animate = function(){
			if(!active){
				progress = progress2 = 0;
				direction = true;
				active = true;
				interval = setInterval(advanceProgress, 30);
			}
		};
		var stop = function(){
			if(active) {
				clearInterval(interval);
				active = false;
				if(pathObj) {
					pathObj.remove();
					pathObj = null;
				}
			}
		};
		var watch = function(image) {
			watchElement = image;
			animate();
		}
		return {
			watch: watch,
			stop: stop,
			animate: animate
		}
	};

	
	var slugify = function(text) {
		text = text.replace(/[^-a-zA-Z0-9,&\s]+/ig, '');
		text = text.replace(/-/gi, "_");
		text = text.replace(/\s/gi, "-");
		text = text.toLowerCase();
		return text;
	}
	
	var initAbout = function() {
		
		var aboutClick = false;
		var mouse = {x:0,y:0};
		var about = $('#about');
			var toggle = function() {
			if(!isOpen()) {
				open();
			} else {
				close();
			}
		}
		
		var open = function() {
			postAnalytics("/about");
			about.addClass("open")
			about.slideDown();
		}
		
		var close = function() {
			about.removeClass("open");
			about.slideUp();
		}
		var isOpen = function() {
			return about.hasClass('open');
		}
		
		about.click(function(){aboutClick = true});
		
		$('body').click(function(e){
								   	if(!aboutClick && mouse.x == e.clientX && mouse.y == e.clientY) {
								   		close();
									}
									aboutClick = false;
								   });
		$('body').mousedown(function(e){
								   		mouse.x = e.clientX;
										mouse.y = e.clientY;
								   });
		
		return {
			open: open,
			close: close,
			toggle: toggle,
			domElement: about,
			isOpen: isOpen
		}
	}
	
	/* Context Menu */
		
	var initContextMenu = function(){
		$("#save").mousedown(function(){
								document.location.href = gallery.currentImage.image.attr("href").replace('.',"download");
							});
		
		var contextMenu = $("#context-menu");
		
		var open = function(x,y){
			contextMenu.css({
								display:"block",
								top: y+"px",
								left: x+"px"
							});
		};
		var close = function(){
			contextMenu.css({
						display:"none"
					});
		};

		
		$(document)[0].oncontextmenu = function() {return false;} 
		
		$(document).mouseup(function(e){ 
		  if( e.button == 2 ) { 
			 open(e.pageX,e.pageY);
			 return false; 
		   } else {
			  close();
			 return true; 
			} 
	
		}); 
	}
	
	var initGalleries = function() {
		var galleriesDiv = $('#galleries');
		var galleries = galleriesDiv.find('.gallery');
		var galleryMenu;
		
		var currentImage = {
			imageIndex: -1,
			image: null,
			galleryIndex: -1,
			gallery:null
		};
		
		
		preloadStack = [];
		var preloading = false;
		
		var slideshow = {
			interval: 6000,
			running:false,
			btn: $('#toggle-slideshow a'),
			start: function(){
				slideshow.running = true;
				slideshow.timeout = setTimeout(nextImage, slideshow.interval);
				slideshow.btn.text("slideshow / off");

			},
			reset: function(){
				clearTimeout(slideshow.timeout);
				slideshow.timeout = setTimeout(nextImage, slideshow.interval);
			},
			stop: function(){
				slideshow.running = false;
				clearTimeout(slideshow.timeout);
				slideshow.btn.text("slideshow / on");

			},
			toggle: function(){
				if(slideshow.running) {
					slideshow.stop();
				}
				else {
					slideshow.start();
				}
			},
			timeout: null
		}
		
		var addNextImages = function() {
			var image = {
				imageIndex: currentImage.imageIndex,
				galleryIndex: currentImage.galleryIndex
			};
			for(var i = 0; i < 6; i++) {
				image = getNextImage(image.galleryIndex,image.imageIndex);
				addImageToStack(image);
			}
		}
		var addPrevImages = function(){
			var image = {
				imageIndex: currentImage.imageIndex,
				galleryIndex: currentImage.galleryIndex
			};
			for(var r = 0; r < 6; r++) {
				image = getPrevImage(image.galleryIndex,image.imageIndex);
				addImageToStack(image);
			}
		}
		var addImageToStack = function(ref) {
			var image = galleries.eq(ref.galleryIndex).children().eq(ref.imageIndex+1);
			if(!image.hasClass("loaded") &&!image.hasClass("loading") && image.attr("href") != undefined)
				preloadStack.push(image);
		}
		var preloadImages = function() {
			if(!currentImage.image.hasClass("loaded") && !currentImage.image.hasClass("loading")) {
				currentImage.image.loadImage(preloadImages);
			}
			else if(!preloading && preloadStack.length > 0) {
				preloadStack.shift().loadImage(preloadImages);
			}
			else if(preloadStack.length == 0) {
				preloading = false;
			}
		}
		
		var changeImage = function(newImage, jump, pushState) {
			if(currentImage.galleryIndex == newImage.galleryIndex && currentImage.imageIndex == newImage.imageIndex) {
				return;
			}
			if(currentImage.galleryIndex != newImage.galleryIndex) {
				currentImage.galleryIndex = newImage.galleryIndex;
				if(currentImage.gallery) {
					currentImage.gallery.removeClass('active').addClass('deactive');
					currentImage.gallery.fadeOut(400,function(){
						currentImage.gallery.fadeIn(400);
					});
					currentImage.gallery = galleries.eq(newImage.galleryIndex);
					currentImage.gallery.removeClass('deactive').addClass('active');
				}
				else {
					currentImage.gallery = galleries.eq(newImage.galleryIndex).fadeIn(400);
					currentImage.gallery.removeClass('deactive').addClass('active');
				}
				hideGalleryName(true);
				$('#gallery-menu li.name').removeClass('selected').eq(newImage.galleryIndex).addClass('selected');
				flashGalleryName();

				$('#current-gallery-label a').text(currentImage.gallery.find('h2').text());
			}
			
			globals.nChanges++;
			var i = currentImage.imageIndex = newImage.imageIndex;
			currentImage.image = currentImage.gallery.children().eq(currentImage.imageIndex + 1);
			var newLeft = '-'+(i * $(window).width())+'px';
			if(jump) {
				currentImage.gallery.css('left', newLeft);
			} else {
				currentImage.gallery.animate({left: newLeft});
			}

			
			if(slideshow.running){
				slideshow.reset();
			}
			
			if(pushState || globals.firstUrlChange) {
				var state = {
					galleryID: currentImage.gallery.attr('id'),
					image: currentImage.imageIndex
				};
				var url = currentImage.gallery.attr('id').replace('gallery-', '')+'/'+(i+1)+'/';
				changeUrl(state, url);
				
			}
			
			$('#current-gallery-label span').text((i+1)+'/'+currentImage.gallery.find('a').length);
			
			addNextImages();
			addPrevImages();
			
			preloadImages();
			
			if(globals.loading) {
				globals.loading.watch(currentImage.image);
			}
		}
		
		var getNextImage = function(galleryIndex,imageIndex) {
			galleryIndex = galleryIndex || currentImage.galleryIndex;
			imageIndex = imageIndex || currentImage.imageIndex;
			
			if(imageIndex == galleries.eq(galleryIndex).find('a').length-1) {
				galleryIndex = getNextGallery(galleryIndex);
				imageIndex = 0;
			} else {
				imageIndex++;
			}
			return {
				galleryIndex: galleryIndex,
				imageIndex: imageIndex
			}
		}
		var getPrevImage = function(galleryIndex,imageIndex) {
			galleryIndex = galleryIndex || currentImage.galleryIndex;
			imageIndex = imageIndex || currentImage.imageIndex;
			
			if(imageIndex == 0) {
				galleryIndex = getPrevGallery(galleryIndex);
				imageIndex = galleries.eq(galleryIndex).find("a").length - 1;
			} else {
				imageIndex--;
			}
			return {
				galleryIndex: galleryIndex,
				imageIndex: imageIndex
			}
		}
		
		var nextImage = function() {
			changeImage(getNextImage(),false,true);
		}
		
		var prevImage = function() {
			changeImage(getPrevImage(), false, true);
		}
		
		var deactivateGallery = function(i) {
			var gallery = galleries.eq(i);
			gallery.removeClass('active').addClass('deactive');
		}
		var getNextGallery = function(galleryIndex) {
			galleryIndex = galleryIndex || currentImage.galleryIndex
			return galleryIndex == galleries.length-1 ? 0 : galleryIndex+1;
		}
		var nextGallery = function() {
			changeImage({
						galleryIndex :getNextGallery(),
						imageIndex: currentImage.imageIndex
						},false, true);
		}
		
		var getPrevGallery = function(galleryIndex) {
			galleryIndex = galleryIndex || currentImage.galleryIndex
			return galleryIndex > 0 ? galleryIndex - 1 : galleries.length-1;
		}
		var prevGallery = function() {
			changeImage({
						galleryIndex :getPrevGallery(),
						imageIndex: currentImage.imageIndex
						},false, true);
		}
		
		/* Gallery menu */
		
		var initGalleryMenu = function() {
			galleryMenu = $('<div id="gallery-menu" class="closed"><ul></ul></div>');
			var galleryMenuList = galleryMenu.find('ul');
			
			for(var i = 0, len = galleries.length; i < len; i++) {
				var gallery = galleries.eq(i);
				var title = gallery.find('h2').text();
				var newLi = $('<li class="name"></li>');
				var link = $('<a href="'+slugify(title)+'">'+title+'</a>');
				
				if(i > 0) {
					galleryMenuList.append('<li class="dash">&nbsp;—&nbsp;</li>');
				}
				
				link.click(function(e) {
					e.preventDefault();
					var index = $(this).parent().index() / 2;
					changeImage({
									imageIndex: 0,
									galleryIndex: index
								},true, true);
					closeGalleryMenu();
				});
				
				galleryMenuList.append(newLi.append(link));
			}

			$(window).resize(function() {
				galleryMenu.css('top', $(window).height()/2-galleryMenu.outerHeight()/2);
			}).trigger('resize');
			
			galleriesDiv.append(galleryMenu);
			$("<div class='flash'><a></a></div>").appendTo(galleryMenu);
			
		}
		
		var toggleGalleryMenu = function() {
			if(menuOpen()) {
				closeGalleryMenu();
			} else {
				openGalleryMenu();
			}
		}
		var menuOpen = function(){
			return galleryMenu.is('.open');
		}

		var openGalleryMenu = function() {
			hideGalleryName(true);
			galleryMenu.addClass('open').removeClass('closed').children().eq(0).fadeIn(200);
		}
		
		var closeGalleryMenu = function() {
			galleryMenu.addClass('closed').removeClass('open').children().eq(0).fadeOut(200);
		}
				
		var flashGalleryName = function() {
			if(!galleryMenu.is('.open')) {
					showGalleryName();
					setTimeout(function() {
						hideGalleryName();
					},FLASH_DURATION * 1000);
			}
		}
		
		var showGalleryName = function() {
			if(!menuOpen()){
				var galleryNameFlash = $("#gallery-menu .flash");
				galleryNameFlash.children().text($("#gallery-menu li.selected a").text());
				$("#gallery-menu .flash").stop().fadeIn(200);
			}
		}
		var hideGalleryName = function(quick) {
			$("#gallery-menu .flash").fadeOut(quick ? 0 : 200);
		}
		
		var bind = function(evtName,func) {
			events[evtName] = func;
		};
		
		galleries.each(function() {
			var gallery = $(this);
			gallery.attr('id', 'gallery-'+slugify(gallery.find('h2').text()));
		});
		
		initGalleryMenu();
		
		var initGallery = function() {
			galleries.each(function() {
				var gallery = $(this);
				var images = gallery.find('a');
				var w = $(window);

				images.click(function(e) {
					e.preventDefault();
				});

				w.resize(function(e) {
					images.width(w.width()).height(w.height());
					gallery.width(w.width() * images.length);
					var newLeft = '-'+(currentImage.imageIndex * $(window).width())+'px';
					currentImage.gallery.css('left', newLeft);
				}).trigger('resize');
			});
		};
		
		return {
			initGallery: initGallery,
			nextImage: nextImage,
			prevImage: prevImage,
			changeImage: changeImage,
			openGalleryMenu: openGalleryMenu,
			closeGalleryMenu: closeGalleryMenu,
			toggleGalleryMenu: toggleGalleryMenu,
			menuOpen: menuOpen,
			slideshow: slideshow,
			currentImage: currentImage
		};
	};
	
	
	
	$.fn.disableSelection = function() {
		var target = $(this).get(0);
		if (typeof target.onselectstart!="undefined") { //IE route
			target.onselectstart= function() { return false }
		} else if (typeof target.style.MozUserSelect!="undefined") { //Firefox route
			target.style.MozUserSelect = "none";
		} else { //All other route (ie: Opera)
			target.onmousedown = function() { return false }
		}
		
		target.style.cursor = "default";
	}
	
	$.fn.initDrawing = function() {
		var paper = Raphael(0,0, $(window).width(), $(window).height());
		var set = paper.set();
		var paths = [];
		var curpath = null;
		globals.loading = new ChasingLoader({
												 	"paper": paper,
													"color": "#60c1ff"
												 });
		//Drawing
		var drawPath = function(e) {
			curpath.attr('path', curpath.attr('path') + ' L'+e.clientX+' '+e.clientY);
		}
		
		// Start drawing
		$('body').bind('mousedown', function(e) {
			if(e.which == 1) {
				var newPath = paper.path('M'+e.clientX+' '+e.clientY);
				newPath.attr('stroke', '#60c1ff');
				newPath.attr('stroke-width', '1.4');
				paths.push(newPath);
				curpath = paths[paths.length-1];
				$('body').bind('mousemove', drawPath);
			}
		});
		
		// Stop drawing
		$('body').bind('mouseup mouseleave', function(e) {
			if(e.which == 1) {
				if(curpath !== null) {
					$('body').unbind('mousemove', drawPath);
					var opacity = 1;
					var path = curpath;
					
					var timer = setInterval(function() {
						opacity -= settings.drawing.fadeSpeed;
						path.attr('opacity', opacity);
						if(opacity <= 0) {
							path.remove();
							clearInterval(timer);
						}
					}, 30);
					
					curpath = null;
				}
			}
		});
		
		// Resize "paper" on window resize
		$(window).resize(function() {
			paper.setSize($(window).width(), $(window).height())
		});
	}
	
	var initInstructions = function() {
		var instructions = $('#instructions');
		var target = {left:0,top:0};
		var width = instructions.outerWidth();
		var height = instructions.outerHeight();
		var offset = 10;
		
		$(document).bind('mousemove.instructions',$.throttle(30,function(e) {
			var position = instructions.position();
			var windowSize = {
				width: $(window).width(),
				height: $(window).height()
			}
			
			var target = {
				x: e.clientX + width < windowSize.width ? e.clientX + 10 : windowSize.width - width,
				y: e.clientY + height < windowSize.height ? e.clientY + 10 : windowSize.height - height
			};
			
			instructions.css({
				// left: Math.round(position.left + (target.x - position.left) / 5),
				// top: Math.round(position.top + (target.y - position.top) / 5),
				left: target.x,
				top: target.y
			});
		}));
		
		var interval = setInterval(function() {
			if(globals.nChanges == 3) {
				instructions.fadeOut(500, function() {
					$(document).unbind('mousemove.instructions');
				})
				clearInterval(interval);
			}
		}, 200);
	};
	
	var initUrlHandler = function() {
		if(Modernizr.history) {
			if(window.location.hash != '') {
				changeUrl({}, window.location.hash.replace('#/', ''));
			}
			
			window.addEventListener('popstate', function(e) {
				onUrlChange(window.location.pathname);
			},true);
		} else {
			if(window.location.pathname.length > 1) {
				window.location.href = '/#'+window.location.pathname;
			}
			$.address.externalChange(function(event) {
				onUrlChange(event.value);
			});
			onUrlChange(window.location.hash);
		}
		if(globals.firstUrlChange) {
			setTimeout(function() {
				onUrlChange(document.location.pathname);
			},10);
		}
	}
	
	var changeUrl = function(state,url) {
		if(Modernizr.history) {
			history.pushState(state, null, '/'+url);
		} else {
			window.location.hash = '/'+url;
		}
		postAnalytics('/'+url);
	}
	
	var onUrlChange = function(pathName) {
		var pathSplit = pathName.match(/([\w-&]+)\/(\d+)/);
		try {
			var galleryId = '#gallery-'+pathSplit[1];
			var imageIndex = parseInt(pathSplit[2])-1;
			
			gallery.changeImage({
								galleryIndex: $(galleryId).index(),
								imageIndex: imageIndex
								}, false, false);
		} catch(err) {
			gallery.changeImage({
								galleryIndex :0,
								imageIndex: 0
								}, false, false);
		}
		
		if(globals.firstUrlChange) {
			globals.firstUrlChange = false;
			gallery.initGallery();
		}
	}
	
	var postAnalytics = function(page) {
		////////////////////////////////////////////
		//Google Analytics
		////////////////////////////////////////////
		if(window['_gaq']) {
			window['_gaq'].push(['_trackPageview', '/'+page]);
		}
	}
	
	$(document).ready(function () {
		$('body').disableSelection();
		gallery = initGalleries();
		about = initAbout();
		
		initUrlHandler();

		$('#current-gallery-label a').click(function(e) {
			e.preventDefault();
			e.stopPropagation();
			gallery.toggleGalleryMenu();
			about.close();
		});
		
		$('#open-about a').click(function(e) {
			e.preventDefault();
			e.stopPropagation();
			about.toggle();
			gallery.closeGalleryMenu();
		});
		
		$('#toggle-slideshow a').click(function(e) {
			e.preventDefault();
			e.stopPropagation();
			gallery.slideshow.toggle();
		});
		
		// Set up raphael svg drawing engine
		$('body').initDrawing();
		
		initInstructions();

		var onGesture = function(gesture) {
			switch(gesture) {
				case 'right':
				case 39:
					gallery.nextImage();
				break;
				case 'left':
				case 37:
					gallery.prevImage();
				break;
				case 'down':
				case 40:
					about.toggle();
					gallery.closeGalleryMenu();
				break;
				case 'up':
				case 38:
					about.close();
					gallery.toggleGalleryMenu();
				break;
			}
		}
		var uiState = {};
		
		var hideUI = function() {
			if(!about.isOpen()) {
				$("#info, #logo, #gallery-menu, #fwa").fadeOut(200);
				uiState.hidden = true;
			}
		}
		
		var restoreUI = function(){
			$("#info, #logo, #gallery-menu").fadeIn(200);
			uiState.hidden = false;
		}
		var resetTimeout = function(e){
			if(e.clientX != globals.mouse.x || e.clientY != globals.mouse.y || e.keyPress) {
				clearTimeout(timeout);
				if(!uiState.hidden) {
					timeout = setTimeout(hideUI, UI_HIDE_TIMEOUT * 1000);
				}
				else {
					restoreUI();
				}
			}
			globals.mouse.x = e.clientX;
			globals.mouse.y = e.clientY;
		}
		var timeout = null;
		
		initContextMenu();
		$("#previous").click(function(){
			gallery.prevImage();
		});
		$("#next").click(function(){
			gallery.nextImage();
		});
		
		
		$(document).bind("mousemove",function(event){resetTimeout(event)});
		// Hook up gestures to actions
		$('body').fancygestures({'s': '432101234', 'o': '432107654'}, onGesture);
		
		$(document).keydown(function(e) {
			e.keyPress = true;
			resetTimeout(e);
			if(e.which == 39 || e.which == 37 || e.which == 38 || e.which == 40 ) {
				e.preventDefault();
			}
			onGesture(e.which) });
		});
})(jQuery);
