var CookieJar = Class.create();

CookieJar.prototype = {
	/**
	 * Author : Lalit Patel
	 */

	appendString: "__CJ_",

	initialize: function(options) {
		this.options = {
			expires: 3600,		// seconds (1 hr)
			path: '',			// cookie path
			domain: '',			// cookie domain
			secure: ''			// secure ?
		};
		Object.extend(this.options, options || {});

		if (this.options.expires != '') {
			var date = new Date();
			date = new Date(date.getTime() + (this.options.expires * 1000));
			this.options.expires = '; expires=' + date.toGMTString();
		}
		if (this.options.path != '') {
			this.options.path = '; path=' + escape(this.options.path);
		}
		if (this.options.domain != '') {
			this.options.domain = '; domain=' + escape(this.options.domain);
		}
		if (this.options.secure == 'secure') {
			this.options.secure = '; secure';
		} else {
			this.options.secure = '';
		}
	},

	put: function(name, value) {
		name = this.appendString + name;
		cookie = this.options;
		var type = typeof value;
		switch(type) {
		  case 'undefined':
		  case 'function' :
		  case 'unknown'  : return false;
		  case 'boolean'  : 
		  case 'string'   : 
		  case 'number'   : value = String(value.toString());
		}
		var cookie_str = name + "=" + escape(Object.toJSON(value));
		try {
			document.cookie = cookie_str + cookie.expires + cookie.path + cookie.domain + cookie.secure;
		} catch (e) {
			return false;
		}
		return true;
	},

	remove: function(name) {
		name = this.appendString + name;
		cookie = this.options;
		try {
			var date = new Date();
			date.setTime(date.getTime() - (3600 * 1000));
			var expires = '; expires=' + date.toGMTString();
			document.cookie = name + "=" + expires + cookie.path + cookie.domain + cookie.secure;
		} catch (e) {
			return false;
		}
		return true;
	},

	get: function(name) {
		name = this.appendString + name;
		var cookies = document.cookie.match(name + '=(.*?)(;|$)');
		if (cookies) {
			return (unescape(cookies[1])).evalJSON();
		} else {
			return null;
		}
	}
};

// ***********************************************

function togglePlaylistFavorite(playlistId,link) {
	link.getElementsByTagName('img')[0].src = '/images/icons/spinner.gif';

	new Ajax.Request('user.php',{
		parameters: {action: 'toggle_playlist_favorite', id: playlistId},
		onSuccess: _toggleFavorite.bind(link),
		onFailure: _toggleFavoriteFailure.bind(link)
	});
}

function _toggleFavorite(t) {
	if (t.responseText == '1') {
		src = '/images/icons/star.gif';
	}
	else {
		src = '/images/icons/star_fade.gif';
	}
	this.getElementsByTagName('img')[0].src = src;
}
function _toggleFavoriteFailure(t) {
	alert('Error toggling favorite...');
}

Effect.PlayerMove = Class.create(Effect.Base, {
  initialize: function(element) {
    this.element = $(element);
    if (!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
			bottom: 0
    }, arguments[1] || { });
    this.start(options);
  },
  setup: function() {
    this.originalBottom  = parseFloat(this.element.getStyle('bottom')  || '0');
  },
  update: function(position) {
		newBottom = (this.originalBottom + position*(this.options.bottom-this.originalBottom)).round();
    this.element.setStyle({
			bottom: newBottom + 'px'
    });
  }
});

/***** CTrack *****/

var CTrack = Class.create();

CTrack.prototype = {
	initialize: function(id, title, artist, url, refURL, bookmarked) {
		this.id = id;
		this.title = title;
		this.artist = artist;
		this.url = url;
		this.refURL = refURL;
		this.soundId = 'track_'+this.id;
		this.bookmarked = bookmarked;
		this.loadError = false;
	},
	
	play: function(options,playbackPosition) {
		if (this.loadError) {
			CPlayer.next();
			return;
		}

		if (!soundManager.getSoundById(this.soundId)) {
			soundManager.createSound(Object.extend(options,{
				id: this.soundId,
				url: this.url,
				autoPlay: false,
				onload: CPlayer.onTrackLoad,
				whileplaying: CPlayer.updateDurationBar,
				whileloading: CPlayer.updateDurationBar
			}));
		}

		if (playbackPosition != null) {
			soundManager.setPosition.delay(1,this.soundId,playbackPosition);
		}

		soundManager.play(this.soundId,options);
	},
	
	getSound: function() {
		return soundManager.getSoundById(this.soundId);
	},
	
	pause: function() {
		soundManager.pause(this.soundId);
	},
	
	resume: function() {
		soundManager.resume(this.soundId);
	},
	
	togglePause: function() {
		soundManager.togglePause(this.soundId);
	},
	
	stop: function() {
		soundManager.stop(this.soundId);
		// if this mp3 is still loading, stop loading.
		if (this.getSound().readyState == 1)
			soundManager.unload(this.soundId);
	},
	
	getPosition: function() {
		return this.getSound().position;
	},
	getDuration: function() {
		return this.getSound().duration;
	},
	
	setVolume: function(v) {
		soundManager.setVolume(this.soundId,v);
	}
}

