/*
Copyright 2010 Spencer Small
*/

/********************************
 *       UTILITY FUNCTIONS      *
 ********************************/
// Utility function for padding a number
function pad(num,len){
	var str = ''+num;
	while (str.length < len){
		str = '0' + str;
	}
	return str;
}

// Load the specified playlist
function loadPlaylist(player, playlist){
	$.ajax({
		url: 'http://www.paradoxical.ly/player/serveplaylist.php', 
		dataType: "jsonp",
		data: ("playlist="+playlist),
		error: function (request, status, error){
			console.log("Error: " + error);
		},
		success: function (data){
			var playlistObject = JSON.parse(unescape(data));
			player.setUpPlayer(playlistObject);
		}
	});
}

/********************************
 *       CLOSURE CREATION       *
 ********************************/

// Due to javascript weirdness, it is necessary to create
// closures for audio player events, rather than relying on the
// "this" keyword

// Update the track and track information
function updateTrack(player){
	return (function() {
		window.clearInterval(player.updateTimer);
		player.audio.pause();
		$(player.audio).children().remove();
		player.playButton.button("option","icons",{primary:'ui-icon-play'})
			.attr('title',"Play");
		player.slider.slider("option","value",0);
		player.currentTime.html("0:00");
		player.totalTime.html("-:--");
		player.trackTitle.html(player.tracks[player.currTrack].name);
		player.trackDescrip.html(player.tracks[player.currTrack].description);
		for (var index in player.tracks[player.currTrack].sources){
			var source = player.tracks[player.currTrack].sources[index];
			var type = source.type;
			var url = source.url;
			var newSource = $(document.createElement("source"));
			newSource.attr({'type': type, 'src': url});
			if (player.audio.canPlayType(type) != ""){
				$(player.audio).append(newSource);
			}
		}
		player.audio.load(); // VERY IMPORTANT; without this, it will continue playing the old track
	});
}

// Update the time display and, if the current track has ended, play the next one
function updateTime(player){
	return (function () {
		var currTime = player.audio.currentTime;
		var duration = player.audio.duration;
		var totalMins = Math.floor(duration / 60);
		var currMins = Math.floor(currTime / 60);
		var totalSecs = pad(Math.round(duration % 60),2);
		var currSecs = pad(Math.round(currTime % 60),2);
		player.totalTime.text(totalMins+":"+totalSecs);
		player.currentTime.text(currMins+":"+currSecs);

		if (!player.mouseOverSlider){
			var sliderMax = player.slider.slider("option","max");
			var sliderVal = Math.round((currTime / duration)*sliderMax);
			player.slider.slider("option","value",sliderVal);
		}

		// If the track has ended, advance to the next one and start playing
		if (player.audio.ended && player.playNext()) { player.playOrPause(); }
	});
}

// Play or pause the audio, depending on its current state
function playOrPause(player){
	var updateTime = this.updateTime(player);
	return (function (){
		if (player.audio.paused){
			player.playButton.button("option","icons",{primary:'ui-icon-pause'})
				.attr('title',"Pause");
			player.audio.play();
			player.updateTimer = window.setInterval(updateTime,500);
		}
		else{
			player.playButton.button("option","icons",{primary:'ui-icon-play'})
				.attr('title',"Play");
			player.audio.pause();
			window.clearInterval(player.updateTimer);
		}
	});
}

// Play the previous track
function playPrevious(player){
	return (function (){
		if (player.currTrack > 0){
			player.currTrack--;
			player.updateTrack();
			if (player.currTrack === 0)
			{
				player.prevButton.addClass("ui-state-disabled")
					.attr('disabled','disabled');
			}
			player.nextButton.removeClass('ui-state-disabled')
				.removeAttr('disabled');
			return true;
		}
		return false;
	});
}

// Play the next track
function playNext(player){
	return (function (){
		if (player.currTrack != (player.tracks.length - 1)){
			player.currTrack++;
			player.updateTrack();
			if (player.currTrack == (player.tracks.length-1))
			{
				player.nextButton.addClass("ui-state-disabled")
					.attr('disabled','disabled');
			}
			player.prevButton.removeClass('ui-state-disabled')
				.removeAttr('disabled');
			return true;
		}
		return false;
	});
}

/********************************
 *       THE PLAYER OBJECT      *
 ********************************/

