/*---------------------------------------------------------------------------
 *	Omniplayer jQuery plugin
 *
 *	Description:
 *					The Omniplayer jquery plugin provides Hear It Local developers with a way to 
 *					put an audio player on their website that features independent artists from the
 *					Hear It Local database.
 *							
 *					Notable Features:
 *						- It can be used multiple times on the same page.
 *						- Pay music based on playlist type.
 *						- Display detailed information about artists, including other songs they may have.
 *						- Play all available and upcoming songs from artists in a given performance stored in the
 *							in the Hear It Local database
 *						- And then some...
 *
 *					Options:
 *						playerType: 			The Hear It Local entity that owns the playlist that the player will default to. (default:promoter)
 *						id: 					The Hear It Local database identifier for the entity whose music is being requested. (default:1 - Bay Vibes Promoter ID)
 *						smSwfUrl: 				The relative path to the directory that holds the SoundManager 2 Flash SWF files.(default: "swf/")
 *						playByDefault: 			Automatically start playing the Omniplayer playlist once the Omniplayer code has loaded.(default: false)
 *						siteDomain: 			TThe root domain of the site that is hosting the Omniplayer plugin. (default: "")
 *						artistImageSize: 		The size, in pixels, of the square thumbnail image for the currently playing artist (default: "")
 *						maxArtistName: 			The maximum number of characters allowed for the artist name in the main display and in the artist flyout. (default: 30)
 *						maxSongName: 			The maximum number of characters allowed for the song title in the main display. (default: 200)
 *						 
 *	Owner: 			Hear It Local
 *	Developer:   	Maurice Wright
 *	Last Updated:	
 *					2012.01.17					Added the onPlayerLoad() callback function/method
 *					2012.01.13					Added the onSongChange() callback function/method
 *												Fixed the problem with songs playing a few seconds when playByDefault is false
 *					2011.12.08
 * 	
 *---------------------------------------------------------------------------*/

