/**********************************************
* Matt's Music Page                           *
* Copyright (C) 2009 Matt Hackmann            *
* All Rights Reserved.                        *
**********************************************/

/**********************************************
* Constants                                   *
**********************************************/
var SORT_ALBUM = 0;
var SORT_ARTIST = 1;
var SORT_SONG = 2;

var NOW_PLAYING = 0;
var ALBUM_INFO = 1;
var CURRENT_LIST = 2;
var SAVED_LISTS = 3;
var ADD_MUSIC = 4;

/**********************************************
* Global Variables                            *
**********************************************/
var songs = new Array ();
var albums = new Array ();
var artists = new Array ();
var theList = new Array (); // The master list from which the display is derived
var playlist = new Playlist ();
var songPlaying = false;
var currentSlide = 0;
var savedSlide = 0;
var currentAlbum = 0;
var slideTimer = 0;
var playSong = 0; // A convenient place to store a number coming in from the hash

/**********************************************
* Generic Functions                           *
**********************************************/
function slideToggle (id)
{
	$(id).slideToggle ();
}

/**********************************************
* Class Strucutres                            *
*                                             *
* Class:       Song                           *
* Properties:  id - ID from database          *
*              title - song title             *
*              artist - database artist ID    *
*              album - database album ID      *
*              length - duration in seconds   *
**********************************************/
function Song (id, title, artist, album, length, track, disc)
{
	this.id = Number (id);
	this.title = title;
	this.artist = Number (artist);
	this.album = Number (album);
	this.length = Number (length);
	this.track = Number (track);
	this.disc = Number (disc);
}

function addSong (id, title, artist, album, length, track, disc)
{
	songs.push (new Song (id, title, artist, album, length, track, disc));
	return songs.length - 1;
}

function getSongByID (id)
{
	for (var i = 0; i < songs.length; i++) {
		if (songs[i].id == id)
			return songs[i];
	}
}

function getSongsByAlbum (id)
{
	for (var i = 0; i < theList.length; i++) {
		if (theList[i].id == id)
			return theList[i].songs;
	}
}

/**********************************************
* Class:       Album                          *
* Properties:  id - ID from database          *
*              title - album title            *
**********************************************/
function Album (id, title, artwork)
{
	this.id = id;
	this.title = title;
	this.artwork = artwork;
}

function addAlbum (id, title, artwork)
{
	albums.push (new Album (id, title, artwork));
	return albums.length - 1;
}

function getAlbumByID (id)
{
	var i = 0;
	while (albums[i].id != id)
		i++;
	return albums[i];
}

/**********************************************
* Class:       Artist                         *
* Properties:  id - ID from database          *
*              name - artist's name           *
**********************************************/
function Artist (id, name)
{
	this.id = id;
	this.name = name;
}

function addArtist (id, name)
{
	artists.push (new Artist (id, name));
	return artist.length - 1;
}

/**********************************************
* Class:       ListObject                     *
* Properties:  title - Title of the list      *
*              songs - songs in the list      *
**********************************************/
function ListObject (title)
{
	this.title = title;
	this.songs = new Array ();
}