/***** CPlaylist *****/

var CPlaylist = Class.create();

CPlaylist.getTrackContainerId = function(id,index) {
	return 'tc_'+id+'_'+index;
};

CPlaylist.prototype = {
	initialize: function(id,trackIds) {
		this.id = id;
		this.setTrackIds(trackIds);
		this.initializeTracks();
	},
	
	initializeTracks: function() {
		// find tracks that haven't been init'ed and query the server for their info
		newTracks = new Array();
		for (i=0; i<this.trackIds.length; i++) {
			if (!CPlayer.tracks.get(this.trackIds[i]))
				newTracks.push(this.trackIds[i]);
		}
		if (newTracks.length > 0) {
			new Ajax.Request('track.php',{
				parameters: {action: 'init_tracks', ids: newTracks.toString()},
				evalScripts: true,
				onSuccess: this._trackInitSuccess,
				onFailure: this._trackInitFailure
			});
		}
	},
	
	addTrack: function(trackId) {
		this.trackIds.push(trackId);
		this.initializeTracks();
	},
	removeTrack: function(index) {
		// remove the trackId from the playlist
		this.trackIds.splice(index,1);
	},
	
	_trackInitSuccess: function(t) {
		//alert(t.responseText);
	},
	_trackInitFailure: function(t) {
		alert("Error initing tracks: "+t.responseText);
	},
	
	setTrackIds: function(trackIds) {
		this.trackIds = trackIds.clone();
	},
	
	getTrackIdAt: function(index) {
		return this.trackIds[index];
	},
	
	getLength: function() {
		return this.trackIds.length;
	}
}

/***** CPlayer *****/

