// requires jquery and soundmanager2

jQuery(function($) {
	  
	// get canvas or be bored
	if (M.elEq && M.elEq.getContext && M.elPeak && M.elPeak.getContext) {		
		M.eq = M.elEq.getContext('2d');	
		M.peak = M.elPeak.getContext('2d');	
	} else {
		$('canvas').replaceWith(function(){ return '<div id="'+ $(this).attr("id") +'" class="canvas"></div>';});
		$('body').addClass('boring');
	}
	
	// action tracking
	$('#actions a').live('click',function(){ pageTracker._trackEvent('Action', $(this).parent().attr('class')); });
	
	// scoundrels
	$('.hello a').scoundrels();

});

// soundmanager settings
soundManager.url = '/sm/';
soundManager.useHighPerformance = true;
soundManager.useFastPolling = false;
soundManager.flashVersion = 9;
soundManager.debugMode = false;

// No Flash
soundManager.onerror = function() {	$('body').addClass('boring'); };

// SM initializer
soundManager.onload = function() {
	
	var mySound = M.createSound($('#playlist li:first-child a'));
	
	// create the controller to toggle start/pause of whatever sound is loaded
	$('<a id="control" href="#">Play/Pause</a>').bind('click',function(){				
		mySound.togglePause();
		$('body').toggleClass('playing').addClass('ready');
		M.state = !M.state;
		// if this is initializes play for first time, make sure to highlight item in playlist
		// once playing starts for the first time, something will always be "current" whether 
		// paused or not until reach end of playlist
		if(!$('.current').length) {
			$('#playlist li:first').addClass('current');
		}
		return false;
	}).appendTo('#player');
	
	// animation for the controller
	$('#player').bind('mouseenter mouseleave',function(e){		
		if($('body.playing').length) {
			$('#control',this)[e.type == "mouseenter" ? 'fadeIn' : 'fadeOut']();
		}		
	});
	
	$('#playlist a').bind('click',function(){
		$('body').addClass('ready');
		// if click is playing sound
		if($(this).parent().is('.current')) {
			mySound.togglePause();
			if($('body').is('.playing')) {
				$('body').removeClass('playing');
				$("#control").fadeIn();
			} else {
				$("#control").fadeOut(function(){ $('body').addClass('playing'); });				
			}			
		} else {
			// load new sound
			mySound.stop();
			M.clearCanvas();
			$('#playlist li').removeClass('current');
			$(this).parent().addClass('current');
		 	mySound = M.createSound($(this)); 
			mySound.play();
			$("#control").fadeOut(function(){ $('body').addClass('playing'); });			
		}
		return false;				
	});
	
	// enable seeking
	$('#player').append('<span id="seek">Seek</span>').bind({
		mouseup : M.seek,
		mousemove : function(e){
			// help with toggling the seek bar
			$('body')[e.pageY < parseInt($('#eq').height()) ? 'addClass' : 'removeClass']('eq');		
		}		
	});
	$('#peaks').bind('mousemove',M.trace);
	
	$(document).keydown(function(e) { 

		// make sure not trying to do UA function before hijacking
		M.isModifier(e);
		
		if(!M.modifier) {
			 // toggle pause : space
			if(e.keyCode == 32) { pageTracker._trackEvent('Keyboard', 'Toggle', M.id, e.keyCode); M.keyboardToggle(); return false; }
		
			// next : right, down, j
			if(e.keyCode == 39 || e.keyCode == 40 || e.keyCode == 74) { pageTracker._trackEvent('Keyboard', 'Next', M.id, e.keyCode); M.keyboardNext(); return false; }

			// prev : left, up, k
			if(e.keyCode == 37 || e.keyCode == 38 || e.keyCode == 75) { pageTracker._trackEvent('Keyboard', 'Previous', M.id, e.keyCode); M.keyboardPrev(); return false; }
		}
		
	}).bind('keyup',M.isModifier).focus(function(){
		M.modifier = false; // reset missed key event
	});
	
};