/**********************************************
* Class:       Playlist                       *
**********************************************/
function Playlist ()
{

	// Properties
	this.songCount = 0; // Number of songs in the playlist
	this.list = new Array (); // The songs in the playlist
	this.randomEnabled = false; // Random flag
	this.playlists = new Array (); // Saved playlists
	this.currentSong = 0; // Index to the currently playing song in the playlist

	// Function:    queueSong
	// Description: Adds a song to the playlist
	this.queueSong = function (t) {
		
		t.played = false;
		
		if (!this.randomEnabled || !this.list.length) {
			this.list.push (t);
			var r = this.list.length - 1;
		}
		else {
			// Find the index of the last played song
			var n = this.currentSong + 1;
			var r = Math.floor (Math.random () * (this.list.length - n)) + n;
			this.list.splice (r, 0, t);
		}	
		
		this.updateList ();
		
		// Slide over to the playlist
		if (!slideTimer)
			savedSlide = currentSlide;
		else
			clearTimeout (slideTimer);
		gotoSlide (CURRENT_LIST);
		slideTimer = setTimeout (function () { gotoSlide (savedSlide); }, "5000");
		
		if (!songPlaying)
			this.playSong (r);
		
	}
	
	// Function:    queueAll
	// Description: Queues an entire section of songs
	this.queueAll = function (id) {
		for (var i = 0; i < theList[id].songs.length; i++)
			this.queueSong (theList[id].songs[i]);
	}
	
	// Function:    queue
	// Description: Queues a single song from the main list
	this.queue = function (id) {
		this.queueSong (getSongByID (id));
	}
	
	// Function:    queuePlaylist
	// Description: Queues all the songs in a playlist
	this.queuePlaylist = function (id) {
	
		for (var i = 0; i < this.playlists[id].songs.length; i++)
			this.queueSong (this.playlists[id].songs[i]);
		
	}
	
	// Function:    playSong
	// Description: Plays the requested song
	this.playSong = function (id)
	{
		
		var t = this.list[id];
		var a = getAlbumByID (t.album);
		updateAlbumInfo (a);
		
		$("#Art").empty ();
		$("#Art").css ("background-image", "url('./thumb.php?file=" + a.artwork + "&w=300&h=300')");
		$("#Art").append ("<img src=\"./graph.php?id=" + t.id + "\" alt=\"" + a.title + "\" />");
		$("#Stats").empty ();
		$("#Stats").append ("<h1>" + t.title + "</h1><h2>" + a.title + "</h2>");		
		
		playSong (t.id);
		this.currentSong = id;
		songPlaying = true;
		t.played = true;
		
		// Add the playing class from the current song
		$("#clist_" + this.currentSong).addClass ("playing");
		
	}
	
	// Function:    songComplete
	// Description: Handles stuff after a song finishes playing
	this.songComplete = function () {
		
		// Run the song complete script
		$.get ("./ajax/song_complete.php", {id:  this.list[this.currentSong].id});		
		
		// Remove the playing class from the current song
		$("#clist_" + this.currentSong).removeClass ("playing");
		
		// Advance in the playlist
		songPlaying = false;
		if (this.list.length > this.currentSong + 1)
			this.playSong (this.currentSong + 1);
	
	}

	// Function:    removeSong
	// Description: Removes a song from the playlist
	this.removeSong = function (id) {

	}

	// Function:    toggleRandom
	// Description: Toggles random playback and reorganizes the list appropriately
	this.toggleRandom = function () {
		this.randomEnabled = !this.randomEnabled;
		
		// If there's music playing, rearrange all the songs after the one currently playing
		if (songPlaying) {
		
		}
		
	}

	// Function:    clear
	// Description: Clears the playlist
	this.clear = function () {
		this.list = new Array ();
		this.updateList ();
	}


	// Function:    updateList
	// Description: Updates the displayed playlist
	this.updateList = function () {

		var cList = $("#Current ol");
		cList.css ("display", "block");
		cList.empty ();
		for (var i = 0; i < this.list.length; i++) {
			var t = this.list[i];
			var a = getAlbumByID (t.album);
			if (i == this.currentSong)
				cList.append ("<li id=\"clist_" + i + "\" class=\"playing\" style=\"background-image: url('./thumb.php?file=" + a.artwork + "');\" onclick=\"playlist.jumpTo ('" + i + "');\">" + t.title + "</li>");
			else
				cList.append ("<li id=\"clist_" + i + "\" style=\"background-image: url('./thumb.php?file=" + a.artwork + "');\" onclick=\"playlist.jumpTo ('" + i + "');\">" + t.title + "</li>");
		}
	
	}
	
	this.jumpTo = function (id) {
		// Remove the playing class from the current song
		$("#clist_" + this.currentSong).removeClass ("playing");
		this.playSong (id);
		
		// clear the played flag of everything after this point
		for (var i = id; i < this.list.length; i++)
			this.list[i].played = false;
		
	}
	
	// Function:    loadPlaylists
	// Description: Loads the list of playlists from the database
	this.loadPlaylists = function () {
		
		this.playlists = new Array ();
		$("#Saved ul").empty ();
		
		// Load and parse the playlist XML file
		$.get ("./ajax/loadplaylists.php", {}, function (data) {
			$(data).find ("playlist").each (function () {
			
				var t = new Object ();
				t.title = $(this).find ("name").text ();
				t.songs = new Array ();
				$(this).find ("track").each (function () {
					var id = parseInt ($(this).find ("id").text ());
					t.songs.push (getSongByID (id));
				});
				
				playlist.playlists.push (t);
				var id = playlist.playlists.length;
				$("#Saved").append ("<ul class=\"Playlist\" id=\"Playlist" + id + "\"><li><a class=\"AlbumTitle\" href=\"javascript:playlist.queuePlaylist('" + (id - 1) + "');\">+</a> <a class=\"AlbumTitle\" href=\"javascript:slideToggle ('#Playlist" + id + "_Songs');\">" + t.title + "</a></li><li><ol id=\"Playlist" + id + "_Songs\" class=\"Playlist\"></ol></li></div>");
				for (var i = 0; i < playlist.playlists[id - 1].songs.length; i++) {
					var t = playlist.playlists[id - 1].songs[i];
					var a = getAlbumByID (t.album);
					$("#Playlist" + id + "_Songs").append ("<li style=\"background-image: url('./thumb.php?file=" + a.artwork + "');\" onclick=\"playlist.queue ('" + t.id + "');\">" + t.title + "</li>");
				}
			
			});
		});
		
	}
	
	// Function:    savePlaylist
	// Description: Saves a playlist to the database
	this.savePlaylist = function () {
		
		// Set up the song list string
		var strList = "";
		for (var i = 0; i < this.list.length; i++)
			strList += this.list[i].id + ",";
		strList = strList.substring (0, strList.length - 1);
		
		// Send the list to be saved
		$.get ("./ajax/saveplaylist.php", {"playlist": document.savelist.name.value, "songs": strList});
		
		// Hide the form and display the header
		$("#Current .header").css ("display", "block");
		$("#Current .form").css ("display", "none");
		return false;
		
	}

}

