var PlaylistController = 
{
	// Helper Property to get/set a channel's track objects
	Tracks : function( channel, tracks )
	{
		if( tracks != null && tracks.length != null && tracks.length > 0 )
		{
			ytdj.mix.playlists[ channel ].tracks = tracks;
		}
		
		return ytdj.mix.playlists[ channel ].tracks;
	},
	
	// Load a video from a given youtube video ID
	loadVid : function( channel, vidId )
	{
		ytdj.tube.embedTube( channel, vidId );
		
		PlaylistController.preLoading( channel, true );
		PlaylistController.setCurrentTrack( channel, vidId );	
	},
	
	// Load a video from a given track object
	loadTrack : function( channel, track )
	{
		this.loadVid( channel, track.id );
	},
	
	// Add track to the playlist
	addTrack : function( channel, track )
	{
		// was trying to filter duplicates - dont think it works
		if($.inArray(track, PlaylistController.Tracks( channel )) == -1)
		{
			PlaylistController.Tracks( channel ).push( track );
		}
		
		if( ytdj.isFirstTrax && !ytdj.isFirstTimerz )
		{
			ytdj.isFirstTrax = false;
			
			// If help bubble is up, it's done now!
			ytdj.help.close( ytdj.help.HELP_SEARCH );
		}
	},
	
	removeCurrentTrack : function( channel )
	{
		this.removeTrack( channel, PlaylistController.getCurrentTrack( channel ) );
	},
	
	removeTrack : function( channel, vidId, optTrackIndex )
	{
		var vidIndex = null;
		
		if(optTrackIndex != null && PlaylistController.Tracks( channel )[optTrackIndex].id == vidId)
		{
			// Remove specific video
			vidIndex = optTrackIndex;
		}
		else
		{
			// Remove first video with matching vidId
			$.each( PlaylistController.Tracks( channel ), function( i )
			{
				if( this.id == vidId )
				{
					vidIndex = i;
					return false;
				}
			});
		}
		
		if( vidIndex != null )
		{
			PlaylistController.Tracks( channel ).splice( vidIndex ,1 )[0];
			this.update();
		}
		
		//PlaylistController.checkIfTracksAreAllGone();
	},
	
	emptyPlaylist : function( channel )
	{
		// surely this isnt the way to empty an array?!
		PlaylistController.Tracks( channel ).length = 0;
	},

	setCurrentTrack : function( channel, vidId )
	{
		$.each( PlaylistController.Tracks( channel ), function( i )
		{
			if( this.id == vidId )
			{
				ytdj.mix.playlists[ channel ].currentTrack = vidId;
			}
		});
		
		// Set current track css for playlist.
		var currentTrack = this.getCurrentTrack( channel );
		if(!currentTrack)
		{
			return
		}
		
		ytdj.setVolumeFader( channel, currentTrack.volume );
		ytdj.setCueToTime( channel, currentTrack.cuePoint );
		if( currentTrack.cuePoint != 0 )
		{
			// Set cue mode to read...
			
		}
		else
		{
			// Set cue mode to write.
		}
		
		$( ytdj.ui.Title( channel ) ).html( currentTrack.name );	
		$( ytdj.ui.PlaylistItems( channel ) ).each(function()
		{
			$(this).removeClass("selected");
			
			if($(this).data("track") == vidId )
			{
				$(this).addClass("selected");
			}
		});
	},
	
	getCurrentTrack : function( channel )
	{
		if( ytdj.mix.playlists[ channel ].currentTrack == "" ) 
		{
			return;
		}
		
		return PlaylistController.getTrackById( channel, ytdj.mix.playlists[ channel ].currentTrack )
	},
	
	getNextTrack : function( channel )
	{
		// Returns the next track in the playlist, or first if there is no next track
		var curTrack = PlaylistController.getCurrentTrack( channel ) || {};		
		var nextTrack = PlaylistController.Tracks( channel )[ 0 ];
		var returnNext = false;

		$.each( PlaylistController.Tracks( channel ), function(i)
		{
			if( returnNext )
			{
				nextTrack = PlaylistController.Tracks( channel )[ i ];
				return false; // this is "break" in jquery
			}
			
			if( curTrack.id == this.id )
			{
				returnNext = true;
			}
		});
		
		return nextTrack;

	},
	
	getTrackById : function( channel, vidId )
	{
		var theTrack = null;
		$.each( PlaylistController.Tracks( channel ), function(i)
		{
			if( this.id == vidId )
			{
				theTrack = PlaylistController.Tracks( channel )[ i ];
			}
		});
		return theTrack;
	},
	
	loadFromString : function( channel, playlistString )
	{
		if( playlistString == null ) return;
		
		var tracks = playlistString.split('|');

		for( var i = 0; i < tracks.length; i++ )
		{
			if( tracks[ i ].indexOf(';') > -1 )
			{
				var track = tracks[ i ].split(';');
				var tmpTrack = new cTrack();
				tmpTrack.name = track[ 0 ];
				tmpTrack.id = track[ 1 ];
				tmpTrack.volume = isNaN( parseInt( track[ 2 ] ) )  ? ytdj.defaultVolume : parseInt( track[ 2 ] );
				tmpTrack.cuePoint = track.length < 4 ? 0 : isNaN( parseInt( track[ 3 ] ) )  ? 0 : parseInt( track[ 3 ] );
				this.addTrack( channel, tmpTrack );
			}
		}
		
		$("#Chan1_ul, #Chan2_ul").jScrollPane({ showArrows:true });
	},
	
	// Updates the display of both channels, and saves the cookies
	update : function()
	{
		this.display( ytdj.LEFT );
		this.display( ytdj.RIGHT );
		
		// update scrollPanes for the playlists
		$("#Chan1_ul, #Chan2_ul").jScrollPane({ showArrows:true });
		PlaylistHelper.cancelOverlaysAndDragging();
		this.persistPlaylists();
	},
	
	display : function( channel )
	{
		// We need to refactor this function - bit crazy!
		
		var playlist = ytdj.mix.playlists[ channel ];
				
		// Remove existing tracks, and re-add from the model
		ytdj.ui.PlaylistItems( channel ).remove();
		
		$(playlist.tracks).each(function(i)
		{
			var trackItem = $("<li>")
				.hover(function(){ 
					//$(this).find(".trackHandle").animate( {color : "#515d63"}, 100 );	// has become annoying to use
					$(this).find(".trackHandle").addClass( "over" );
					$(this).find(".trackControls").show();
				}, function(){ 
					//$(this).find(".trackHandle").animate( {color : "#a6b3ba"}, 500 );
					$(this).find(".trackHandle").removeClass( "over" )
					$(this).find(".trackControls").hide();
				})
				.addClass("trackItem").attr("id", channel + "_" + i).data("track", this.id).data("sequence", i);
			var _this = this;
			
			// Make the name the handle
			$("<div/>").addClass("trackHandle").text(this.name.substring(0,40))
				.bind("dblclick", function(){ 
					PlaylistHelper.loadInfo(channel, this, _this.id); 
				})
				.appendTo(trackItem);
			
			// Add a container for track controls
			var trackControls = $("<div/>").addClass("trackControls").appendTo(trackItem);
			
			// Add the "Delete" dialog
			var trackDeleteConfirmation = $("<div><p>Remove this video?</p></div>").addClass("dialog").appendTo(trackItem).css("display","none");
			var trackDeleteConfirmationArrow = $('<img src="images/dialog-arrow.png" />').addClass("arrow").appendTo(trackDeleteConfirmation);
			
			$("<input type='button' />").addClass("button").val("Yes").bind("click", function(){
				PlaylistController.removeTrack( channel, _this.id, i );
			}).appendTo(trackDeleteConfirmation);
			$("<input type='button' />").addClass("button").val("No").css("opacity", ".5").bind("click", function(){
				trackDeleteConfirmation.fadeOut(100);
				$(this).parents(".trackItem").removeClass("info-open");
				PlaylistHelper.cancelOverlaysAndDragging();
			}).appendTo(trackDeleteConfirmation);
			
			$("<div/>").addClass("trackDelete").attr("title","Remove this video from this playlist").bind("click", function(e)
			{
				PlaylistHelper.allowOverlaysAndDragging();
				$(this).parents(".Chan_Playlist").find(".dialog").hide();
				$(this).parents(".trackItem").addClass("info-open").siblings().removeClass("info-open");

				trackDeleteConfirmation.fadeIn(100);

			}).appendTo(trackControls);
			
			// Add the "Load" button
			$("<div/>").addClass("trackLoad").attr("title","Load this video").bind("click", function(e)
			{ 
				ytdj.help.close(channel == ytdj.LEFT ? 0 : 1);
				
				ytdj.ui.setPlayState( channel, false);
				PlaylistController.loadVid( channel, _this.id );
				
				// Set auto-load next track on... if autoplaying.
				if( ytdj.STATE != ytdj.AUTOPLAY_OFF )
				{
					ytdj.autoplay_loading_track = channel;		
				}
				
			} ).appendTo(trackControls);
			
			// Add the "Info" button
			$("<div/>").addClass("trackInfo").attr("title","More info about this video").bind("click", function(e)
			{ 
				// show Info overlay...
				PlaylistHelper.loadInfo(channel, this.parentNode, _this.id);
			} ).appendTo(trackControls);
			
			// track thumbnail
			var info = $("<div/>").addClass("info dialog").css("display","none") // Important to hide - it's visible by default. .hide() doesn't work in Safari
			info.appendTo(trackItem);
			
			// Add it to the trax
			trackItem.appendTo( ytdj.ui.PlaylistItemContainer( channel ) );
		});

	},
	
	persistPlaylists : function()
	{
		$.cookie( 'playlist_one', this.toString( ytdj.LEFT ), { expires: 28 } );
		$.cookie( 'playlist_two', this.toString( ytdj.RIGHT ), { expires: 28 } );
	},
	
	persistVolume : function( channel )
	{
		if( PlaylistController.getCurrentTrack( channel ) == null )
			return;

		PlaylistController.getCurrentTrack( channel ).volume = 100 - parseInt(ytdj.ui.volumeSliders[ channel ].slider("value"));
		PlaylistController.persistPlaylists();
	},
	
	preLoading : function( channel, isPreLoading )
	{
		if( arguments.length == 1 )
		{
			return ytdj.mix.playlists[ channel ].preLoading;
		}
		
		ytdj.mix.playlists[ channel ].preLoading = isPreLoading;
		
	},
	
	preLoadPaused : function( channel, isPreLoadPausing )
	{
		if( arguments.length == 1 )
		{
			if( ytdj.mix.playlists[ channel ].preLoadPaused == undefined ) return false;
			return ytdj.mix.playlists[ channel ].preLoadPaused;
		}
		
		ytdj.mix.playlists[ channel ].preLoadPausing = isPreLoadPausing;
		
	},
	
	checkIfTracksAreAllGone : function()
	{
		if(PlaylistController.Tracks( ytdj.LEFT ).length > 0 ||	PlaylistController.Tracks( ytdj.RIGHT ).length > 0)
		{
			return false;
		}
		
		ytdj.isFirstTrax = true;
		// set up the help box thingos
		//ytdj.help.openAll();
			
		return true;
	},
	
	getCookie : function( channel )
	{
		return $.cookie( channel == ytdj.LEFT ? 'playlist_one' : 'playlist_two')
	},
	
	toString : function( channel )
	{
		var pl = "";
		$.each( PlaylistController.Tracks( channel ), function()
		{
			pl += TrackController.toString( this ).replace("|", "-") + "|";
		});
		return pl + "ytdj";
		
	}
}