var CPlayer = {
	tracks: 					new Hash(),
	playlists: 				new Hash(),
	currentTrack: 		null,
	currentPlaylist: 	null,
	playing: 					false,
	volume: 					100,
	visible: 					false,
	tagsVisible: 			false,
	
	initialize: function() {
		jar = new CookieJar();
		playerState = jar.get('player_state');
		if (playerState != null) {
			t = playerState.track;
			previousTrack = new CTrack(t.id,t.title,t.artist,t.url,t.refURL,t.bookmarked);
			CPlayer.addTrack(previousTrack);
			previousPlaylist = CPlayer.addPlaylist(new CPlaylist('previous_playlist',
				playerState.playlistTrackIds));
			Event.observe(window,'load', CPlayer.autoPlay.curry(
				'previous_playlist',playerState.playlistIndex,playerState.playbackPosition));
			jar.remove('player_state');
		}
		Event.observe(window,'unload',CPlayer.onUnload);
	},
	addPlaylist: function(playlist) {
		CPlayer.playlists.set(playlist.id,playlist);
	},
	addTrack: function(track) {
		if (CPlayer.tracks.get(track.id) == undefined)
			CPlayer.tracks.set(track.id,track);
	},
	autoPlay: function(playlistId,index,playbackPosition) {
		CPlayer.fadeIn = true;
		// fix this next line
		soundManager.onload = CPlayer.play.curry(playlistId,index,playbackPosition);
	},
	play: function(playlistId,index,playbackPosition) {
		// show player if hidden
		if (!CPlayer.visible) {
			new Effect.PlayerMove('cplayer',{bottom: 0, duration: 1});
			CPlayer.visible = true;
		}

		if (CPlayer.currentTrack != null) {
			CPlayer.currentTrack.stop();
		}

		// fade in if we need to
		if (CPlayer.fadeIn)
			CPlayer.startFadeIn();

		CPlayer.currentPlaylist = CPlayer.playlists.get(playlistId);
		CPlayer.currentPlaylistIndex = index;
		CPlayer.currentTrack = CPlayer.tracks.get(
			CPlayer.currentPlaylist.trackIds[CPlayer.currentPlaylistIndex]);

		CPlayer.playing = true;
		$('cplayer_play_button').addClassName('playing');
		
		$('cplayer_current_title').update(CPlayer.currentTrack.title);
		$('cplayer_current_artist').update(CPlayer.currentTrack.artist);
		src = (CPlayer.currentTrack.bookmarked ? 
			'/images/player/star.gif' : '/images/player/star_fade.gif');
		$('cplayer_toggle_favorite').getElementsByTagName('img')[0].src = src;
		if (CPlayer.currentTrack.refURL == '') {
			$('cplayer_current_track_ref').hide();
		}
		else {
			$('cplayer_current_track_ref').show();
			$('cplayer_current_track_ref').href = CPlayer.currentTrack.refURL;
		}
		
		// load current track's tags
		$('cplayer_tag_container').update('loading tags...');
		new Ajax.Updater('cplayer_tag_container','tag.php',{
			parameters: {
				action: 'fetch_track_tags',
				track_id: CPlayer.currentTrack.id
			}
		});
		
		CPlayer.currentTrack.play({onfinish: CPlayer.onTrackFinish},playbackPosition);
		CPlayer.highlightCurrentTrack();
	},
	
	highlightCurrentTrack: function() {
		// un-highlight old track
		if (CPlayer.currentTrackContainer != null) {
			CPlayer.currentTrackContainer.removeClassName('now_playing');
		}
		
		CPlayer.currentTrackContainer = $('tc_'+CPlayer.currentPlaylist.id+'_'+
			CPlayer.currentPlaylistIndex);
		if (CPlayer.currentTrackContainer != null) {
			CPlayer.currentTrackContainer.addClassName('now_playing');
		}
	},
	
	pause: function() {
		if (CPlayer.currentTrack != null)
			CPlayer.currentTrack.pause();
	},
	
	stop: function() {
		if (CPlayer.currentTrack != null)
			CPlayer.currentTrack.stop();
	},
	
	togglePlay: function() {
		if (CPlayer.currentTrack != null) {
			if (CPlayer.currentTrack.togglePause());
			CPlayer.playing = !CPlayer.playing;
			if (CPlayer.playing)
				$('cplayer_play_button').addClassName('playing');
			else
				$('cplayer_play_button').removeClassName('playing');
		}
	},
	
	previous: function() {
		if (CPlayer.currentPlaylist != null && 
			CPlayer.currentPlaylistIndex-1 >= 0) {
				CPlayer.play(CPlayer.currentPlaylist.id,CPlayer.currentPlaylistIndex-1);
		}
	},
	next: function() {
		if (CPlayer.currentPlaylist != null && 
			CPlayer.currentPlaylistIndex+1 < CPlayer.currentPlaylist.getLength()) {
				CPlayer.play(CPlayer.currentPlaylist.id,CPlayer.currentPlaylistIndex+1);
		}
		else {
			CPlayer.playing = false;
		}
	},
	
	onTrackFinish: function() {
		CPlayer.next();
	},
	
	// callback from track when it finished loading
	onTrackLoad: function() {
		if (CPlayer.currentTrack.getSound().readyState == 2) {
			// we couldn't load the track.
			// deactivate it and move forward
			CPlayer.currentTrack.loadError = true;
			CPlayer.next();
		}
	},
	
	toggleCurrentFavorite: function() {
		if (CPlayer.currentTrack == null)
			return;

		$('cplayer_toggle_favorite').getElementsByTagName('img')[0].src =
			'/images/icons/spinner.gif';

		new Ajax.Request('user.php',{
			parameters: {action: 'toggle_track_favorite', id: CPlayer.currentTrack.id},
			onSuccess: CPlayer._toggleCurrentFavorite,
			onFailure: CPlayer._toggleCurrentFavoriteFailure
		});
	},
	_toggleCurrentFavorite: function(t) {
		var data = eval(t.responseText);
		if (data.favorite == '1') {
			src = '/images/player/star.gif';
			CPlayer.currentTrack.bookmarked = true;
		}
		else {
			src = '/images/player/star_fade.gif';
			CPlayer.currentTrack.bookmarked = false;
		}
		$('cplayer_toggle_favorite').getElementsByTagName('img')[0].src = src;
	},
	_toggleCurrentFavoriteFailure: function(t) {
		alert('Error toggling favorite...');
	},
	
	updateDurationBar: function() {
		maxWidth = $('cplayer_current_wrapper').getWidth();
		width = Math.round((CPlayer.currentTrack.getPosition()/CPlayer.currentTrack.getDuration())*maxWidth);
		$('cplayer_duration_bar').setStyle({
			width: width+'px'
		});
		$('cplayer_duration_background').setStyle({
			width: maxWidth+'px'
		})
		
		// HACK.  this isn't really the place to do this, I think...
		CPlayer.playbackPosition = CPlayer.currentTrack.getPosition();
	},
	
	onUnload: function() {
		playerState = new Object();
		if (CPlayer.playing) {
			playerState.playlistTrackIds = CPlayer.currentPlaylist.trackIds;
			playerState.playlistIndex = CPlayer.currentPlaylistIndex;
			playerState.playbackPosition = CPlayer.playbackPosition;
			playerState.track = Object.clone(CPlayer.currentTrack);
//			playerState.tracks = Object.clone(CPlayer.tracks);
			jar = new CookieJar();
			success = jar.put('player_state',playerState);
		}
	},
	
	setVolume: function(v) {
		if (v > 100)
			v = 100;
		if (v < 0)
			v = 0;
		CPlayer.volume = v;
		if (CPlayer.currentTrack != null) {
			CPlayer.currentTrack.setVolume(v);
		}
	},
	
	startFadeIn: function() {
		CPlayer.setVolume(0);
		CPlayer.fadeInPE = new PeriodicalExecuter(CPlayer._doFadeIn,0.05);
	},
	_doFadeIn: function() {
		if (CPlayer.volume >= 100)
			CPlayer.fadeInPE.stop();
		else
			CPlayer.setVolume(CPlayer.volume+2);
	},
	
	addTrackTag: function(tag) {
		var input = $('cplayer_tag_input').value;
		if (CPlayer.currentTrack == null || input == '')
			return;

		new Ajax.Updater('cplayer_tag_container','tag.php', {
			insertion: 'bottom',
			parameters: {
				action: 'add_track_tag',
				track_id: CPlayer.currentTrack.id,
				tag: input
			}
		});
		$('cplayer_tag_input').value = '';
	},
	
	removeTrackTag: function(tag,linkId) {
		if (CPlayer.currentTrack == null)
			return;
			
		new Ajax.Request('tag.php', {
			parameters: {
				action: 'remove_track_tag',
				track_id: CPlayer.currentTrack.id,
				tag: tag,
				link_id: linkId
			},
			onSuccess: CPlayer._removeTrackTag
		});
	},
	_removeTrackTag: function(t) {
		$(t.responseText).remove();
	}
};