/**********************************************
* Callback Functions                          *
**********************************************/
function loadSongs (data)
{
	
	// Populate the albums array
	$(data).find ("album").each (function () {
	
		var id = $(this).find ("aid").text ();
		var title = $(this).find ("name").text ();
		var artwork = $(this).find ("artwork").text ();
		addAlbum (id, title, artwork);
	
	});
	
	// Populate the songs array
	$(data).find ("track").each (function () {
	
		var id = $(this).find ("id").text ();
		var title = $(this).find ("title").text ();
		var album = $(this).find ("album_id").text ();
		var duration = $(this).find ("duration").text ();
		var disc = $(this).find ("disc").text ();
		var track = $(this).find ("number").text ();
		addSong (id, title, 0, album, duration, track, disc);
		
	});
	
	// Populate the master list
	sortList (SORT_ALBUM);
	
}

/**********************************************
* Display Functions                           *
**********************************************/
function pageLoaded ()
{

	// Retrieve the songlist
	$.get ("./ajax/songlist.php", {}, loadSongs);
	playerInitialize ();
	$(window).resize (windowResize);
	windowResize ();

}

function refreshAll ()
{
	// Start everything over from scratch
	pause ();
	songs = new Array ();
	albums = new Array ();
	artists = new Array ();
	theList = new Array (); // The master list from which the display is derived
	playlist = new Playlist ();
	$.get ("./ajax/songlist.php", {"generate":"true"}, loadSongs);
}

function windowResize ()
{

	// Get the height of the window
	var h = $(window).height ();
	$("#SongList").height (h - 30);

	// Set up the slides
	var winWidth = $(window).width ();
	var w = $("#RightPane").width ();
	$("#Slides").height (h - 170);
	$("#Slides").width (w * 5);
	$("#Slides > div").width (w);
	$("#Slides").css ("left", (currentSlide * w * -1) + "px");
	
}

function gotoSlide (slide)
{
	var w = $("#Current").width ();
	$("#RightPane ul > li").removeClass ("Selected");
	var l = (currentSlide - slide) * w;
	if (l < 0)
		$("#Slides").animate ({left: "-=" + Math.abs (l) + "px"});
	else
		$("#Slides").animate ({left: "+=" + l + "px"});
	currentSlide = slide;
	$("#SlideNav" + slide).addClass ("Selected");
	
	// clear the slide timer if on was set
	if (slideTimer) {
		clearTimeout (slideTimer);
		slideTimer = 0;
		savedSlide = 0;
	}
	
}