// M is for Murder
var M = {
	// canvas elements
	elEq : document.getElementById('eq'),
	elPeak : document.getElementById('peaks'),
	modifier : false,
	isModifier : function(e) {	
		var key = e.keyCode == 224 || e.keyCode == 91 || e.keyCode == 93, // check for control/command key
			setdown = !M.modifier && e.type == 'keydown' && key, // pressed modifier key
			unsetup = M.modifier && e.type == 'keyup'; // released any key -- modifier keyup doesn't always get triggered
		
		if(setdown || unsetup) {
			M.modifier = !M.modifier;
		}
	},	
	createSound : function($obj) {
		M.id = $obj.attr('href').split('/')[1].split('.')[0];
		pageTracker._trackEvent('Audio', 'Play', M.id);
		return soundManager.createSound({	
			id: M.id,
			url: $obj.attr('href'),
			useEQData: true,
			usePeakData: true,
			whileplaying: M.whileplaying,
			onfinish: M.onfinish
		});
	},
	onfinish : function (key) {
		var $sound = $('#playlist .current').next().find('a');
		pageTracker._trackEvent('Audio', 'Finish', M.id);
		if($sound.length) {
			$sound.trigger('click');
		} else {
			if(key) { return false; }
			$('#playlist li').removeClass('current');
			$('body').removeClass('playing');		
			M.clearCanvas();
			$("#control").fadeIn();
		}
	},
	whileplaying : function () {

		// general visualization settings
		var downSample = 4, // avoid melting processors
			eqSamples = 192, // drop the last 25% of the spectrum (>16500 Hz), most stuff won't actually use it.
			sampleCount = (eqSamples / 4), // number of samples total
			w = M.elEq.width, // canvas width
			h = M.elEq.height, // canvas height
			wp = M.elPeak.width, // canvas width
			hp = M.elPeak.height, // canvas height
			l = this.eqData.left, // left channel EQ
			r = this.eqData.right, // right channel EQ
			p = this.peakData.left + this.peakData.right, // sum of peaks, should be between 0-2
			b = (w / 2)/sampleCount, // bar width	
			j = 1; // just another counter		
						
		// clears frequency canvas and set fills
		M.elEq.width = M.elEq.width;	
		M.eq.fillStyle = "rgba(0,0,0,.6)";
		M.peak.fillStyle = "rgba(255,255,255,.2)";
			
		for (var i = 0; i < eqSamples; i += downSample) {			
			// eq left and right
			M.eq.fillRect( (w / 2) - (b * j), h - (l[i] * h * 2), b * 4, 300 );
			M.eq.fillRect( (w / 2) + (b * j), h - (r[i] * h * 2), b * 4, 300 );
			j++;
		}		

		// peaks
		M.peak.fillRect( (this.position / this.duration) * wp, hp - (( p / 2 ) * hp), 1, 3);
		
	},
	seek : function(e) {
		if (e.pageY < parseInt($('#eq').height()) + 4) { return; }
		var percent = ( e.pageX - $('#peaks').offset()['left'] ) / parseInt($('#peaks').width());
		soundManager.setPosition(M.id,soundManager.sounds[M.id].duration * percent);
		
		if(!$('body.playing').length) {			
			soundManager.sounds[M.id].play();
			$('body').toggleClass('playing');
		}		
		pageTracker._trackEvent('Audio', 'Seek', M.id, Math.floor((soundManager.sounds[M.id].duration * percent)/1000));
	},
	trace : function(e) {
		$('#seek').css({ left : ( e.pageX - $('#peaks').offset()['left'] ) + 'px' });
	},
	clearCanvas : function() {		
		M.elEq.width = M.elEq.width;
		M.elPeak.width = M.elPeak.width;
	},
	keyboardToggle : function() {
		$("#control").trigger('click');
		$('#control')[!$('body.playing').length ? 'fadeIn' : 'fadeOut']();				
	},
	keyboardNext : function() {		
		M.onfinish(true);
	},
	keyboardPrev : function() {
		var $sound = $('#playlist .current').prev().find('a');
		if($sound.length) {
			$sound.trigger('click');
		} 	
	}
};

// scoundrels
// http://www.alistapart.com/articles/gracefulemailobfuscation/
// http://github.com/jaz303/jquery-grab-bag/blob/master/javascripts/jquery.text-effects.js
$.fn.scoundrels = function() {
	this.each(function() {
		$(this).attr('href','mailto:'+$(this).attr('href').replace(/.*c\/([a-z0-9._%-]+)\+([a-z0-9._%-]+)\+([a-z.]+)/ig, function(chr,p1,p2,p3) {
			function replacer(str) {
				return str.replace(/[a-z0-9]/ig,function(chr) {
					var cc = chr.charCodeAt(0);
					if (cc >= 65 && cc <= 90) cc = 65 + ((cc - 52) % 26);
					else if (cc >= 97 && cc <= 122) cc = 97 + ((cc - 84) % 26);
					else if (cc >= 48 && cc <= 57) cc = 48 + ((cc - 43) % 10);
					return String.fromCharCode(cc);
				});
			}
			return replacer(p1) + '@' + replacer(p2) + '.' + replacer(p3); 		
		}));
	});
	return this;
};