// Definition of the Player object
function Player(container, playlist){
	this.target = container;
	loadPlaylist(this, playlist); 
}
Player.prototype = {
	currTrack: 0,
	mouseOverSlider: false,
	createControls: function(){
		var controls = $(document.createElement("div"));
		controls.addClass("controls ui-widget-header ui-corner-all");

		this.prevButton = $(document.createElement("button"));
		this.prevButton.addClass("ui-state-disabled")
			.attr("disabled",'disabled')
			.text("Previous")
			.button({
				text: false,
				icons: {primary: 'ui-icon-seek-first'}
			})
			.click(this.playPrevious);
		
		this.playButton = $(document.createElement("button"));
		this.playButton.button({
				text: false,
				icons: {primary: 'ui-icon-play'}
			})
			.click(this.playOrPause);
		
		this.nextButton = $(document.createElement("button"));
		this.nextButton.button({
				text: false,
				icons: {primary: 'ui-icon-seek-end'}
			})
			.click(this.playNext);

		var player = this;
		this.slider = $(document.createElement("span"));
		this.slider.addClass("slider")
			.slider()
			.mouseenter(function (event) {
				player.mouseOverSlider = true;
			})
			.mouseleave(function (event) {
				player.mouseOverSlider = false;
			})
			.mousemove(function (event) {
				var pos = event.pageX - $(this).offset().left;
				$(this).slider("option","value",pos);
			})
			.mousedown(function (event) {
				player.audio.currentTime = ($(this).slider("option","value") / $(this).slider("option","max")) * player.audio.duration;
			});
		var timeContainer = $(document.createElement("span"));
		timeContainer.addClass("time ui-widget-content ui-corner-all");

		this.currentTime = $(document.createElement("span"));
		this.currentTime.text("-:--");

		this.totalTime = $(document.createElement("span"));
		this.totalTime.text("-:--");

		timeContainer.text("/")
			.prepend(this.currentTime)
			.append(this.totalTime);
		
		controls.append(this.prevButton)
				.append(this.playButton)
				.append(this.nextButton)
				.append(this.slider)
				.append(timeContainer);
		
		return controls;	
	},
	setUpPlayer: function(playlistData){
		this.playOrPause = playOrPause(this);

		this.playNext = playNext(this);

		this.playPrevious = playPrevious(this);

		this.updateTrack = updateTrack(this);

		this.tracks = playlistData.Tracks;

		this.audio = document.createElement("audio");
		
		// Eventually this will be replaced with the figure element
		var container = $(document.createElement("div"));
		container.addClass("Player ui-widget");
		
		var title = $(document.createElement("h4"));
		title.addClass("playlistTitle ui-widget-content ui-corner-top")
			 .text(playlistData.Name);
		
		var controls = this.createControls();

		var descrip = $(document.createElement("div"));
		descrip.addClass("descrip ui-widget-content ui-corner-all");

		this.trackTitle = $(document.createElement("h5"));
		this.trackTitle.addClass("title");

		this.trackDescrip = $(document.createElement("p"));
		this.trackDescrip.addClass("body");

		descrip.append(this.trackTitle)
			.append(this.trackDescrip);

		container.append(this.audio)
			.append(title)
			.append(controls)
			.append(descrip);

		this.target.replaceWith(container);
		this.slider.slider("option","max",this.slider.width());
		this.updateTrack();
	}
};

/********************************
 *          SET-UP CODE         *
 ********************************/

// Load the Paradoxical Player
function loadPlayer(){
	$("player").each(function (){
		var p = new Player($(this), $(this).attr('playlist'));
	});
}

// Load the javascript libraries to be used by the Paradoxical Player
function loadLibraries(){
	if (typeof jQuery == 'undefined'){
		var head= document.getElementsByTagName('head')[0];
		var script= document.createElement('script');
		script.type= 'text/javascript';
		script.src= 'http:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/1.4.2\/jquery.min.js';
		head.appendChild(script);
		var loadjQueryUI = function(){
			if (typeof jQuery.ui != 'undefined'){ return; }
			var head= document.getElementsByTagName('head')[0];
			var script= document.createElement('script');
			script.type= 'text/javascript';
			script.src= 'http:\/\/ajax.googleapis.com\/ajax\/libs\/jqueryui\/1.8.2\/jquery-ui.min.js';
			head.appendChild(script);
			script.onreadystatechange = (function () {
				if (this.readyState == 'complete'){ loadPlayer(); }
			});
			script.onload= loadPlayer;
		};
		script.onreadystatechange = function () {
			if (this.readyState == 'complete'){ loadjQueryUI(); }
		};
		script.onload= loadjQueryUI;
	}
}

// Load the CSS for the Paradoxical Player
function loadCSS(){
	for (var i in document.getElementsByTagName('link')){
		var element = document.getElementsByTagName('link')[i];
		if ((typeof element.href != 'undefined') && (element.href.search(/player\.css/i) != -1)){
			return;
		}
	}
	var head = document.getElementsByTagName('head')[0];
	var player = document.createElement('link');
	var theme = document.createElement('link');
	player.rel = 'stylesheet';
	theme.rel = 'stylesheet';
	player.type = 'text/css';
	theme.type = 'text/css';
	player.href = "http:\/\/www.paradoxical.ly\/player\/css\/player.css";
	theme.href = "http:\/\/www.paradoxical.ly\/player\/css\/trontastic\/theme.css";
	head.appendChild(player);
	head.appendChild(theme);
}

loadCSS();
loadLibraries();