(function($){  
	$.fn.omniplayer = function(options) {  
		
		// ------------------------------------------
		// Load the options
		var o = $.extend({}, $.fn.omniplayer.defaults, options);
		var thisObj = $(this);
		
		// ------------------------------------------
		// Set the options inside of the DOM element
		this[0][0] = o;
		
		// ------------------------------------------
		// Grab any parameters that may have been set manually
		
		o.parentName = (o.parentName=='') ? $(this).attr('id') : o.parentName;
		o.messageDiv = (o.messageDiv=='') ? $(this).find('.op-song-loading') : o.messageDiv;
		o.btnPlay = (o.btnPlay=='') ? $(this).find('.oplink-play') : o.btnPlay;
		o.btnPause = (o.btnPause=='') ? $(this).find('.oplink-pause') : o.btnPause;
		o.btnStop = (o.btnStop=='') ? $(this).find('.oplink-stop') : o.btnStop;
		o.btnNext = (o.btnNext=='') ? $(this).find('.oplink-next') : o.btnNext;
		o.btnPrev = (o.btnPrev=='') ? $(this).find('.oplink-prev') : o.btnPrev;
		o.btnPlayApiDiv = (o.btnPlayApiDiv=='') ? $('.omni-trigger-div') : o.btnPlayApiDiv;
		o.btnPlayApiHref = (o.btnPlayApiHref=='') ? $('.omni-trigger-href') : o.btnPlayApiHref;
		o.btnVolumeSlider = (o.btnVolumeSlider=='') ? $(this).find('.omni-button-volume') : o.btnVolumeSlider;
		
		
		
		// ------------------------------------------
		// The volume slider isn't being used by all themes
		// Comment out the code for cases where it's not being used.
		
		if ( $(this).find('.omni-button-volume').length > 0 ) {
		
			// ------------------------------------------
			// Set the volume slider parameters the volume DOM elements
		
			o.volMinX = o.btnVolumeSlider.position().left;
			o.volRange = $(this).find('.omni-volume-slider').width() - o.btnVolumeSlider.width();
			o.volMaxX = o.volMinX + o.volRange;
			volXpos = (o.smDefaultVolume/100)*o.volRange;
		
			// ------------------------------------------
			// Set the volume slider position based on the default volume
		
			o.btnVolumeSlider.position({
				my: 'left',
				at: 'left',
				of: '#' + o.parentName + ' .omni-volume-slider',
				offset: volXpos + ' 0'
			});
			//console.log(o.volMinX, o.volRange, o.volMaxX, volXpos);

			// ------------------------------------------
			// Initialize the volume slider
		
			o.btnVolumeSlider.draggable({ 
				axis: 'x',
				containment: '.omni-volume-slider',

				// Drag current position of dragged image.
				drag: function(event, ui) {

					// Show the current dragged position of image
					var currentPos = $(this).position().left;
					var song = thisObj[0]['song'];
					var volume = (currentPos/o.volRange)*100;
					song.setVolume(volume);
					//$("div#xpos").text("Left: " + currentPos.left + "\nTop: " + currentPos.top);

				}
			});
		}
		
		// ------------------------------------------
		// Set the default PLAY button behavior (.oplink-play)
		
		o.btnPlay.live('click',function(e){
			e.preventDefault();
			$.fn.omniplayer.omniPlay(thisObj,'pause');
		});

		// ------------------------------------------
		// Set the default PAUSE button behavior (.oplink-pause)
		
		o.btnPause.live('click',function(e){
			e.preventDefault();
			$.fn.omniplayer.omniPause(thisObj);
		});

		// ------------------------------------------
		// Set the default STOP button behavior (.oplink-stop)

		o.btnStop.live('click',function(e){
			e.preventDefault();
			$.fn.omniplayer.omniStop(thisObj);
		});

		// ------------------------------------------
		// Set the default NEXT button behavior (.oplink-play)

		o.btnNext.live('click',function(e){
			e.preventDefault();
			$.fn.omniplayer.omniNext(thisObj);
		});

		// ------------------------------------------
		// Set the default PREVIOUS button behavior (.oplink-prev)

		o.btnPrev.live('click',function(e){
			e.preventDefault();
			$.fn.omniplayer.omniPrev(thisObj);
		});

		// ------------------------------------------
		// Set the default PLAY from API button behavior (.omni-play)

		o.btnPlayApiDiv.live('click',function(e){
			e.preventDefault();
			$.fn.omniplayer.omniPlayAPI($(this),thisObj,true);
		});

		// ------------------------------------------
		// Set the default PLAY from API button behavior (.omni-play)

		o.btnPlayApiHref.live('click',function(e){
			e.preventDefault();
			$.fn.omniplayer.omniPlayAPI($(this),thisObj,false);
		});
		
		
		// ------------------------------------------
		// Get to work
		return this.each(function() {
			
			// ------------------------------------------
			// Instantiate the object we'll use to pass to the private functions
			var obj = $(this);  
			
			// ------------------------------------------
			// Set the parameters for the paging filter
			initializeOmniplayer(obj);
			
		});  
		
	};
	
	
	// ------------------------------------------------------------------------------------------
	// Expose defaults to allow users to define them independently
	
	$.fn.omniplayer.defaults = {
		playByDefault: 			false,
		owner: 					'Hear It Local',
		siteDomain: 			'',
		filePath: 				'',
		apiDomain: 				'hearitlocal.com',
		promoterID: 			1,
		id: 					1,
		playerType: 			'',
		urlApi: 				'http://hearitlocal.com/api/',
		url: 					'http://hearitlocal.com/api/promoterMedia&promoter=',
		urlArtist: 				'http://hearitlocal.com/api/artist&id=',
		urlPlaylist: 			'http://hearitlocal.com/api/promoterMediaPlus&promoter=',
		songUrl: 				'http://hearitlocal.com/api/getSong&song=',
		smSwfUrl: 				'swf/',
		smUseFlashBlock: 		false,
		smDebugMode: 			false,
		smDefaultVolume: 		40,
		parentName: 			'omniplayer',
		maxTracksInHistory: 	5,
		maxArtistName: 			30,
		maxSongName: 			200,
		scrollAnimationTime: 	15000,
		btnPlay: 				'',
		btnPause: 				'',
		btnStop: 				'',
		btnNext: 				'',
		btnPrev: 				'',
		btnPlayApiDiv: 			'',
		btnPlayApiHref: 		'',
		btnVolumeSlider: 		'',
		messageDiv: 			'',
		artistImageSize: 		'',
		volMinX: 				370,
		volMaxX: 				417,
		onSongChange: 			function(){},
		onPlayerLoad: 			function(){}
	};


	// ------------------------------------------------------------------------------------------
	// Initialize Omniplayer for the first time
	
	function initializeOmniplayer(obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		o = obj[0][0];
	
		// ------------------------------------------
		// What is the API url that we'll be retrieving the song data from?
		
		switch(o.playerType) {
			case 'promoter':
			  	o.url = o.urlApi + 'promoterMediaPlus&promoter=' + o.id;
			  	break;
			case 'region':
				o.url = o.urlApi + 'regionMedia&id=' + o.id;
			  	break;
			case 'venue':
			  	o.url = o.urlApi + 'venueMedia&id=' + o.id;
			  	break;
			case 'artist':
			  	o.url = o.urlApi + 'artistMediaPlus&id=' + o.id;
			  	break;
			default:
			  	o.url = o.url + o.promoterID;
		}
		var url = o.url;
		//console.log(url);
		
		// ------------------------------------------
		// Initialize SoundManager
	
		soundManager.url = o.smSwfUrl;
		soundManager.useFlashBlock = o.smUseFlashBlock;
		soundManager.debugMode = o.smDebugMode;
		soundManager.defaultOptions.volume = o.smDefaultVolume;

		// ------------------------------------------
		// Launch SoundManager
		soundManager.onready(function() {

			// ------------------------------------------
			// Retrieve music data
			
			$.get(
				url,
				function(data){
				
					// ***REMINDER***: Remember to add the cacheHasher stuff back in
					rows = data.rows;

					// ------------------------------------------
					// If no data is returned, stop processing
					if ( data.rows.length == 0 ) {
						$('.op-artist-name').html('No Songs Available');
						$('.op-song-title').html(o.owner);
						return;
					}
		
					// ------------------------------------------
					// Playlist and song information will be contained within the OmniPlayer DOM array as follows:
					// 
					// 	$('#omniplayer')[0]['song'] ==> An object containing the song being played
					// 	$('#omniplayer')[0]['playlist'] ==> An array of the playlist
					// 	$('#omniplayer')[0]['playlistDefault'] = data.rows;
					// 	$('#omniplayer')[0]['usingDefault'] ==> A flag indicating whether the default playlist is being used
					// 	$('#omniplayer')[0]['defaultPosition'] ==> The song index position of the default playlist
					// 	$('#omniplayer')[0]['history'] ==> An array of the history
					// 	$('#omniplayer')[0]['playlistHistory'] ==> An array of the playlist history (defined in omniplayerPlaylist.js)
					// 	$('#omniplayer')[0]['position'] ==> Position in the playlist array
					// 	$('#omniplayer')[0]['volume'] ==> Song volume (0-100)
					//
					// The Playlist array will be formatted as follows (for now)
					// 				
					// 	playlist[i]['artistID'] 			==> artistID
					// 	playlist[i]['artistName'] 			==> artistName
					// 	playlist[i]['artistThumb'] 			==> artistThumb
					// 	playlist[i]['artistSmallThumb'] 	==> artistSmallThumb
					// 	playlist[i]['artistImage'] 			==> artistImage
					// 	playlist[i]['songURL'] 				==> songURL
					// 	playlist[i]['songTitle'] 			==> songTitle
					// 	playlist[i]['songID'] 				==> songID
					//
				
					// ------------------------------------------
					// Assign music data to a position in the OmniPlayer DOM array
					obj[0]['playlist'] = playlist = data.rows.songData;
					obj[0]['playlistDefault'] = data.rows.songData;
					obj[0]['usingDefault'] = true;
					obj[0]['history'] = new Array();
					obj[0]['playlistHistory'] = new Array();
					obj[0]['position'] = 0;
					obj[0]['volume'] = o.smDefaultVolume;
				
					// ------------------------------------------
					// The following code is used for testing the API feed
					// for (var i in playlist) {
					// 	songTitle = playlist[i]['songTitle'];
					// 	artistName = playlist[i]['artistName'];
					// 	songURL = playlist[i]['songURL'];
					// 	alert( songTitle + ' by ' + artistName + ' (' + songURL + ')\\n');
					// }

					// ------------------------------------------
					// SM2 has loaded - now you can create and play sounds!
					// We'll initially start with the first record in the playlist
		
					obj[0]['song'] = soundManager.createSound({
						id: 'aSound',
						url: 'http://hearitlocal.com' + playlist[0]['songURL']
						//url: 'http://hearitlocal.com/accelsite/media/mediaFile563.mp3'
						// onload: [ event handler function object ],
						// other options here..
					});
					song = obj[0]['song'];
					addToHistory(playlist[0],obj);
										
					// ------------------------------------------
					// Play the first song
					
					song.play({
					  	onfinish: function() {
					    	//playSong(1,obj);
							$.fn.omniplayer.playSong(1,obj);
						},
						whileplaying: function() {
							
							// ------------------------------------------
							// Pause the first song if the playByDefault flag is set to false
							if ( !o.playByDefault ) $.fn.omniplayer.omniPause(obj);	
							
							// ------------------------------------------
							// Show song loading info
							$('#duration').html(song.position + ' ' + song.durationEstimate + ' ' + song.duration);
						}
					});
					
					// ------------------------------------------
					// Set the volume to zero if playByDefault is false;
					if ( !o.playByDefault ) song.setVolume(0);
					
					// ------------------------------------------
					// Display the artist's meta data
					showArtistInfo(0,obj);
					
					// ------------------------------------------
					// Execute the onSongChange() callback function
					song = obj[0]['playlist'][0];
					if ( typeof o.onSongChange=='function' && o.playByDefault ) o.onSongChange.call(this,song);
					
					// ------------------------------------------
					// Execute the onSongChange() callback function
					if ( typeof o.onPlayerLoad=='function' ) o.onPlayerLoad.call(this,song);
				
				},
				'jsonp'
			);
			
		});
		
		return;
		
	}
	
	
	// ------------------------------------------------------------------------------------------
	// Manage player history
	
	function addToHistory(song,obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		o = obj[0][0];

		// ------------------------------------------
		// Check for a long song title
		
		if ( song.songTitle.length > 30 ) {
			songTitle = song.songTitle.substring(0,26) + '...';
		} else {
			songTitle = song.songTitle;
		}

		// ------------------------------------------
		// Modify the history playlist
		
		var history = new Array();
		history = obj[0]['history'];
		//( history instanceof Array ) ? alert('is array') : alert('not array');

		// ------------------------------------------
		// Now that we have the history array, make sure that a duplicate isn't being added to the viewable list.
		maxTracks = o.maxTracksInHistory;

		// ------------------------------------------
		// Start looping with item 0 if there are less than maxTracks number of items in history.
		
		if (history.length > 0 ) {
			startTrack = (history.length < maxTracks) ? 0 : history.length - maxTracks;
			//alert(startTrack + ':' + (history.length));
			for (i=startTrack;i<history.length;i++) {
				if ( song.songID == history[i].songID ) return;
			}
		}

		// ------------------------------------------
		// Append the song to the history array.
		history.push(song);

		// ------------------------------------------
		// Redefine the playlist and position
		obj[0]['history'] = history;

		// ------------------------------------------
		// Add the new track to the history list	
		
		historyItem = "<div id='" + song.songID + "' class='op-history-item omni-trigger-div' style='display:none;'>";
		historyItem += "	<div class='op-history-image'><img src='" + song.artistThumb + "' height='35' width='35' alt='" + song.songTitle + " by " + song.artistName + "' /></div>";
		historyItem += "	<div class='op-history-artist-info'>";
		historyItem += "		<p class='op-history-track'>" + songTitle+ "</p>";
		historyItem += "		<p class='op-history-name'>" + song.artistName+ "</p>";
		historyItem += "	</div>";
		historyItem += "</div>";
		$('#op-history-container').prepend(historyItem).find('.op-history-item:hidden').fadeIn('slow');

		// ------------------------------------------
		// Make sure not to exceed the upper limit of tracks that appear in history set above with maxTracks
		
		totalTracks = $("#op-history-container").children('.op-history-item').length;
		//alert(maxTracks + ':' + totalTracks);
		if ( totalTracks > maxTracks ) {
			$("#op-history-container").children('.op-history-item:last').fadeOut().remove();
		}

		// Add the tracks to a list. Use this loop to test the history array.;
		// var tracks = '';
		// for (var i in history) {
		// 	tracks = i + '. ' +history[i].artistName + '\n' + tracks;
		// }
		// alert(tracks);
		
		return;

	}	
	
	
	// ------------------------------------------------------------------------------------------
	// Display the info for the Artist whose song is currently playing
	
	function showArtistInfo(playlistID,obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		o = obj[0][0];

		// ------------------------------------------
		// Retrieve the playlist from the #omniplayer DOM element
		playlist = obj[0]['playlist'];

		// ------------------------------------------
		// Get artist info for the flyout
		getArtistInfo(playlist[playlistID]['artistID'],obj);

		// ------------------------------------------
		// Retrieve the song from the playlist
		songData = playlist[playlistID];

		// ------------------------------------------
		// Place the current artist's info into DIVs.
		// But, first, check to see if the artist's thumbnail size has been specified.
		
		var artistThumb = songData['artistThumb'];
		if ( o.artistImageSize != '' && (!isNaN (o.artistImageSize-0)) ) {
			artistThumb = artistThumb.replace('|90|','|'+o.artistImageSize+'|');
		}
		artistName = (songData['artistName'].length>o.maxArtistName) ? songData['artistName'].substr(0,o.maxArtistName-3)+'&#8230;' : songData['artistName'];
		$('.op-artist-thumb').html('<img src=\"'+artistThumb+'\">');
		$('.op-artist-name').html('<a class=\"artist-omni-trigger\" href=\"'+songData['artistID']+'\">'+artistName+'</a>');
		$('.op-song-title').html(songData['songTitle']);
		
		// ------------------------------------------
		// Display the song rating options
		songRate(songData['songID'],obj);
		//$('a.follow-artist').html($('#artist_like').html().replace('{{id}}', songData['artistID']));
		
		// ------------------------------------------
		// Display the next artist up
		showNextArtistInfo(playlistID,obj);
		
		// ------------------------------------------
		// Handle long artist names and song titles
		//handleLongNames(songData,obj);

		return;

	}
	
	
	// ------------------------------------------------------------------------------------------
	// Display the info for the "Next Up" Artist
	
	function showNextArtistInfo(playlistID,obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		o = obj[0][0];

		// ------------------------------------------
		// Retrieve the playlist from the #omniplayer DOM element
		playlist = obj[0]['playlist'];

		// ------------------------------------------
		// Set a limit to the amount of songs the playlist will loop through.
		songCount = playlist.length;

		// ------------------------------------------
		// Set the playlistID for the next song
		playlistID++;
		if ( playlistID > songCount-1 ) playlistID = 0;

		// ------------------------------------------
		// Retrieve the song from the playlist
		songData = playlist[playlistID];

		// ------------------------------------------
		// Place the info into DIVs
		artistName = (songData['artistName'].length>o.maxArtistName) ? songData['artistName'].substr(0,o.maxArtistName-3)+'&#8230;' : songData['artistName'];
		$('.op-next-artist-name').html('<div class="nametext">'+artistName+'</div>');
		$('.op-next-artist-thumb').html('<img src=\"'+songData['artistSmallThumb']+'\">');

		return;

	}


	// ------------------------------------------------------------------------------------------
	// Show artist flyout info

	function getArtistInfo(artistID,obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		o = obj[0][0];
		
		// ------------------------------------------
		// What's the API url needed to retrieve the artist's info?
		var urlArtist = o.urlArtist + artistID;

		// ------------------------------------------
		// Cancel any pre-existing AJAX call
		if ( obj[0]['ajaxArtistInfo'] != null ) obj[0]['ajaxArtistInfo'].abort();

		// ------------------------------------------
		// Get an individual artist's info from the api
		
		obj[0]['ajaxArtistInfo'] = $.get(
			urlArtist,
			function(data){
				artist = data.rows[0];
				artistImage = "<img src='" + artist.thumbSrc + "' height='210' width='210' alt='' />";
				songs = ''; 
				performTitle = "No Upcoming Shows";
				performDate = showTime = venueName = image = "";

				// ------------------------------------------
				// Build this condition if an artist doesn't have any upcoming shows.
				
				if ( artist.nextShow != null ) {
					performTitle = artist.nextShow.performTitle;
					performID = artist.nextShow.id;
					//performDateObj = new Date(artist.nextShow.PerformDate); <== This works for every browser except for IE7,8
					performDateObj = buildDateObjectForIE(artist.nextShow.PerformDate);
					performDate = dateFormat(performDateObj,"ddd, mmm dS, yyyy");
					showTime = artist.nextShow.BeginTime + ' to ' + artist.nextShow.EndTime;
					venueName = '@ ' + artist.nextShow.venueName;
					performTitle = "<a class='' href='" + performID + "'>" + performTitle + "</a>";
					$('#artist-info-container .featured-artist-show').css('display','block');
				} else {
					$('#artist-info-container .featured-artist-show').css('display','none');
				}
				
				// ------------------------------------------
				// Build a condition for artists that don't have music available
				
				var playAll = "";
				if ( artist.songs.length > 0 ) {
					for ( i=0; i<artist.songs.length; i++ ) {
						songs += "<a title='Click to play track " + i + "' rel='" + artist.songs[i].title + "' class='omni-trigger-href btn-omni-play' href='" + artist.songs[i].id + "'>" + artist.songs[i].title + "</a>\n";
					}
					playAll = "<a class='playlist-artist btn-omni-play omni-bold' href='" + artist.id + "'>PLAY ALL TRACKS</a>";
				}	

				// ------------------------------------------
				// Place artist info
				
				$('#artist-info-container .show-name').html("<a class='link-artist-detail' href='" + artist.id + "'>" + maxName(artist.name,o.maxArtistName) + "</a>");
				$('#artist-info-container .artist-thumb-drop').html(artistImage);
				$('#artist-info-container .featured-artist-show .next-show-title').html(performTitle);
				$('#artist-info-container .date').html(performDate);
				$('#artist-info-container .time').html(showTime);
				$('#artist-info-container .featured-venue').html(venueName);
				$('#artist-info-container .fan-count').html(artist.fanCount);
				$('#artist-info-container .featured-artist-tracks').html(songs);
				$('#artist-info-container .play-all-tracks').html(playAll);
				$('#artist-info-container .share-this .featured-artist-id').html(artist.id);
				$('#artist-info-container .share-this .name-share').html(artist.name);
				$('#artist-info-container .share-this .url-share').html(escape("http://"+o.siteDomain+"/as_bay-vibes-artists&detailID=" + artist.id));
				$('#artist-info-container .fav-link-holder iframe').attr('src','http://hearitlocal.com/?ado=genericSnippet&ajax=true&module=generic&snippet=hearitBayVibesFav&type=artist&id='+artist.id);
				
				// ------------------------------------------
				// Reset the AJAX artistInfo placeholder
				obj[0]['ajaxArtistInfo'] = null;

			},
			'jsonp'
			
		);
		
		return;
		
	}
	

	// ------------------------------------------------------------------------------------------
	// Long artist and song names are problematic for presentation. This function provides a clean-up option.
	
	function handleLongNames(arrSongData,obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		o = obj[0][0];

		// ------------------------------------------
		// Handle a long artist name
		
		maxArtistName = o.maxArtistName; // use 30 characters (less for testing)
		lenArtistName = songData['artistName'].length;
		if ( lenArtistName > maxArtistName ) {

			// ------------------------------------------
			// Slide the radio title out
			$(".channel-name").animate({marginLeft:'-100px'},'slow');
			$(".op-artist-name").animate({marginLeft:'-100px'},'slow');	

		} else {

			// ------------------------------------------
			// Slide the radio title in if it's out
			$(".channel-name").animate({marginLeft:'0px'},'slow');
			$(".op-artist-name").animate({marginLeft:'0px'},'slow');

		}

		// ------------------------------------------
		// Handle a long song title
		var w1 = $(".op-song-title").width();
		var w2 = $(".artist-name-title").width();

		// ------------------------------------------
		// Scroll the song title
		if ( w1 > w2 ) scrollText($(".op-song-title"),w1,w2,w1/(w1+w2),obj);

		// ------------------------------------------
		// Handle a long 'Next Up' artist name
		var w1 = $('.op-next-artist-name .nametext').width();
		var w2 = 90;

		// ------------------------------------------
		// Scroll the 'Next Up' artist name
		if ( w1 > w2 ) scrollText($('.op-next-artist-name .nametext'),w1,w2,w1/(w1+w2),obj);
		
		return;

	}
	

	// ------------------------------------------------------------------------------------------
	// Long artist and song names are problematic for presentation. This function provides a clean-up option.
	
	function scrollText(objScroll,wItem,wContainer,durationRatio,obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		o = obj[0][0];

		// ------------------------------------------
		// How long will it take for the animated artist name and song title text to scroll?
		animationTime = o.scrollAnimationTime; //<== This is the time it takes to go from the rightmost left margin to the leftmost left margin

		// ------------------------------------------
		// Since this is a recursive function, check to see if the scrolling object has changed width in order to end the looping.
		if ( objScroll.width() <= wContainer ) { return true; }

		// ------------------------------------------
		// Animate the horizontally scrolling text
		
		objScroll.animate(
			{marginLeft:'-'+wItem},
			durationRatio*animationTime,
			'linear',
			function(){
				obj.css('margin-left',wContainer);
				scrollText(obj,wItem,wContainer,1,obj);
		});
		
		return;
		
	}
	
	
	// ------------------------------------------------------------------------------------------
	// Play songs from a playlist in order
	
	function songRate(songID,obj){

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		o = obj[0][0];
		
		// ------------------------------------------
		// Place the like buttons in the player 
		var t = Math.random()*10;
		var anchorDislike = '';
		//var anchorDislike = '<a href=\"\" class="media-dislike pointer mark-' + songID + '"><img src="http://accelhost.bayvibes.com/accelsite/themes/temp999/images/dislike.png" class=\"\"></a>';
		var imgCover = '<img src="http://hearitlocal.com/sf/accelFile/imagemgr|imageResize.login|32|thumbup_off.png?t=' + t + '" class="logged-out-thumb-cover" />';
		// var anchorDislike = "<a href='' class='media-dislike pointer mark-" + songID + "'><img src='http://accelhost.bayvibes.com/accelsite/themes/temp999/images/dislike.png' class='' /></a>";
		// var imgCover = "<img src='http://hearitlocal.com/sf/accelFile/imagemgr|imageResize.login|32|thumbup_off.png?t=" + t + "' class='logged-out-thumb-cover' />";
		
		$('.op-song-rate')
			.html($('<iframe>')
				.attr({
					'frameborder'		: 0,
					'border'			: 0,
					'marginHeight'		: 0,
					'marginWidth'		: 0,
					'allowTransparency' : 'true',
					'backgroundColor'	: 'transparent',
					'width' 			: 25,
					'height'			: 25,
					'src'				: 'http://hearitlocal.com/?ado=genericSnippet&ajax=true&module=media&snippet=hearitBayVibesMediaLike&imgSize=25&id=' + songID
				})
			);
			
		// NOTE: chaining these .append() commands to the attr() command causes a error to be logged in IE
		$('.op-song-rate').append(anchorDislike);
		$('.op-song-rate').append(imgCover)
	}
	
	
	// ------------------------------------------------------------------------------------------
	// Play songs from a playlist in order

	//function playSong(playlistID,obj) {
	$.fn.omniplayer.playSong = function(playlistID,obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		o = obj[0][0];
		
		// ------------------------------------------
		// Retrieve the playlist from the #omniplayer DOM element
		playlist = obj[0]['playlist'];

		// ------------------------------------------
		// Set a limit to the amount of songs the playlist will loop through.
		songCount = playlist.length;

		// ------------------------------------------
		// Take care of playlistID values that are outside of the size of the playlist
		if ( playlistID > songCount-1 ) playlistID = 0;
		if ( playlistID < 0 ) playlistID = songCount-1;

		// ------------------------------------------
		// Retrieve the song from the playlist
		songData = playlist[playlistID];

		// ------------------------------------------
		// Destroy the previous song
		obj[0]['song'].destruct();

		// ------------------------------------------
		// Set the current song in the playlist
		obj[0]['position'] = playlistID;

		// ------------------------------------------
		// Create the song
		obj[0]['song'] = soundManager.createSound({
			id: 'aSound',
			url: 'http://hearitlocal.com' + songData['songURL'],
			volume: obj[0]['volume']
			// onload: [ event handler function object ],
			// other options here..
		});

		// ------------------------------------------
		// Add the song to history
		addToHistory(songData,obj);

		// ------------------------------------------
		// Play the song
		song = obj[0]['song'];
		song.play({
		  	onfinish: function() {
				nextPlaylistID = playlistID + 1;
				//alert('song finished - nextPlaylistID=' + nextPlaylistID);
				if ( nextPlaylistID > songCount-1 ) {
					//alert('second song');
		    		//playSong(0,obj);
					$.fn.omniplayer.playSong(0,obj);
				} else {
					//alert('next song');
					//playSong(nextPlaylistID,obj);
					$.fn.omniplayer.playSong(nextPlaylistID,obj);
				}
			},
			whileplaying: function() {
				o.messageDiv.html('Song started...').fadeOut(2000);
				//$('#omniplayer .op-song-loading').html('Song started...').fadeOut(2000);
				
				// ------------------------------------------
				// Show song loading info
				$('#duration').html(song.position + ' ' + song.durationEstimate + ' ' + song.duration);
			}
		});	

		// ------------------------------------------
		// Show the current and next artist's info
		showArtistInfo(playlistID,obj);

		// ------------------------------------------
		// Show song loading text
		o.messageDiv.html('Loading Song...');
			
		// ------------------------------------------
		// Execute the onSongChange() callback function
		song = obj[0]['playlist'][playlistID];
		if ( typeof o.onSongChange=='function' ) o.onSongChange.call(this);
		
		//$('#omniplayer .op-song-loading').html('Loading Song...');
		// $('.op-artist-name').html(songData['artistName']);
		// 		$('.op-song-title').html(songData['songTitle']);

		return;

	};
	
	// ------------------------------------------------------------------------------------------
	// Play a single song from history, or one that has been specifically requested.

	$.fn.omniplayer.getSong = function(songID,obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		o = obj[0][0];

		// ------------------------------------------
		// What's the API url for retrieving data for a single song
		songURL = o.songUrl + songID;
		//console.log(songURL);
		
		// ------------------------------------------
		// Cancel any pre-existing AJAX call
		if ( obj[0]['ajaxGetSong'] != null ) obj[0]['ajaxGetSong'].abort();

		// ------------------------------------------
		// Retrieve the data for the song
		
		obj[0]['ajaxGetSong'] = $.get(
			songURL,
			function(data){

				// ------------------------------------------
				// Assign song data to placeholders
				
				var userSong = new Array();
				songData = data.rows;

				artistID 			= userSong['artistID'] 			= songData.artistID;
				artistName 			= userSong['artistName'] 		= songData.artistName;
				artistThumb 		= userSong['artistThumb'] 		= songData.artistThumb;
				artistSmallThumb 	= userSong['artistSmallThumb'] 	= songData.artistSmallThumb;
				artistImage 		= userSong['artistImage'] 		= songData.artistImage;
				songURL 			= userSong['songURL'] 			= songData.songURL;
				songTitle 			= userSong['songTitle'] 		= songData.songTitle;
				songID 				= userSong['songID'] 			= songData.songID;


				// Destroy the previous song
				//$('#omniplayer')[0]['song'].destruct();
				// -- Moved to the 'click' event
				
				// ------------------------------------------
				// Build a 'song' object
				
				song = soundManager.createSound({
					id: 'aSound',
					url: 'http://hearitlocal.com' + songURL
				});
				
				// ------------------------------------------
				// Assign the new song to the OmniPlayer DOM
				obj[0]['song'] = song;

			
				// ------------------------------------------
				// Modify the playlist
				
				playlist = obj[0]['playlist'];
				position = obj[0]['position'];
				playlist.splice(position+1, 0, userSong);

				// ------------------------------------------
				// Redefine the playlist and position
				
				obj[0]['playlist'] = playlist;
				obj[0]['position'] = position+1;

				// ------------------------------------------
				// Place the current artist's info into DIVs
				// But, first, check to see if the artist's thumbnail size has been specified.

				if ( o.artistImageSize != '' && (!isNaN (o.artistImageSize-0)) ) {
					artistThumb = artistThumb.replace('|90|','|'+o.artistImageSize+'|');
				}
				
				$('.op-artist-name').html('<a class=\"artist-omni-trigger\" href=\"'+artistID+'\">'+artistName+'</a>');
				$('.op-artist-thumb').html('<img src=\"'+artistThumb+'\">');
				$('.op-song-title').html(songTitle);
				getArtistInfo(artistID,obj);

				// ------------------------------------------
				// Add the song to history
				songRate(songID,obj);
				//$('#omniplayer .op-song-loading').html('Loading Song...');

				// ------------------------------------------
				// Add the song to history
				addToHistory(songData,obj);

				// ------------------------------------------
				// Play the song
				song.setVolume(obj[0]['volume']);
				song.play({
				  	onfinish: function() {

						// ------------------------------------------
						// Retrieve the playlist from the #omniplayer DOM element
						playlist = obj[0]['playlist'];

						// ------------------------------------------
						// Set a limit to the amount of songs the playlist will loop through.
						songCount = playlist.length;

						// ------------------------------------------
						// Set the playlistID for the next song
						playlistID = obj[0]['position'];
						playlistID++;
						if ( playlistID > songCount-1 ) playlistID = 0;

						// ------------------------------------------
						// Play the next song
				    	//playSong(playlistID,obj);
						$.fn.omniplayer.playSong(playlistID,obj);

					},
					whileplaying: function() {
						o.messageDiv.html('Song started...').fadeOut(2000);
						$('#duration').html(song.position + ' ' + song.durationEstimate + ' ' + song.duration);
					}
				});

				// ------------------------------------------
				// Handle long artist names and song titles
				//handleLongNames(userSong);
				
				// ------------------------------------------
				// Set the AJAX placeholder to null
				obj[0]['ajaxGetSong'] = null;
				
				// ------------------------------------------
				// Execute the onSongChange() callback function
				song = songData;
				if ( typeof o.onSongChange=='function' ) o.onSongChange.call(this,song);

			},
			'jsonp'
		);
		return;

	};
	

	// ------------------------------------------------------------------------------------------
	// Reset PLAY to PAUSE
	
	function playPauseReset(obj,btnToShow) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		var o = obj[0][0];
		
		// ------------------------------------------
		// Reset buttons
		if ( btnToShow == 'pause' ) {
			if ( o.btnPlay.is(':visible') ) {
				o.btnPause.fadeIn();
				o.btnPlay.hide();
			}
		} else {
			if ( o.btnPause.is(':visible') ) {
				o.btnPause.hide();
				o.btnPlay.fadeIn();
			}
		}
		return;
		
	}

	// ------------------------------------------------------------------------------------------
	// Global PLAY button behavior
	// @param btnToShow: 	Flag to turn on the play button or turn on the pause button. 'play'|'pause'
	
	$.fn.omniplayer.omniPlay = function(obj,btnToShow) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		var o = obj[0][0];
		
		// ------------------------------------------
		// Play the song
		obj[0]['song'].play();
		obj[0]['song'].setVolume(40);
		var song = obj[0]['playlist'][obj[0]['position']];
		
		// ------------------------------------------
		// Reset buttons
		playPauseReset(obj,btnToShow);
		
		// ------------------------------------------
		// Turn on the playByDefault flag
		o.playByDefault = true;		
		
		// ------------------------------------------
		// Execute the onSongChange() callback function
		if ( typeof o.onSongChange=='function' ) o.onSongChange.call(this,song);
		
		return;
	};
	
	
	// ------------------------------------------------------------------------------------------
	// Global PAUSE button behavior

	$.fn.omniplayer.omniPause = function(obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		var o = obj[0][0];

		// ------------------------------------------
		// Play the song
		obj[0]['song'].pause();

		// ------------------------------------------
		// Reset buttons
		playPauseReset(obj,'play');
		
		return;
	};


	// ------------------------------------------------------------------------------------------
	// Global STOP button behavior

	$.fn.omniplayer.omniStop = function(obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		var o = obj[0][0];

		// ------------------------------------------
		// Play the song
		obj[0]['song'].stop();

		// ------------------------------------------
		// Reset buttons
		playPauseReset(obj,'play');
		return;
	};


	// ------------------------------------------------------------------------------------------
	// Global NEXT button behavior

	$.fn.omniplayer.omniNext = function(obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		var o = obj[0][0];

		// ------------------------------------------
		// Reset buttons
		playPauseReset(obj,'pause');

		// ------------------------------------------
		// Play the NEXT song
		$.fn.omniplayer.playSong(obj[0]['position']+1,obj);

		// ------------------------------------------
		// Show 'Retrieving Song...' Message
		obj.find('.op-song-loading').html('Retrieving Song...').show();
		return;
	};


	// ------------------------------------------------------------------------------------------
	// Global PREV button behavior

	$.fn.omniplayer.omniPrev = function(obj) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		var o = obj[0][0];

		// ------------------------------------------
		// Reset buttons
		playPauseReset(obj,'pause');

		// ------------------------------------------
		// Play the PREVIOUS song
		$.fn.omniplayer.playSong(obj[0]['position']-1,obj);

		// ------------------------------------------
		// Show 'Retrieving Song...' Message
		obj.find('.op-song-loading').html('Retrieving Song...').show();
		return;
	};

	// ------------------------------------------------------------------------------------------
	// Retrieve a single song from the API
	// omniPlayAPI
	// @param useDivID: 	This paramater indicates whether the ID from a DIV or an HREF from an 
	//						anchor contains the songID value. true|false 
	//
	//						true: use the DIV's ID
	//						false: use the Anchor's HREF attribute
	//

	$.fn.omniplayer.omniPlayAPI = function(objLink,obj,useDivID) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		var o = obj[0][0];
		
		// ------------------------------------------
		// Reset buttons
		playPauseReset(obj,'pause');
		
		// ------------------------------------------
		// Destroy the Previously played song
		obj[0]['song'].destruct();
		
		// ------------------------------------------
		// Show 'Retrieving Song...' Message
		obj.find('.op-song-loading').html('Retrieving Song...').show();
		
		// ------------------------------------------
		// Retrieve the song ID from the link and play it
		
		if ( useDivID ) {
			songID = objLink.attr('id');
		} else {
			songID = objLink.attr('href');
		}
		
		// ------------------------------------------
		// Get the song from the API and play it
		$.fn.omniplayer.getSong(songID,obj);

		return;
	};
	

	// ------------------------------------------------------------------------------------------
	// Increment volume up
	
	$.fn.omniplayer.countUp = function(action){
		var song = $('#omniplayer')[0]['song'];
		var volume = $('#omniplayer')[0]['volume'];
		if ( typeof vUp === 'undefined' ) vUp = '';

		if ( action == 'start' && volume < 100 ) { 

			if ( volume < 100 ) volume = volume + 5;
			if ( volume > 100 ) volume = 100;
			$('#omniplayer')[0]['volume'] = volume;
			song.setVolume(volume);

			vUp = setTimeout('$.fn.omniplayer.countUp(\"start\")',50);
		} else {
			clearTimeout(vUp);
		}
	};
	
	
	// ------------------------------------------------------------------------------------------
	// Increment volume down
	
	$.fn.omniplayer.countDown = function(action){
		var song = $('#omniplayer')[0]['song'];
		var volume = $('#omniplayer')[0]['volume'];
		if (typeof vDown === 'undefined') vDown = '';

		if ( action == 'start' && volume > 0 ) { 

			if ( volume >= 0 ) volume = volume - 5;
			if ( volume < 0 ) volume = 0;
			$('#omniplayer')[0]['volume'] = volume;
			song.setVolume(volume);

			vDown = setTimeout('$.fn.omniplayer.countDown(\"start\")',50);
		} else {
			clearTimeout(vDown);
		}
	};
	
	
	
	// ------------------------------------------------------------------------------------------
	// Change volume based on volume slider
	
	$.fn.omniplayer.volume = function(minX,maxX,xPos){
		var range = maxX - minX;
		var vol = (xPos/range)*100;
		return vol;
	};
	
	
	// ------------------------------------------------------------------------------------------
	// Change playlists (channels)
	// Name: 			getPlaylist(plType,val,plName,obj)
	// Author: 			Maurice Wright
	// Last Modified: 	9/22/2011
	// Description:		For a given promoter, return the appropriate playlist of songs for use with the OmniPlayer
	// @param			plType
	// 					promoter: 		The promoters ID [promoterid] REQUIRED FOR URL (but should be hard-coded into the function)
	// 					default: 		Use the default playlist. The default playlist is for the promoter ... for now
	// 					artist:			The id of an individual artist whose songs will be returned [artistid]
	// 					performance:	The id of an individual performance. All artists associated with this performance will have their songs returned [performanceid]
	// 					upcoming:		A flag to indicate whether to return songs from all artists associated with upcoming events ['true']
	// 					favorites:		Indicates whether the member wants to hear their favorite songs, or songs from their favorite artists ['song'|'artist']
	//								**	Appending :$memberID to the favorites value will return the favorite songs or artists for that member (if they have made their playlist public)
	// 					genre:			A text string that matches exactly one of the three categories an artist is labeled as. ['Rock and Pop','Acoustic','Folk',etc....]
	//					playlist:		This indicates that we're using an existing playlist that is tracked in playlist history. [int representing playlist history array index]
	// @param			val
	// @param 			plName			The name that appears in the channel history
	// @param			obj				The jQuery version of the omniplayer object
	// @param			pause			Pause the first song in the playlist	
	
	$.fn.omniplayer.getPlaylist = function(plType,val,plName,obj,pause) {

		// ------------------------------------------
		// Get the options from the DOM array position 0,0
		o = obj[0][0];

		// ------------------------------------------
		// If no 'plType' or 'val' is passed, fail gracefully.
		
		plType = (typeof plType == 'undefined') ? '' : plType;
		val = (typeof val == 'undefined') ? '' : val;
		plName = (typeof plName == 'undefined' || plName == null) ? '' : plName;
		pause = (typeof pause == 'undefined' || pause == null) ? false : true;

		// ------------------------------------------
		// If the playlist name isn't defined, set it to something. Start with the type.
		
		if ( plName == '' ) {
			if ( plType == 'favorites' || plType == 'genre' ) plName = 'Favorite ' + ucFirst(val);
			if ( plType == 'upcoming' ) plName = plType;
			if ( plType == 'promoter' || plType == 'artist' || plType == 'performance' ) plName = ucFirst(plType) + ' - ' + ucFirst(val);
			if ( plType == 'default' || plType == 'promoter' || plType == 'venue' || plType == 'region' || plType == 'playlist' ) plName = o.owner;
		}

		// ------------------------------------------
		// Build the URL from the playlist type
		
		var qString = o.id + '&' + plType + '=' + val;
		var url = "";
		switch(plType) {
			case 'promoter':
				url = o.urlApi + 'promoterMediaPlus&promoter=' + qString;
				break;
			case 'region':
				url = o.urlApi + 'regionMedia&id=' + qString;
				break;
			case 'venue':
				url = o.urlApi + 'venueMedia&id=' + val;
				break;
			case 'artist':
				url = o.urlApi + 'artistMediaPlus&id=' + qString;
				break;
		}
		
		// ------------------------------------------
		// Was one of the special case URLs created?
		
		if ( url == "" ) {
			
			// ------------------------------------------
			// Use one derived from the player type
			 
			switch(o.playerType) {
				case 'promoter':
				  	url = o.urlApi + 'promoterMediaPlus&promoter=' + qString;
				  	break;
				case 'region':
					url = o.urlApi + 'regionMedia&id=' + qString;
				  	break;
				case 'venue':
				  	url = o.urlApi + 'venueMedia&id=' + qString;
				  	break;
				case 'artist':
				  	url = o.urlApi + 'artistMediaPlus&id=' + qString;
				  	break;
				default:
				  	url = o.urlPlaylist + o.promoterID + '&' + plType + '=' + val;
			}
		}
		
		
		// ------------------------------------------
		// Not finished yet. If we have a playlist type (plType) of 'artist' or 'performance' with a numeric value,
		// go directly to the API that supports individual artists and performances.
		
		if ( plType == 'artist' && !isNaN (val-0) ) 
			url = o.urlApi + 'getArtistSongs&id=' + val;
		if ( plType == 'performance' && !isNaN (val-0) )
			url = o.urlApi + 'getPerformanceSongs&id=' + val;
		
		//console.log(url);
		
		// ------------------------------------------
		// Cancel any pre-existing AJAX call
		if ( obj[0]['ajaxPlaylist'] != null ) obj[0]['ajaxPlaylist'].abort();
		
		// ------------------------------------------
		// Retrieve music data
		
		obj[0]['ajaxPlaylist'] = $.get(
			url,
			function(data){

				rows = data.rows.songData;
				rowCount = data.rows.songCount;
				
				if ( data.results == 0 ) { 
					alert('There are no songs in this playlist');
					return; 
				}

				// ------------------------------------------
				// Playlist and song information will be contained within the OmniPlayer DOM array. See the initializeOmniplayer function for reference.
				//
				// The Playlist History Array
				//
				// playlistHistory['url'] 				==> url
				// playlistHistory['playlist'] 		==> playlist
				// playlistHistory['type'] 			==> type
				// playlistHistory['value'] 			==> value

				// Assign music data to a position in the OmniPlayer DOM array
				// First, save the current track position of the default playlist so that we can return to the next one.
				if ( obj[0]['usingDefault'] ) {
					obj[0]['defaultPosition'] = $('#omniplayer')[0]['position'] + 1;
				}

				// ------------------------------------------
				// We've left the default playlist. This flag tells us so.
				obj[0]['usingDefault'] = false;
				
				// ------------------------------------------
				// Now, add the departing playlist to the playlistHistory array
				
				arrPlaylistHistory = new Array();
				arrPlaylistHistory['url'] = url;
				arrPlaylistHistory['playlist'] = obj[0]['playlist'];
				arrPlaylistHistory['type'] = plType;
				arrPlaylistHistory['value'] = val;
				arrPlaylistHistory['name'] = plName;
				arrPlaylistHistory['image'] = data.rows.playlistImage;
				
				// ------------------------------------------
				// Add the departing playlist to history
				addToPlaylistHistory(arrPlaylistHistory,obj);

				// ------------------------------------------
				// Destroy the previous song
				obj[0]['song'].destruct();

				// ------------------------------------------
				// Grab the new data and build the new playlist
				
				obj[0]['playlist'] = playlist = data.rows.songData;
				obj[0]['position'] = 0;
				obj[0]['playlistType'] = data.rows.playlistType;
				obj[0]['playlistValue'] = data.rows.playlistValue;
			 	obj[0]['playlistImage'] = data.rows.playlistImage;

				// ------------------------------------------
				// Start with the first record in the playlist
				
				obj[0]['song'] = soundManager.createSound({
					id: 'aSound',
					url: 'http://hearitlocal.com' + playlist[0]['songURL']
				});
				song = obj[0]['song'];
				song.setVolume(obj[0]['volume']);

				// ------------------------------------------
				// Add this song to history
				addToHistory(playlist[0],obj);

				// ------------------------------------------
				// Play the song
				
				song.play({
				  	onfinish: function() {
						//alert('song finished');
						$.fn.omniplayer.playSong(1,obj);
					},
					whileplaying: function() {
						
						// ------------------------------------------
						// Pause the first song if the playByDefault flag is set to false
						if ( pause ) {
							$.fn.omniplayer.omniPause(obj);
							pause = false;
						}
						
						$('#duration').html(song.position + ' ' + song.durationEstimate + ' ' + song.duration);
					}
				});
				
				// ------------------------------------------
				// Display the artist's meta data
				showArtistInfo(0,obj);

				// ------------------------------------------
				// Display the artist's meta data
				omniPlaylist();
				
				// ------------------------------------------
				// Set the AJAX playlist placeholder to null
				obj[0]['ajaxPlaylist'] == null;
				
				// ------------------------------------------
				// Execute the onSongChange() callback function
				song = obj[0]['playlist'][0];
				if ( typeof o.onSongChange=='function' ) o.onSongChange.call(this,song);
			},
			'jsonp'
		);

	};
	

	// ------------------------------------------------------------------------------------------
	// Manage channel history
	
	function addToPlaylistHistory(arrPlaylist,obj) {

		// ------------------------------------------
		// Modify the channel history
		var playlistHistory = new Array();
		playlistHistory = obj[0]['playlistHistory'];

		// ------------------------------------------
		// Now that we have the playlist history array, make sure that a duplicate isn't being added to the viewable list.
		maxChannels = 5;

		// ------------------------------------------
		// Start looping with item 0 if there are less than maxChannels number of items in history.
		
		if (playlistHistory.length > 0 ) {
			plStart = (playlistHistory.length < maxChannels) ? 0 : playlistHistory.length - maxChannels;
			for (i=plStart;i<playlistHistory.length;i++) {
				if ( arrPlaylist['url'] == playlistHistory[i]['url'] ) return;
			}
		}

		// ------------------------------------------
		// Append the playlist to the playlistHistory array
		playlistHistory.push(arrPlaylist);

		// ------------------------------------------
		// Add the new channel to the playlist history list
		
		historyItem = "<div class='op-channel-item pointer playlist-" + arrPlaylist['type'] + "' style='display:none;'>";
		historyItem += "	<span class='" + arrPlaylist['value'] + "'></span>";
		historyItem += "	<div class='op-channel-image'><img src='" + arrPlaylist['image'] + "' alt='Playlist - " + arrPlaylist['name'] + "' /></div>";
		historyItem += "	<div class='op-channel-info'>" + arrPlaylist['name'] + "</div>";
		historyItem += "	</div>";
		historyItem += "</div>";
		$('#op-channel-history-container').prepend(historyItem).find('.op-channel-item:hidden').fadeIn('slow');

		// ------------------------------------------
		// Make sure not to exceed the upper limit of playlist items allowed to appear. This is set with maxChannels.
		
		totalChannels = $("#op-channel-history-container").children('.op-channel-item').length;
		if ( totalChannels > maxChannels ) {
			$("#op-channel-history-container").children('.op-channel-item:last').fadeOut().remove();
		}

		// ------------------------------------------
		// Add the playlists to a list. Use this loop to test the history array.;
		var pl = '';
		for (var i in playlistHistory) {
			pl = i + '. ' +playlistHistory[i]['type'] + ':' + playlistHistory[i]['name'] + '\n' + pl;
		}
	}
	
	
	// ------------------------------------------------------------------------------------------
	// Make any string fit the format of uppercase first character, lowercase all others
	
	function ucFirst(str) {
		if ( typeof str == 'string' ) {
			str.toLowerCase();
			firstChar = str.charAt(0);
			newStr = str.replace(firstChar,firstChar.toUpperCase());
			return newStr;
		}
		return str
	}


	// ------------------------------------------------------------------------------------------
	// Make any string fit a certain number of characters

	function maxName(str,len) {
		var newStr = str;
		if ( typeof str == 'string' ) {
			newStr = (str.length > len) ? str.substr(0,o.maxArtistName-3)+'&#8230;' : str;
		}
		return newStr;
	}
	
	
	// ------------------------------------------------------------------------------------------
	// This is a goofy function to handle IE's inability to format a date
	/*
	 * @param {string} dateStringInRange format YYYY-MM-DD, with year in range of 0000-9999, inclusive.
   	 * @return {Date} Date object representing the string.
	 */
	
	function buildDateObjectForIE(dateStringInRange) {
		var isoExp = /^\s*(\d{4})-(\d\d)-(\d\d)\s*$/,
		    date = new Date(NaN), month,
		    parts = isoExp.exec(dateStringInRange);

		if(parts) {
			month = +parts[2];
			date.setFullYear(parts[1], month - 1, parts[3]);
			if(month != date.getMonth() + 1) {
				date.setTime(NaN);
			}
		}
		return date;
	}

})(jQuery);