/***** TrackTools *****/

var TrackTools = {
	initialize: function() {
		// go through each track and initialize the bookmark button for that track
		CPlayer.tracks.each(function(pair) {
			if (pair.value.bookmarked) {
				src = '/images/player/star.gif';
			}
			else {
				src = '/images/player/star_fade.gif';
			}
			var imgs = $$('img.toggle_favorite_'+pair.key);
			for (var i=0; i<imgs.length; i++) {
				imgs[i].src = src;
			}
		});
	},
	
	toggleFavorite: function(id) {
		var imgs = $$('img.toggle_favorite_'+id);
		for (var i=0; i<imgs.length; i++) {
			imgs[i].src = '/images/icons/spinner.gif';
		}

		new Ajax.Request('user.php',{
			parameters: {action: 'toggle_track_favorite', id: id},
			onSuccess: TrackTools._toggleFavorite,
			onFailure: TrackTools._toggleFavoriteFailure
		});
		return false;
	},
	_toggleFavorite: function(t) {
		var data = eval(t.responseText);
		if (data.favorite == '1') {
			src = '/images/player/star.gif';
			CPlayer.tracks.get(data.id).bookmarked = true;
		}
		else {
			src = '/images/player/star_fade.gif';
			CPlayer.tracks.get(data.id).bookmarked = false;
		}
		var imgs = $$('img.toggle_favorite_'+data.id);
		for (var i=0; i<imgs.length; i++) {
			imgs[i].src = src;
		}
	},
	_toggleFavoriteFailure: function(t) {
		alert('Error toggling bookmark...');
	}
};

CPlayer.initialize();
Event.observe(window,'load',TrackTools.initialize);