var PlaylistHelper = 
{
	setUpLists : function()
	{
		$.each([ ytdj.LEFT, ytdj.RIGHT ], function()
		{
			var channel = this;
			$("<ul/>").attr("id", channel + "_ul").appendTo( ytdj.ui.Playlist( channel ) );
		});

		// Attach the drag/drop handlers
		ytdj.ui.PlaylistItemContainer( ytdj.LEFT ).sortable({handle : '.trackHandle', connectWith : ytdj.ui.PlaylistItemContainer( ytdj.RIGHT ), start: this.allowOverlaysAndDragging, stop: this.cancelOverlaysAndDragging, update : this.reorderPlaylist});
		ytdj.ui.PlaylistItemContainer( ytdj.RIGHT ).sortable({handle : '.trackHandle', connectWith : ytdj.ui.PlaylistItemContainer( ytdj.LEFT ), start: this.allowOverlaysAndDragging, stop: this.cancelOverlaysAndDragging, update : this.reorderPlaylist});
		
	},
	
	reorderPlaylist : function( e, ui )
	{

		if( ui.sender != null ) return; // Don't need to handle received track

		var playlistChannel = this.id;
		var receivingChannel = ui.item.parent().attr("id");

		var channel = playlistChannel.replace("_ul","");
		var oppositeChannel = channel == ytdj.LEFT ? ytdj.RIGHT : ytdj.LEFT;
		
		var currentIndex = ui.item.data('sequence');
		var insertedIndex = ui.item.prevAll("li").length;

		// remove from playlist spot
		var removedTrack = PlaylistController.Tracks( channel ).splice( currentIndex ,1 )[0];

		// add it to the new spot
		PlaylistController.Tracks(  receivingChannel == playlistChannel ? channel : oppositeChannel ).splice(insertedIndex, 0, removedTrack);

		PlaylistController.update();	
			
	},
	
	// temporarily adjust playlist CSS properties in order to show overlays correctly and allow dragging between playlists (needed as a result of scrollable playlists)
	allowOverlaysAndDragging : function() {

		$(".trackItem").css( "width", "90px" );
		$(".jScrollPaneContainer").css( "overflow", "visible" );

		// tidy up a few things
		$(".trackItem").unbind("hover").removeClass("info-open").children(".trackControls").hide();
		$(".dialog, .jScrollPaneTrack, .jScrollArrowDown, .jScrollArrowUp").hide();

		// hiding temporarily exposed items that shouldn't be		
		$(".trackItem").each( function() {
			if (($(this).offset().top < $(this).parents(".jScrollPaneContainer").offset().top) || ($(this).offset().top > ($(this).parents(".jScrollPaneContainer").offset().top + $(this).parents(".jScrollPaneContainer").outerHeight() - $(this).outerHeight()))) {
				$(this).css( "visibility", "hidden" );
			}
		});
	},
	
	// restores back to normal after allowOverlaysAndDragging
	cancelOverlaysAndDragging : function() {
		$(".trackItem").css({ width: "auto", visibility: "visible" }).children(".trackHandle").removeClass("over");
		$(".jScrollPaneContainer").css({ overflow: "hidden" });
		$("#Chan1_ul, #Chan2_ul").jScrollPane({ showArrows:true });
	},
	
	addTrack : function( channel, trackString, trackName )
	{	
		var vidId = trackString;
		if( !trackString || trackString.length == 0 )
		{
			vidId = $("#ImportExportArea").val();
		}
	
		if( vidId.substr(vidId.length - 4, 4) == "ytdj")
		{
			// Its a whole playlist, not just a video...
			PlaylistController.loadFromString( channel, vidId );
		}
		else
		{
			if( vidId.length > 13 )
			{
				var ov = vidId;
				//It ain't a straight id... lets tryparse...
				var maybeMatch = "" + vidId.match(/v[a-z_]*=[^&]{11,13}/);
				vidId = maybeMatch.replace(/^v[a-z_]*=/, "");

				if( vidId.length < 11 || vidId.length > 13)
				{
					alert("couldn't figure out that vid... sorry\n\n" + ov);
					return;
				}
			}

			var vidName = (!trackName || trackName == "") ? prompt("Vid name?") : trackName;
			if( !vidName ) return;
			vidName = vidName.length > 0 ? vidName : vidId;
			
			var theTrack = new cTrack();
			theTrack.name = vidName;
			theTrack.id = vidId;
			
			PlaylistController.addTrack( channel, theTrack );
		}
	//	PlaylistController.update();
	
	},
	
	getDebugger : function( channel )
	{
		var vidStats = $("<div/>").addClass("video-stats").attr("id", channel + "_vidStats").fadeTo(0, 0.3);
		$("<input type='text' id='" + channel + "_vidTime' /><span>Vid time</span><br />").appendTo( vidStats );
		$("<input type='text' id='" + channel + "_vidDuration' /><span>Vid duration</span><br />").appendTo( vidStats );
		$("<input type='text' id='" + channel + "_vidVolume' /><span>Vid volume</span><br />").appendTo( vidStats );
		$("<input type='text' id='" + channel + "_bytesTotal' /><span>Bytes total</span><br />").appendTo( vidStats );
		$("<input type='text' id='" + channel + "_bytesLoaded' /><span>Bytes loaded</span><br />").appendTo( vidStats );
		$("<input type='text' id='" + channel + "_bytesStart' /><span>Start bytes</span><br />").appendTo( vidStats );
		$("<input type='text' id='" + channel + "_state' /><span>State</span><br />").appendTo( vidStats );
		$("<input type='text' id='" + channel + "_states' /><span>States</span><br />").appendTo( vidStats );
		$("<input type='text' id='" + channel + "_vidId' /><span>VidId</span><br />").appendTo( vidStats );
		$("<input type='text' id='" + channel + "_title' />").css("width","200px").appendTo( vidStats ).bind("blur", function()
		{
			PlaylistController.getTrackById( channel, $("#" + channel + "_vidId").val() ).name = $(this).val();
			PlaylistController.update();
		});

		return vidStats;
	},
	
	loadInfo : function( channel, titleSpan, vidId )
	{
		// Remove any existing "info-open" classes
		$(titleSpan).parents(".Chan_Playlist").find(".trackItem").removeClass("info-open");

		// If info box is open, then just close and get outta here.
		var infoBox = $(titleSpan).siblings(".info");
		if(infoBox.is(":visible"))
		{
			infoBox.hide();
			PlaylistHelper.cancelOverlaysAndDragging();
			return;
		}

		PlaylistHelper.allowOverlaysAndDragging();
		$(titleSpan.parentNode).addClass("info-open");
		
		// Hide any open infos
		$(titleSpan).parents("ul").find(".dialog").hide();

		// Have we already loaded this track info?
		if( infoBox.html().length == 0 )
		{
			// nope... go ask youtube for some details, and populate the info box
			var videoInfoArrow = $('<span />').addClass("close").attr("title","Close").click( function() { 
				$(this).parents(".dialog").fadeOut(100);
				$(this).parents(".info-open").removeClass("info-open");
				PlaylistHelper.cancelOverlaysAndDragging();
			});
			
			infoBox.append("loading...");
			infoBox.append(videoInfoArrow).show();
			$('<img src="images/dialog-arrow.png" />').addClass("arrow").appendTo(infoBox);
			ytdj.tube.getVidInfo( channel, vidId, infoBox );
		}
		else
		{
			// Yep... just fade in the old one
			infoBox.fadeIn();
		};

		// Get info for the debug window
        var track = PlaylistController.getTrackById( channel, vidId );
		$("#" + channel + "_vidId").val( track.id );
		$("#" + channel + "_title").val( track.name );	
	},
	
	defaultList : function( playlistNumber )
	{
		var tmpFirstTimerz = ytdj.isFirstTimerz;
		ytdj.isFirstTimerz = true;
		
		PlaylistController.emptyPlaylist( ytdj.LEFT);
		PlaylistController.emptyPlaylist( ytdj.RIGHT);
		
		switch( playlistNumber )
		{
			case 0:
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("ap-OO0xqTe4", "Hall & Oates - Maneater") );
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("gnbj0w8iOeM", "Joe Jackson - Stepping Out") );
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("zVymoIwKHjE", "Billy Squire - The Stroke") );
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("30AVhf-ZLwM", "David Bowie - Let's Dance") );
				
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("3pQJvinmsiI", "Power Station - Some Like It Hot") );
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("cznha2YTTh0", "Visage - Fade to Grey") );
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("NJJQpSzDgC0", "Exile - I Wanna Kiss You All Over") );
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("lPT_3PEjnsE", "Toto - Africa") );
				break;
			case 1:
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("lxhk-cWQbrs", "Kid Koala - Fender Bender") );
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("2FwbsSdWh-U", "Sebastien Tellier - Divine (Danger Remix)") );
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("BTF7Kag_o-c", "Mr. Oizo - Analog Worms Attack") );
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("J6SKNEYvZvQ", "Midnight Juggernauts - Into the Galaxy") );
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("ZVArC_klWEI", "10cc - Dreadlock Holiday") );
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("G30nXKh1Xho", "Deerhoof - Kidz are so Small") );			
				
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("U8BWBn26bX0", "The Avalanches - Frontier Psychiatrist") );				
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("1zTkrPNNpkc", "Ratatat - Seventeen Years") );				
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("jCXjL_0Ww9E", "Flying Lotus - Tea Leaf Dancers") );
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("fZcmg4-Zm-8", "Bag Raiders - Fun Punch") );
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("AFsvgTtlJtY", "Messer Chups - Swamp Surfing") );
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("lrBZeWjGjl8", "Boards of Canada - Dayvan Cowboy") );
				break;				
			case 2:
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("ZZZADbubu0Y", "House Of Pain - Jump Around") );
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("bdTELokKfCk", "The Timelords / KLF - Doctorin' The Tardis") );
				PlaylistController.addTrack( ytdj.LEFT, TrackController.createTrack("TfJe8hQ8ha0", "OMC - How bizarre") );

				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("Vp-is6S_b_g", "Vanilla Ice - Ice Ice Baby") );				
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("He82NBjJqf8", "Baha Men - Who Let the Dogs out?") );
				PlaylistController.addTrack( ytdj.RIGHT, TrackController.createTrack("FCARADb9asE", "The Firm - Star Trekking") );
				break;
		}
		
		PlaylistController.display( ytdj.LEFT );
		PlaylistController.display( ytdj.RIGHT );
		
		ytdj.isFirstTimerz = tmpFirstTimerz;
	}

}

var TrackController = 
{
	createTrack : function( id, name )
	{
		track = new cTrack();
		track.id = id;
		track.name = name;
		return track;
	},
	
	toString : function( track )
	{
		var tmpVol = track.volume == undefined ? ytdj.defaultVolume : track.volume;
		var tmpCue = track.cuePoint == undefined ? 0 : track.cuePoint;
		return track.name.replace(";",",") + ";" + track.id + ";" + tmpVol + ";" + tmpCue;
	}
}
