﻿/******************************************************
* Funciones para manejar el reproductor de musica
* @autor ivangc
******************************************************/
var playerStatus = { Play : 1, Pause: 0, Stop: 2 };
var playerMode = { Normal : 0, Shuffle : 1 };
var commands = { CreateAlbum: "addAlbum", DeleteAlbum: "deleteAlbum", PlaySong: "playSong", 
AddSong: "addSong", DeleteSong: "deleteSong", MoveSong: "moveSong", MoveToList: "moveToList",
GetList: "getList", GetOptions: "getOptions", SetVol: "setVol", PlayerMode: "setPlayerMode",
RepeatMode: "setRepeatMode", SetListExpanded: "setListExpanded" };
function Player(destination,volume,onErrorCallback,onChangeSongCallback,onPreChangeSongCallback,onTimeChangedCallback, onLoadChangedCallback, onChangeStatusCallback)
{
	/*CAMPOS*/
	//Public: Almacena el modo de reproduccion
	this.mode = playerMode.Shuffle;
	//Public: Alamacena el valor de la lista q se quiere repetir. -1 = ninguna
	this.repeat = -1;
	//Private: Almacena el objeto flash
	this._swfObj = null;
	//Private: El id de la etiqueta HTML en la que va a salir el flash
	this._destination = destination;
	//Private: Almacena el volumen actual del reproductor
	this._volume = volume;
	//Private: Guarda la cancion actual
	this._song = null;
	//Public: Guarda el id de la cancion actual
	this.songID = null;
	//Private: Guarda el estado del reproductor, enumeracion del tipo playerStatus
	this._status = playerStatus.Pause;
	//Public: Guarda las playlists actuales
	this.playLists = null;
	//Private: Guarda el indice de la lista actual
	this._listPosition = null;
	//Private: Guarda la lista reproducida anteriormente
	this._lastListPosition=null;
	//Private: Guarda el indice de la cancion actual
	this._trackPosition = null;
	//Private: Guarda la cancion reproducida anteriormente
	this._lastTrackPosition = null;
	//Indica si hay se va a fijar la lista en cuanto se reproduzca una cancion
	this.fixPending = false;
	//Private: indica el porcentaje cargado de la cancion
	this._loaded = 0;
	//Public: indica si la cancion actual es de las listas o no
	this.isSingle = false;
	/*EVENTOS*/
	//Funcion que se desencadena cuando ocurre un error al cargar la canciÃ³n
	this.onError = onErrorCallback;
	//Funcion que se desencadena cuando se carga una nueva canciÃ³n
	this.onChangeSong = onChangeSongCallback;
	//Funcion que se llama antes de enviar la peticion de cambio de cancion
	this.onPreChangeSong = onPreChangeSongCallback;
	//Funcion que se llama cuando cambia el progreso de la canciÃ³n
	this.onTimeChanged = onTimeChangedCallback;
	//Funcion que se llama cuado avanza la carga de la cancion
	this.onLoadChanged = onLoadChangedCallback;
	//Funcion que se llama cuando cambia el estado de reproduccion (play, pause, tiempo...)
	this.onChangeStatus = onChangeStatusCallback;
	

	/*FUNCIONES*/
	//Public: Para o reproduce una cancion segun su estado
	this.playPause = function(){
		this.setFlashVar('playpause');
	}
	//Public: Detiene una la reproduccion actual
	this.stop = function(){
		this.setFlashVar('stop');
	}
	this.setPlayerMode = function(mode, save)
	{
		this.mode = mode;
		var shuffle = $("#shuffle");
		if(this.mode == playerMode.Shuffle)
			shuffle.addClass("active");
		
		else
			shuffle.removeClass("active");
		if(save)
		{
			var p = new Params();
			p.add("value", this.mode);
			queue.callServer("callbacks", commands.PlayerMode, p, null);
		}
	}
	//Public: Pasa a la siguiente cancion de la lista de reproduccion, teniendo en cuenta las opciones de reproduccion (aleatorio,repetir...)
	this.nextSong = function() {
		if(this.playLists == null || this._listPosition == null)
			return;
		if(this.mode == playerMode.Normal)
		{
			if(this.playLists[this._listPosition].tracks.length > this._trackPosition + 1)
				this.setSong(this._listPosition,this._trackPosition + 1);
			else //if(this.playLists.length > this._listPosition + 1)
			{
				if(this.repeat == -1)
				{
					var pos = this.getNextNonEmptyList();
					if(pos != null)
						this.setSong(pos, 0);
				}
				else
				{
					this.setSong(this._listPosition, 0);
				}
			}
		}
		else if(this.mode == playerMode.Shuffle)
		{
			var total;
			if(this.repeat > -1)
			{
				if(this.playLists[this.repeat].tracks)
				{
					var randomTrack = Math.floor(Math.random() * this.playLists[this.repeat].tracks.length);
					this.setSong(this.repeat, randomTrack);
				}
			}
			else
			{
				var randomList;
				var i = 0;
				randomList = Math.floor(Math.random() * this.playLists.length);
				while(!this.playLists[randomList].tracks && i < 50)
				{
					randomList = Math.floor(Math.random() * this.playLists.length);
					i++;
				}
				var randomTrack = Math.floor(Math.random() * this.playLists[randomList].tracks.length);
				this.setSong(randomList, randomTrack);
			}
		}
	}
	//Public: Pasa a la anterior cancion de la lista de reproduccion, teniendo en cuenta las opciones de reproduccion (aleatorio,repetir...)
	this.previousSong = function() {
		if(this.playLists == null || this._listPosition == null)
			return;
		if(this.mode == playerMode.Normal)
		{
			if(this._trackPosition - 1 >= 0)
				this.setSong(this._listPosition,this._trackPosition - 1);
			else
			{
				if(this.repeat == -1)
				{
					var pos = this.getBackNonEmptyList();
					if(pos != null)
						this.setSong(pos, this.playLists[pos].tracks.length-1);
				}
				else
				{
					this.setSong(this._listPosition, this.playLists[this._listPosition].tracks.length-1);
				}
			}
		}
	}
	//Private: Devuelve la posicion de la proxima lista no vacia empezando en la posicion de la lista actuals
	this.getNextNonEmptyList = function()
	{
		var i,j;
		for(i=0, j=this._listPosition+1; i<this.playLists.length; i++,j++)
		{
			if(j == this.playLists.length)
				j = 0;
			if(this.playLists[j].tracks && this.playLists[j].tracks.length > 0)
				return j;
		}
		return null;
	};
	//Private: Devuelve la posicion de la anterior lista no vacia empezando en la posicion de la lista actuals
	this.getBackNonEmptyList = function(){
		var i,j;
		for(i=0, j=this._listPosition-1; i<this.playLists.length; i++,j--)
		{
			if(j == -1)
				j = this.playLists.length-1;
			if(this.playLists[j].tracks && this.playLists[j].tracks.length > 0)
				return j;
		}
		return null;
	}
	//Public: Reproduce la canciÃ³n anterior
	this.prevSong = function() {}
	//Public: Cambia el volumen al valor especificado
	this.changeVol = function(volume, save) {
		this._volume = volume;
		this.setFlashVar('volume',this._volume);
		printVol();
		if(save)
		{
			var p = new Params();
			p.add("value", volume);
			queue.callServer("callbacks", commands.SetVol, p, null);
		}
	}
	//Public: Setea si una lista se muestra o no
	this.setListExpanded = function(listPosition, expanded){
		this.playLists[listPosition].expanded = expanded;
		var params = new Params();
		params.add("idList", this.playLists[listPosition].id);
		params.add("expanded", expanded);
		queue.callServer("callbacks", commands.SetListExpanded, params, null);
	}
	//Public: Devuelve el volumen actual del reproductor
	this.getVol = function() {
		return this._volume;
	}
	//Public: Salta a una parte de la cancion
	this.seek = function(seconds) {
		this.setFlashVar('scrub',seconds);
	}
	//Public: Establece la lista de reproduccion
	this.setList = function(JSONPlayList) {
		this.playLists = eval('(' + JSONPlayList + ')');
	}
	//Public: AÃ±ade una nueva cancion a la lista indicada
	this.addSong = function(idList,id,title){
		var params = new Params();
		params.add("idlista",idList);
		params.add("idcancion",id);
		params.add("title",title)
		var me = this;
		queue.callServer("callbacks",commands.AddSong, params,function(response){
			response = eval(response);
			if(!response)
			{
				alert("Unexpected error");
				return;
			}
			var indexAlbum = me.getIndexList(idList);
			if(indexAlbum > -1)
			{
				if(!me.playLists[indexAlbum].tracks || !me.playLists[indexAlbum].tracks.length)
					me.playLists[indexAlbum].tracks = Array();
				me.playLists[indexAlbum].tracks.push({id: id, name: response});
				imprimeListas(false);
			}
		});
	}
	//Public: Elimina una canciÃ³n del album especificado
	this.delSong = function(idAlbum,idSong)
	{
		var params = new Params();
		params.add("idlista",this.playLists[idAlbum].id);
		params.add("idcancion",this.playLists[idAlbum].tracks[idSong].id);
		var me = this;
		$("#id-" + this.playLists[idAlbum].tracks[idSong].id).remove();
		queue.callServer("callbacks", commands.DeleteSong, params,function(list){
			if(list && list != "[]")
			{
				me.setList(list);
				imprimeListas(false);
			}
		});
	}
	//Public: Añade una nueva lista
	this.addAlbum = function(name, callback)
	{
		if(!this.playLists){
			this.playLists = Array();
		}
		var params = new Params();
		params.add("album",name);
		var me = this;
		queue.callServer("callbacks", commands.CreateAlbum, params,function(data){
			var data = eval('(' + data + ')');
			if(data && data.id != null){
				me.playLists.push({id: data.id, name: data.title, tracks: [],expanded:1});
			}
			if(callback)
					callback(data);
		});
	}
	//Public: Elimina la lista especificada
	this.delAlbum = function(idAlbum)
	{
		var params = new Params();
		params.add("idlista",idAlbum);
		var me = this;
		
		queue.callServer("callbacks", commands.DeleteAlbum, params,function(data){
			var indexAlbum = me.getIndexList(idAlbum);
			if(indexAlbum > -1)
			{
				me.playLists.splice(indexAlbum,1);
				imprimeListas(false);
				if(me.repeat == indexAlbum)
				{
					if(indexAlbum == me._listPosition){
						me._listPosition = 0;
						me._trackPosition = 0;
					}
					me.setRepeatMode(false);
				}
			}
		});
	}
	this.getIndexList = function(idAlbum)
	{
		var i;
		for(i=0; i<this.playLists.length; i++)
		{
			if(this.playLists[i].id == idAlbum)
				return i;
		}
		return -1;
	}
	
	this.moveSong = function(album_inicio,posicion_inicio,album_destino,posicion_destino)
	{
		if(album_inicio == album_destino)
		{
			var params = new Params();
			params.add("from",posicion_inicio);
			params.add("to",posicion_destino);
			params.add("idlista",album_inicio);
			var me = this;
			queue.callServer("callbacks", commands.MoveSong,params,function(data){
				if(data != "false"){
					me.setList(data);
				}
			});
		}
		else
		{
			var params = new Params();
			params.add("fromlista",album_inicio);
			params.add("tolista",album_destino);
			params.add("fromposicion",posicion_inicio);
			params.add("toposicion",posicion_destino);
			var me = this;
			queue.callServer("callbacks", commands.MoveToList,params,function(data){
				if(data != "false"){
					me.setList(data);
					imprimeListas(false);
				}
			});
		}
	}
	
	//Public: Mueve una cancion a la position indicada en el album especificado
	this.moveSongAlbum = function(idAlbum,idSong,position)
	{
	    var song = this.playLists[idAlbum].tracks[idSong];
	    this.playLists[idAlbum].tracks.splice(idSong,1);
	    this.playLists[idAlbum].tracks.splice(position,0,song);
	}
	//Public: Mueve una cancion de un album a otro
	this.moveSongToAlbum = function(idAlbumFrom,idAlbumTo,idSong)
	{
	    this.playLists[idAlbumFrom].tracks.splice(idSong,1);
	    this.playLists[idAlbumTo].tracks.push(this.playLists[idAlbumFrom].tracks[idSong]);
	}
	//Public: Mueve un album a la posicion indicada
	this.moveAlbum = function(idAlbum,position)
	{
	    var album = this.playLists[idAlbum];
	    this.playLists.splice(idAlbum,1);
	    this.playLists.splice(position,0,album);
	}
	this.setRepeatMode = function(activated, save)
	{
		if(activated)
		{
			$("#repeatAll").removeClass("active");
			$("#repeat1").addClass("active");
			if(this._listPosition != null)
				this.repeat = this._listPosition;
			else
				this.repeat = -2;			
		}
		else
		{
			$("#repeat1").removeClass("active");
			$("#repeatAll").addClass("active");
			this.repeat = -1;
		}
		if(save)
		{
			var p = new Params();
			p.add("value", activated?1 : 0);
			queue.callServer("callbacks", commands.RepeatMode, p, null);
		}
		disableLists();
	}
	//Public: reproduce una cancion especifica
	this.setSingleSong = function(name,id){
		this._lastTrackPosition = this._trackPosition;
		this._lastListPosition = this._listPosition;
		this._trackPosition = null;
		this._listPosition = null;
		this._song = name;
		var p = new Params();
		p.add("id",id);
		p.add("title",this._song);
		this.onPreChangeSong(id,this.songID);
		this.isSingle = true;
		this.playSong(p);
	}
	//Private: setea la cancion que se va a reproducir
	this.setSong = function(idList,idTrack) {
		if(this.playLists == null)
			return;
		this._lastTrackPosition = this._trackPosition;
		this._lastListPosition = this._listPosition;
		this._trackPosition = idTrack;
		this._listPosition = idList;
		if(this.repeat != -1)
			this.setRepeatMode(true);
		this._song = this.playLists[idList].tracks[idTrack].name;
		var p = new Params();
		p.add("id", this.playLists[idList].tracks[idTrack].id);
		p.add("title",this._song);
		this.onPreChangeSong(this.playLists[idList].tracks[idTrack].id, this.songID);
		this.isSingle = false;
		this.playSong(p);
	}
	//Private: envia la peticion del id de Youtube al servidor y cuando llegar carga el video
	this.playSong = function(params)
	{
		var me = this;
		var newSongID = params.getItem(0).value;
		if(this.songID == newSongID){
			_notify = true;
			this.seek(0);
			return;
		}
		else {
			if(this.songID != null)
				this.stop();
			TOTAL = null;
			$("#percent").css("width",0);
			$("#pos").css("width",0);
			$("#infoSongTime").html("00:00 / 00:00");
			//$("#title").text(lg_loading + "...");
		}
		this.songID = newSongID;
		//document.location.hash = "#song=" + params.getItem(0).value;
		
		queue.callServer("callbacks", commands.PlaySong,params, function(response){
			if(response){
				response = eval('(' + response + ')');
				if(response.t == null){
					me.onError();
					return;
				}
				var flv = "http://www.youtube.com/get_video?video_id="+ response.v +"%26t=" + response.t;
				me.createFlash(flv);
				_notify = true;
				me.onChangeSong(response.title);
				me.setLoaded(0);
			}
			else{
				//Error, no se puede cargar la cancion
				me.onError();
			}
		}, function(){
			me.nextSong();
		});
	}
	

	//Private: envÃ­a datos al reproductor flash para modificarlo
	this.setFlashVar = function(cmd, param1){
		var movie = null;
		if(navigator.appName.indexOf("Microsoft")!=-1){
			movie = window['rep'];
		}
		else{
			movie = document['rep'];
		}
		if(movie!=undefined)
			movie.sendEvent(cmd,param1);
	}
	//Private: Crea el objeto flash
	this.createFlash = function(file){
		var flashvars = { 
			type: "flv",
			javascriptid: this._swfName,
			volume: this.volume,
			enablejs:true
		};
		if(file){
			flashvars.file = file;
			flashvars.autostart = true;
		}
		swfobject.embedSWF("/mediaplayer.swf", "rep", "0", "0", "9.0.0",null, flashvars);
		
		
		/*//this._swfObj.addVariable("autostart","true");
		this._swfObj.addVariable("type","flv");
		this._swfObj.addVariable("javascriptid",this._swfName);
		this._swfObj.addVariable("volume",this._volume);
		this._swfObj.addParam("allowscriptaccess ", "always");
		this._swfObj.addVariable("enablejs",true);
		this._swfObj.addVariable("allowfullscreen",true);
		this._swfObj.write("rep");*/
	}
	this.setLoaded = function(percent)
	{
		this._loaded = percent;
	}
	this.getLoaded = function()
	{
		return this._loaded;
	}
	//Public: serÃ­a el "constructor" del objeto
	this.init = function(){
		//loading tracks...
		$("#loadingSearch").css("visibility","visible");
		$("#loadingSearch").css("opacity",1);

		this.createFlash();
		var me = this;
	}
	this.init();
	//Private: lanza el evento onTimeChanged, llamado desde la funcion getUpdate
	this.fireOnTimeChanged = function(seconds,left){ this.onTimeChanged(seconds,left); }
	this.fireOnLoadChanged = function(p){ this.setLoaded(p); this.onLoadChanged(p); }
	this.fireOnChangeStatus = function(status) { this._status = status; this.onChangeStatus(status); }
}
//Objeto global q representa  al reproductor
var player = null;
//Almacena un valor que indica si se van obtener datos del flash o no
var _notify = true;
var queue = null;

//Funcion llamada por el reproductor de flv para informar sobre el estado
function getUpdate(type,pr1,pr2){
	if(type == "time")
	{
		player.fireOnTimeChanged(pr1,pr2);
		if(pr2 == 0 && pr1 > 0 && _notify)
		{
			_notify = false;
			player.nextSong();
		}
	}
	else if(type == "load")
	{
		player.fireOnLoadChanged(pr1);
	}
	else if(type == "state")
	        player.fireOnChangeStatus(pr1);
}