// Function:    sortList
// Description: Sorts the display array based upon the sorting parameters.
function sortList (sorting)
{

	// clear the master list
	theList = new Array ();
	var last = 0, i = 0, thisVal = 0;

	// Figure out how the list should be sorted
	switch (sorting) {
		case SORT_ARTIST:
			break;
		case SORT_SONG:
			
			// Sort the songs by title
			songs.sort (function (a, b) {
				if (a.title.substr (0, 4).toLowerCase () == "the ")
					x = a.title.substr (4).toLowerCase ();
				else
					x = a.title.toLowerCase ();
				if (b.title.substr (0, 4).toLowerCase () == "the ")
					y = b.title.substr (4).toLowerCase ();
				else
					y = b.title.toLowerCase ();
				return x < y ? -1 : (x == y) ? a.track < b.track ? -1 : a.track == b.track ? 0 : 1 : 1;
			});
			
			// Begin creating the listings
			for (var j = 0; j < songs.length; j++) {
				if (!songs[j].title)
					songs[j].title = "No Name";
				
				// Check to see if we're on a new letter (or number)
				if (songs[j].title.substring (0, 4).toLowerCase () == "the ")
					thisVal = songs[j].title.substring (4).substring (0, 1).toUpperCase ();
				else
					thisVal = songs[j].title.substring (0, 1).toUpperCase ();
				
				if (thisVal != last) {
					theList.push (new ListObject (thisVal));
					i = theList.length - 1;
					last = thisVal;
					theList[i].title = thisVal;
					theList[i].id = i;
					theList[i].artwork = "./album_art/no_art.png";
				}
				
				// Dump the song
				theList[i].songs.push (songs[j]);
				
			}
			break;
		case SORT_ALBUM:
		default:
		
			// Sort all the songs in the library by album ID (descending)
			songs.sort (function (a, b) { return (a.album < b.album) ? -1 : (a.album == b.album) ? 0 : 1; });

			// Begin populating the list
			for (var j = 0; j < songs.length; j++) {

				// If this album is different from the previous, add a new group to the array
				if (songs[j].album != last) {
					theList.push (new ListObject ());
					i = theList.length - 1;
					var album = getAlbumByID (songs[j].album);
					theList[i].id = album.id;
					theList[i].title = album.title;
					theList[i].artwork = album.artwork;
					last = songs[j].album;
					
					// If the is not the first item in the list, sort the previous songs by song disc, number
					if (i)
						theList[i - 1].songs.sort (function (a, b) {return (a.disc < b.disc) ? -1 : (a.disc == b.disc) ? (a.track < b.track) ? -1 : (a.track == b.track) ? 0 : 1 : 1; });
					
				}
				
				// Add the song to the list
				theList[i].songs.push (songs[j]);
				
			}
			
			// Sort the last set of songs
			theList[i].songs.sort (function (a, b) {return (a.track < b.track) ? -1 : (a.track == b.track) ? (a.disc < b.disc) ? -1 : (a.disc == b.disc) ? 0 : 1 : 1; });
			
			// Finally, sort the list by album title
			theList.sort (function (a, b) {
				if (a.title.substr (0, 4).toLowerCase () == "the ")
					ta = a.title.substr (4).toLowerCase ();
				else
					ta = a.title.toLowerCase ();
				if (b.title.substr (0, 4).toLowerCase () == "the ")
					tb = b.title.substr (4).toLowerCase ();
				else
					tb = b.title.toLowerCase ();
				return ta < tb ? -1 : (ta == tb) ? 0 : 1;
			});
		
			break;
	}

	// Refresh the list
	displayList ();
	
	// Load the playlists
	playlist.loadPlaylists ();
	
}

// Function:    displayList
// Description: Displays the list generated in sortList
function displayList ()
{

	var h, o, w, t;
	var m = /\((.*?)\)/;
	
	// clear out the current list
	w = $("#SongList").width () - 60;
	$("#SongList").empty ();
	
	// Populate the list
	for (var i = 0; i < theList.length; i++) {
	
		// Add the section header
		if (theList[i].artwork) {
			$("#SongList").append ("<div class=\"Section\" onclick=\"slideToggle ('#Songs_" + i + "');\" style=\"background-image: url('./thumb.php?file=" + theList[i].artwork + "');\"><a class=\"AlbumArt\" id=\"AA" + theList[i].id + "\" href=\"javascript:playlist.queueAll ('" + i + "');\">&nbsp;</a><div class=\"AlbumTitle\">" + theList[i].title + "</div><div class=\"clear\"></div></div>");
			
			// Check to see if the album title is too long for the line
			o = $(".AlbumTitle:last");

			if (o.width () >= w) {
				
				// The most common problem with overly long album names is the addition of "original soundtrack" in parenthesis
				// This attempts to remove them without having to destroy the whole album title
				if (theList[i].title.match (m)) {
					t = theList[i].title.replace (m, "");
					o.html (t);
				}
				
				// If the new title is still too large, truncate it
				if (o.width () >= w) {
					t = theList[i].title.substr (0, theList[i].title.length / 2) + "...";
					o.html (t);
				}
				
			}
			
			// Vertically center the text
			o.css ({"padding-top": ((35 - o.height ()) / 2) + "px"});
			
		}
		
		// Add the songs
		$("#SongList").append ("<ul id=\"Songs_" + i + "\"><li><a class=\"edit\" onclick=\"editAlbumInfo('" + theList[i].id + "');\">Edit Album/Track Info</a></li></ul>");
		for (var j = 0; j < theList[i].songs.length; j++)
			$("#Songs_" + i).append ("<li>" + theList[i].songs[j].track + ". <a href=\"javascript:playlist.queue (" + theList[i].songs[j].id + ");\">" + theList[i].songs[j].title + "</a></li>");
	
	}

}

// Function:    editAlbumInfo
// Description: Sets an album up for editing
function editAlbumInfo (album)
{
	
	var a = getAlbumByID (album);
	
	// Set up the pane
	$("#AlbumInfo h1").text (a.title);
	$("#AlbumInfo div.left:first").html ("<img src=\"./thumb.php?file=" + a.artwork + "&w=300&h=300\" alt=\"" + a.title + "\" /><a onclick=\"deleteAlbum ('" + album + "');\" title=\"Delete Album\">Delete Album</a><a onclick=\"$('#AlbumSearch').show (); $('#AlbumTracks').hide ();\" title=\"Change Album Art\">Change Album Art</a><a onclick=\"$('#AlbumSearch').hide (); $('#AlbumTracks').show ();\" title=\"Edit Tracks\">Edit Tracks</a>");
	
	// Populate the list with the albums songs
	var s = getSongsByAlbum (album);
	$("#AlbumInfo div ul").empty ();
	for (var i = 0; i < s.length; i++)
		$("#AlbumInfo ul").append ("<li><a class=\"delete\" title=\"Delete Track\" onclick=\"deleteTrack ('" + s[i].id + "');\"><span>[ Delete ]</span></a><a class=\"edit\" title=\"Edit Track Information\" onclick=\"prepareSongEdit ('" + s[i].id + "');\"><span>[ Edit ]</span></a> " + s[i].title + "</li>");
	
	gotoSlide (ALBUM_INFO);
	
}

// Function:    updateAlbumInfo
// Description: Updates the album info pane
function updateAlbumInfo (a)
{
	
	currentAlbum = a.id;
	
	// Create the search terms for finding album art
	var t = a.title;
	var l = t.length;
	t.replace (/\((.*?)\)/, "");
	if (t.length != l)
		t += " OST";
	document.forms["albumArt"].search.value = t;
	
}

// Function:    findArtwork
// Description: Searches for album art on the currently playing song
function findArtwork (form)
{
	
	var a = currentAlbum;
	
	$.get ("./ajax/album_art.php", {"terms": form.search.value}, function (data) {
		var o = $("#AlbumInfo ul");
		o.empty ();
		$(data).find ("album").each (function () {
			o.append ("<li><a href=\"javascript:changeArtwork ('" + currentAlbum + "', '" + $(this).find ("imgurl").text () + "');\"><img src=\"" + $(this).find ("thumb").text () + "\" /><br />" + $(this).find ("dimensions").text () + "</a></li>");
		});
	});

}

function changeArtwork (id, url)
{
	$.get ("./ajax/album_art.php", {"action": "change", "url": url, "id": id}, function (data) {
		var a = getAlbumByID (id);
		a.artwork = $(data).find ("art").text ();
		
	});
}

function getCurrentArtwork ()
{
	findArtwork (playlist.list[playlist.currentSong].song.album);
}

function beginSave ()
{
	$("#Current .header").css ("display", "none");
	$("#Current .form").css ("display", "block");
	document.savelist.name.value = "";
	document.savelist.name.focus ();
}
