/*
 *  
 *  $Id: controladorcomandos.cpp $
 *  Ginkgo CADx Project
 *
 *  Copyright 2008-12 MetaEmotion S.L. All rights reserved.
 *  http://ginkgo-cadx.com
 *
 *  This file is licensed under LGPL v3 license.
 *  See License.txt for details
 *
 *
 */
//#define _GINKGO_TRACE

#include <api/globals.h>
#include <api/threads/thread.h>
#include <api/icommand.h>
#include <api/ientorno.h>

#include <api/controllers/icontroladorlog.h>
#include <api/controllers/ieventscontroller.h>
#include <eventos/progresocomando.h>
#include <main/controllers/historycontroller.h>

#include <wx/wx.h>
#include <wx/thread.h>

#include "controladorcomandos.h"
#include <main/gui/mainwindow/ventanaprincipal.h>

//#undef GTRACE
//#define GTRACE(expr) std::cout << expr << std::endl


GNC::LanzadorComandos::LanzadorComandos(GNC::GCS::IComando* pComando)
{
	//std::cout << "LanzadorComandos::LanzadorComandos()" << this << std::endl;
	m_idThreadGinkgo = 0;
	m_pComando = pComando;
	m_Abortar = false;
	//this->Create();
	m_pComando->SetNotificadorProgreso(this);
	//NotificarProgreso(0.0f, m_pComando->GetName());
}

GNC::LanzadorComandos::~LanzadorComandos()
{

}

void* GNC::LanzadorComandos::Entry()
{
	this->IniciarUnlocker();

	GNC::GCS::Threading::SetThreadName( GetId(), m_pComando->GetName());

	if (m_pComando != NULL && !m_pComando->EstaAbortado() && m_Dependencias.Size() > 0) {
		while (m_Dependencias.NotEmpty()) {
			if (!m_Dependencias.Wait(1000)) {
				//std::cout << "Timeout de espera para " << m_pComando->GetName() << "(" << m_idThreadGinkgo << ") " << m_Dependencias.Size() << " pendientes" << std::endl;
				m_Dependencias.TerminarPendientes();
			}
		}
	}

	wxWindow* w = GNC::GCS::IEntorno::Instance()->GetVentanaPrincipal();

	if (m_pComando != NULL && !m_pComando->EstaAbortado()) {

		if (w != NULL) {
			EventoProgreso ce(EventoProgreso::ComandoIniciado, m_idThreadGinkgo);
			w->AddPendingEvent(ce);
		}

		try {
			m_pComando->Execute();
		}
		catch (GNC::GCS::ControladorComandosException& ) {
			//comando abortado
		}
		catch (const std::bad_alloc& ) {
			//comando ha cascado por un bad alloc
		}
		catch (const std::exception& ) {
			//comando abortado
		}
		catch (...) {
			LOG_ERROR("LanzadorComandos", "Error interno ejecutando el comando con id = " << m_pComando->GetId());
		}

	}
	return NULL;
}

bool GNC::LanzadorComandos::RecalcularDependencias()
{
	//revisamos la lista de "aborta si" ya que en ese caso no arrancamos

	if(m_Abortar){
		return false;
	}

	GNC::GCS::IPersistentCommand* pPersistent = dynamic_cast<GNC::GCS::IPersistentCommand*>(m_pComando);

	//GTRACE(">> comprobando el ''AbortaSi'' y el ''CancelaA'' : " << m_idThreadGinkgo);
	GNC::ControladorComandos::MapaComandos* mapaComandosLanzados = &(GNC::ControladorComandos::Instance()->m_ComandosLanzados);
	for(GNC::ControladorComandos::MapaComandos::iterator it = mapaComandosLanzados->begin(); it!= mapaComandosLanzados->end(); ++it){
		LanzadorComandos* pLanzador = (*it).second;
		if (pLanzador == this) {
			continue;
		}

		for(GNC::GCS::IComando::TipoListaIdComandos::iterator it1 = m_pComando->m_Conflictos.begin(); it1 != m_pComando->m_Conflictos.end(); ++it1){
			if(pLanzador->GetComando()->GetId() == (*it1) && pLanzador->m_idThreadGinkgo != m_idThreadGinkgo){
				return false;
			}
		}
		//cancel persistent commands with same idBBDD
		if (pPersistent != NULL) {
			GNC::GCS::IPersistentCommand* pPersistent2 = dynamic_cast<GNC::GCS::IPersistentCommand*>(pLanzador->GetComando());
			if (pPersistent2 != NULL && pPersistent2->getIdBBDD() == pPersistent->getIdBBDD()) {
				return false;
			}
		}
	}

	for(GNC::ControladorComandos::MapaComandos::iterator it = mapaComandosLanzados->begin(); it!= mapaComandosLanzados->end(); ++it){
		LanzadorComandos* pLanzador = (*it).second;
		if (pLanzador == this) {
			continue;
		}

		for(GNC::GCS::IComando::TipoListaIdComandos::iterator it1 = m_pComando->m_Reemplazos.begin(); it1 != m_pComando->m_Reemplazos.end(); ++it1){
			if(pLanzador != NULL && pLanzador->GetComando()->GetId() == (*it1) && pLanzador->m_idThreadGinkgo != m_idThreadGinkgo){
				m_Dependencias.RegistrarEspera(pLanzador);
				pLanzador->Terminar();
			}
			else if (pLanzador == NULL) {
				LOG_ERROR("CommandsController","Inconsistency detected: Launched command was dereferenced");
			}
		}

		for(GNC::GCS::IComando::TipoListaIdComandos::iterator it1 = m_pComando->m_Dependencias.begin(); it1 != m_pComando->m_Dependencias.end(); ++it1){
			if(pLanzador != NULL && pLanzador->GetComando()->GetId() == (*it1) && pLanzador->m_idThreadGinkgo != m_idThreadGinkgo){
				//GTRACE(">> encontrado un comando de ''Espera a'' => El hilo " << m_idThreadGinkgo<< " esprerara a "<<pLanzador->m_idThreadGinkgo);
				//nos aseguramos de que el no esta esperando por nosostros... en tal caso habría un bloqueo mutuo!!!
				//solo se permite en caso de que los dos comandos tengan el mismo id por ejemplo comandos que se tienen que ejecutar en serie,
				//en tal caso solo le esperamos si su id es menor que el nuestro
				if(pLanzador->GetComando()->GetId() != this->GetComando()->GetId() ||
					(pLanzador->GetComando()->GetId() == this->GetComando()->GetId() && m_idThreadGinkgo > pLanzador->m_idThreadGinkgo))
				{
					m_Dependencias.RegistrarEspera(pLanzador);
				}
			}
		}
	}
	return true;
}

void GNC::LanzadorComandos::OnExit()
{
	{
		GNC::GCS::ILocker pLocker(GNC::ControladorComandos::Instance());

		//region "Region sincrona con ControladorComandos"
		m_pComando->SetNotificadorProgreso(NULL);

		GNC::ControladorComandos::MapaComandos::iterator it = GNC::ControladorComandos::Instance()->m_ComandosLanzados.find(m_idThreadGinkgo);
		if (it != GNC::ControladorComandos::Instance()->m_ComandosLanzados.end()) {
			GNC::ControladorComandos::Instance()->m_ComandosLanzados.erase(it);
		}

		//avisa a los que estan esperando

		wxWindow* w = GNC::GCS::IEntorno::Instance()->GetVentanaPrincipal();

		if (w != NULL) {
			GNC::ControladorComandos::Instance()->m_ComandosTerminados[m_idThreadGinkgo] = m_pComando;
			EventoProgreso ce(EventoProgreso::ComandoFinalizado, m_idThreadGinkgo);
			w->AddPendingEvent(ce);
		}
		else {
			LOG_WARN("LanzadorComandos::OnExit()", "Error: No se invocara el evento de finalizacion del comando. El sistema puede quedar bloqueado o inestable");
			if (m_pComando != NULL) {
				m_pComando->Abort(); // Notificamos al comando de que va a abortar.
				delete m_pComando;
				m_pComando = NULL;
			}
		}
	}

	Signal();

	//LOG_TRACE("LanzadorComandos", "<< Comando Terminado");

	//endregion
}

void GNC::LanzadorComandos::IniciarUnlocker()
{
	#if defined(_WINDOWS)

	#else
	/*
	struct sigaction action;
	memset(&action, 0, sizeof(action));
	sigemptyset(&action.sa_mask);
	action.sa_flags = 0;
	action.sa_handler = FooSignalHandler;
	sigaction(SIGUSR2, &action, NULL);
	*/
	#endif
}

void GNC::LanzadorComandos::DoTerminar()
{
	this->m_Abortar = true;
	if (m_pComando != NULL) {
		//std::cout << "LanzadorComandos::DoTerminar(): Abortando comando:" << std::endl;
		m_pComando->Abort();
	}
	#if defined(_WINDOWS)

	#else
	//pthread_kill((pthread_t)this->GetId(), SIGUSR2);

	#endif
}

bool GNC::LanzadorComandos::NotificarProgreso(float progresoNormalizado, const std::string& texto)
{
	//GNC::GCS::ILocker pLocker(this);
	if(m_Abortar){
		//std::cout << "Comando abortado: No se notificara el progreso" << std::endl;
		return false;
	}
	//GTRACE(">> LanzadorComandos::NotificarProgreso(): " << m_idThreadGinkgo);
	LockProgreso();
	SetProgresoNormalizado(std::max<float>(0, std::min<float>(progresoNormalizado,1.0f)));
	SetTextoProgreso(texto);
	UnLockProgreso();


	wxWindow* w = GNC::GCS::IEntorno::Instance()->GetVentanaPrincipal();
	if(w!=NULL) {
		EventoProgreso ce(EventoProgreso::ComandoEjecutando, m_idThreadGinkgo);
		//std::cout << "AddPendingEvent EventoProgreso::ComandoEjecutando " << m_idThreadGinkgo << std::endl;
		w->GetEventHandler()->AddPendingEvent(ce);
	}
	//GTRACE("<< LanzadorComandos::NotificarProgreso(): " << m_idThreadGinkgo);
	return true;

}

//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------

//region Controlador de comandos

GNC::ControladorComandos* GNC::ControladorComandos::m_psInstancia = NULL;

GNC::ControladorComandos::ControladorComandos()
{
	m_Destroying = false;
	m_pProgreso = NULL;
	m_idThreads = 1;
}

GNC::ControladorComandos::~ControladorComandos()
{
	GTRACE(">> ControladorComandos::~ControladorComandos() ");
	AbortarComandosDeOwner(NULL);
	GTRACE("<< ControladorComandos::~ControladorComandos() ");
}

GNC::ControladorComandos* GNC::ControladorComandos::Instance()
{
	if (m_psInstancia == NULL) {
		m_psInstancia = new ControladorComandos();
	}
	return m_psInstancia;
}

void GNC::ControladorComandos::FreeInstance()
{
	if (m_psInstancia != NULL) {
		delete m_psInstancia;
		m_psInstancia = NULL;
	}

}

void GNC::ControladorComandos::Process(GNC::GCS::IComando * cmd)
{
	ProcessSync(cmd, true);
}

void GNC::ControladorComandos::ProcessSync(GNC::GCS::IComando* cmd, bool autodelete)
{
	cmd->Execute();
	cmd->Update();
	if (autodelete) {
		delete cmd;
	}
}

void GNC::ControladorComandos::ProcessAsync(std::string str, GNC::GCS::IComando* cmd, void * owner)
{
	cmd->SetOwner(owner);
	cmd->SetNotificadorProgreso(NULL);
	LanzadorComandos* thread = new LanzadorComandos(cmd);
	//thread->SetPriority(WXTHREAD_MAX_PRIORITY);

	GNC::GCS::ILocker locker(this);

	long threadId = m_idThreads++;
	thread->m_idThreadGinkgo = threadId;

	int res = -1;
	int creado = -1;
	try {
		if (thread->RecalcularDependencias()) {
			//if command is persistent... save it
			GNC::GCS::IPersistentCommand* pPersistent = dynamic_cast<GNC::GCS::IPersistentCommand*>(cmd);
			if (pPersistent != NULL) {
				GNC::GCS::HistoryController::Instance()->SaveTask(pPersistent);
			}
			creado = thread->Create();
			res = thread->Run();
		}
		else {
			delete cmd;
			if(creado == wxTHREAD_NO_ERROR)
			{
				thread->Delete();
			} else {
				delete thread;
			}
			thread = NULL;
		}
	}
	catch (GNC::GCS::ControladorComandosException& ex) {
		LOG_ERROR("ControladorComandos", "Error al lanzar el comando: " << ex.str());
		delete cmd;
		if(creado == wxTHREAD_NO_ERROR)
		{
			thread->Delete();
		} else {
			delete thread;
		}
		thread = NULL;
	}
	catch (...) {
		LOG_ERROR("ControladorComandos", "Error interno al lanzar el comando");
		delete cmd;
		if(creado == wxTHREAD_NO_ERROR)
		{
			thread->Delete();
		}
		else {
			delete thread;
		}
		thread = NULL;
	}
	if ( res == wxTHREAD_NO_ERROR && creado == wxTHREAD_NO_ERROR)
	{
		m_ComandosLanzados[threadId] = thread;
		MapaOwners::iterator it = m_MapaOwners.find(owner);
		if (it != m_MapaOwners.end())
		{
			(*it).second.push_back(threadId);
		}
		else
		{
			ListaHilos l;
			l.push_back(threadId);
			m_MapaOwners[owner] = l;
		}
	}
}

//este metodo es un poco malo porque la busqueda iterada...
void GNC::ControladorComandos::AbortarComando(GNC::GCS::IComando* pComando, bool sincrono)
{
	GNC::GCS::WaitQueue wqueue;
	GNC::GCS::ILocker locker(this);
	// Recorremos la lista de threads_ids de la vista
	for(MapaComandos::iterator it = m_ComandosLanzados.begin(); it!= m_ComandosLanzados.end(); ++it){
		LanzadorComandos* pLanzador = (*it).second;
		if(pLanzador == NULL || (*it).second->GetComando() != pComando){
			continue;
		}
		if (sincrono ) {
			wqueue.RegistrarEspera(pLanzador);
			std::cerr << "Registrando espera para tarea: ptr = " << pLanzador << std::endl;
		}
		pLanzador->Terminar();
	}	
}

void GNC::ControladorComandos::AbortarComando(long threadId, bool sincrono)
{
	GNC::GCS::WaitQueue wqueue;

	//---------------------------------------------------------------------
	// REGION CRITICA
	//---------------------------------------------------------------------
	{ // BEGIN Modificación del estado interno del controlador de comandos.
		GNC::GCS::ILocker locker(this);
		// Recorremos la lista de threads_ids de la vista
		MapaComandos::iterator it = m_ComandosLanzados.find(threadId);
		if (it != m_ComandosLanzados.end()) {
			LanzadorComandos* pLanzador = (*it).second;
			if (pLanzador != NULL) { //
				if (sincrono ) {
					wqueue.RegistrarEspera(pLanzador);
					std::cerr << "Registrando espera para tarea: threadId = " << (unsigned long) threadId << " ptr = " << pLanzador << std::endl;
				}
				pLanzador->Terminar();
			} else {
				std::cerr << "Detectada inconsistencia en el controlador de comandos: Comando lanzado desreferenciado. Flujo de comando perdido." << std::endl;
			}
		} else { // Buscamos el id en la lista de comandos terminados
			MapaComandosTerminados::iterator it3 = m_ComandosTerminados.find(threadId);
			if (it3 != m_ComandosTerminados.end()) {
				GNC::GCS::IComando* pComando = (*it3).second;
				if (pComando != NULL) {
					std::cerr << "Anulando comando terminado: threadId = " << (unsigned long) threadId << std::endl;
					pComando->Abort();
					delete pComando;
				} else {
					std::cerr << "Detectada inconsistencia en el controlador de comandos: Comando terminado nulo." << std::endl;
				}
				m_ComandosTerminados.erase(it3);
			} else {
				std::cerr << "Detectada inconsistencia en el controlador de comandos: Comando desreferenciado. Flujo de comando perdido." << std::endl;
			}
		}
	}
	// END Modificación del estado interno del controlador de comandos.
	//---------------------------------------------------------------------
	//---------------------------------------------------------------------
	while (wqueue.NotEmpty()) {
		if (!wqueue.Wait(500)) {
			wqueue.TerminarPendientes( );
		}
	}
}

void GNC::ControladorComandos::AbortarComandosDeOwner(void * owner)
{

	GNC::GCS::WaitQueue wqueue;

	{
		GNC::GCS::ILocker locker(this);
		// Recorremos la lista de threads_ids de la vista
		MapaOwners::iterator it1 = m_MapaOwners.find(owner);
		MapaComandos::iterator itcl;
		if (it1 != m_MapaOwners.end()) {
			for (ListaHilos::iterator it2 = (*it1).second.begin(); it2 != (*it1).second.end(); ++it2) {
				long threadId = (*it2);
				// Buscamos el id en la lista de comandos lanzados
				itcl = m_ComandosLanzados.find(threadId);
				if (itcl != m_ComandosLanzados.end()) { // El comando esta lanzado
					LanzadorComandos* pLanzador = (*itcl).second;
					if (pLanzador != NULL) { //

						wqueue.RegistrarEspera(pLanzador);
						pLanzador->Terminar();

						std::cerr << "Registrando espera para tarea: threadId = " << (unsigned long) threadId << " ptr = " << pLanzador << std::endl;
					} else {
						std::cerr << "Detectada inconsistencia en el controlador de comandos: Comando lanzado desreferenciado. Flujo de comando perdido." << std::endl;
					}
				} else { // Buscamos el id en la lista de comandos terminados
					MapaComandosTerminados::iterator it3 = m_ComandosTerminados.find(threadId);
					if (it3 != m_ComandosTerminados.end()) {
						GNC::GCS::IComando* pComando = (*it3).second;
						if (pComando != NULL) {
							std::cerr << "Anulando comando terminado: threadId = " << (unsigned long) threadId << std::endl;
							pComando->Abort();
							delete pComando;
						} else {
							std::cerr << "Detectada inconsistencia en el controlador de comandos: Comando terminado nulo." << std::endl;
						}
						m_ComandosTerminados.erase(it3);
					} else {
						std::cerr << "Detectada inconsistencia en el controlador de comandos: Comando desreferenciado. Flujo de comando perdido." << std::endl;
					}
				}
			}
			m_MapaOwners.erase(it1);
		}
	}

	while (wqueue.NotEmpty()) {
		if (!wqueue.Wait(500)) {
			wqueue.TerminarPendientes();
		}
	}	
}

void GNC::ControladorComandos::AbortarComandosDeOwnerAsincrono(void * owner)
{
	GNC::GCS::ILocker locker(this);
	// Recorremos la lista de threads_ids de la vista
	MapaOwners::iterator it1 = m_MapaOwners.find(owner);
	if (it1 != m_MapaOwners.end()) {
		for (ListaHilos::iterator it2 = (*it1).second.begin(); it2 != (*it1).second.end(); ++it2) {
			long threadId = (*it2);
			// Buscamos el id en la lista de comandos lanzados
			MapaComandos::iterator it = m_ComandosLanzados.find(threadId);
			if (it != m_ComandosLanzados.end()) { // El comando esta lanzado
				LanzadorComandos* pLanzador = (*it).second;
				if (pLanzador != NULL) { //
					pLanzador->Terminar();
				} else {
					std::cerr << "Detectada inconsistencia en el controlador de comandos: Comando lanzado desreferenciado. Flujo de comando perdido." << std::endl;
				}
			} else { // Buscamos el id en la lista de comandos terminados
				MapaComandosTerminados::iterator it3 = m_ComandosTerminados.find(threadId);
				if (it3 != m_ComandosTerminados.end()) {
					GNC::GCS::IComando* pComando = (*it3).second;
					if (pComando != NULL) {
						std::cerr << "Anulando comando terminado: threadId = " << (unsigned long) threadId << std::endl;
						pComando->Abort();
						delete pComando;
					} else {
						std::cerr << "Detectada inconsistencia en el controlador de comandos: Comando terminado nulo." << std::endl;
					}
					m_ComandosTerminados.erase(it3);
				} else {
					std::cerr << "Detectada inconsistencia en el controlador de comandos: Comando desreferenciado. Flujo de comando perdido." << std::endl;
				}
			}
		}
		m_MapaOwners.erase(it1);
	}
}

void GNC::ControladorComandos::WaitToOwnerCommands(void* owner)
{
	GNC::GCS::WaitQueue wqueue;

	{
		GNC::GCS::ILocker locker(this);
		// Recorremos la lista de threads_ids de la vista
		MapaOwners::iterator it1 = m_MapaOwners.find(owner);
		MapaComandos::iterator itcl;
		if (it1 != m_MapaOwners.end()) {
			for (ListaHilos::iterator it2 = (*it1).second.begin(); it2 != (*it1).second.end(); ++it2) {
				long threadId = (*it2);
				// Buscamos el id en la lista de comandos lanzados
				itcl = m_ComandosLanzados.find(threadId);
				if (itcl != m_ComandosLanzados.end()) { // El comando esta lanzado
					LanzadorComandos* pLanzador = (*itcl).second;
					if (pLanzador != NULL) { //

						wqueue.RegistrarEspera(pLanzador);
						pLanzador->Terminar();

						std::cerr << "Registrando espera para tarea: threadId = " << (unsigned long) threadId << " ptr = " << pLanzador << std::endl;
					} else {
						std::cerr << "Detectada inconsistencia en el controlador de comandos: Comando lanzado desreferenciado. Flujo de comando perdido." << std::endl;
					}
				}
			}
		}
	}

	while (wqueue.NotEmpty()) {
		if (!wqueue.Wait(500)) {
		}
	}	
}

unsigned int GNC::ControladorComandos::GetNumActiveCommands() {
	return m_ComandosLanzados.size();
}

void GNC::ControladorComandos::OnComandoLanzado(long threadId)
{

	GNC::GCS::ILocker locker(this);

	MapaComandos::iterator it = m_ComandosLanzados.find(threadId);
	if (it != m_ComandosLanzados.end()) {
		LanzadorComandos* pLanzador = (*it).second;
		pLanzador->m_pComando->SetNotificadorProgreso(pLanzador);
		if (m_pProgreso) {
			m_pProgreso->InsertarTarea(threadId, pLanzador->m_pComando->GetName());
		}
		GNC::GCS::IEventsController::Instance()->ProcesarEvento(new GNC::GCS::Events::EventoProgresoComando(pLanzador->m_pComando, GNC::GCS::Events::EventoProgresoComando::TEP_Iniciado, 0.0f, pLanzador->m_pComando->GetName()));
	}
	else {
		MapaComandosTerminados::iterator it = m_ComandosTerminados.find(threadId);
		if (it != m_ComandosTerminados.end()) {
			GNC::GCS::IComando* pComando = (*it).second;
			if (m_pProgreso) {
				m_pProgreso->InsertarTarea(threadId, pComando->GetName());
			}
			GNC::GCS::IEventsController::Instance()->ProcesarEvento(new GNC::GCS::Events::EventoProgresoComando(pComando, GNC::GCS::Events::EventoProgresoComando::TEP_Iniciado, 1.0f, pComando->GetName()));
		}
		else
		{
			LOG_WARN("ControladorComandos", "Error al iniciar comunicacion de progreso del comando. Thread Id no encontrado.");
			//std::cout << "OnComandoLanzado: Thread Id not found: " << threadId << std::endl;
		}
	}
}

void GNC::ControladorComandos::OnComandoProgreso(long threadId)
{
	GNC::GCS::ILocker locker(this);

	MapaComandos::iterator it = m_ComandosLanzados.find(threadId);
	if (it != m_ComandosLanzados.end()) {
		LanzadorComandos* pLanzador = (*it).second;
		pLanzador->LockProgreso();
		float progreso = pLanzador->GetProgresoNormalizado();
		std::string texto = pLanzador->GetTextoProgreso();
		pLanzador->UnLockProgreso();
		m_pProgreso->SetProgresoTarea(threadId, progreso, texto);
		GNC::GCS::IEventsController::Instance()->ProcesarEvento(new GNC::GCS::Events::EventoProgresoComando(pLanzador->m_pComando, GNC::GCS::Events::EventoProgresoComando::TEP_Progreso, progreso, texto));
	}
	else {
		//std::cout << "OnComandoProgreso: Thread Id not found: " << threadId << std::endl;
	}

}

void GNC::ControladorComandos::OnComandoFinalizado(long threadId, bool lock)
{
	GNC::GCS::IComando* pComando = NULL;

	bool actualizar=false;

	GNC::GCS::ILocker* pLocker = NULL;

	//LOG_TRACE("ControladorComandos", "OnComandoFinalizado(" << threadId << ")");

	{
		if (lock) {
			pLocker = new GNC::GCS::ILocker(this);
		}
		try {
			if(m_pProgreso != NULL){
				m_pProgreso->EliminarTarea(threadId);
			}

			MapaComandosTerminados::iterator it1 = m_ComandosTerminados.find(threadId);
			if (it1 != m_ComandosTerminados.end()) {
				actualizar = true;
				pComando = (*it1).second;
				m_ComandosTerminados.erase(it1);
			}
			else {
				//LOG_TRACE("ControladorComandos", "Id thread no encontrado en finalizados");
			}


			// TODO: Añadir un diccionario inverso o usar un set
			for (MapaOwners::iterator it2 = m_MapaOwners.begin(); it2 != m_MapaOwners.end(); ++it2) {
				ListaHilos::iterator it3 = (*it2).second.begin();
				bool found = false;
				while (!found && it3 != (*it2).second.end()) {
					if ((*it3) == threadId) {
						found = true;
					}
					else {
						++it3;
					}
				}
				if (found) {
					(*it2).second.erase(it3);
				}
			}
		}
		catch (std::exception&) {
			throw;
		}

		if (pLocker != NULL)
		{
			delete pLocker;
			pLocker = NULL;
		}
	}

	if (pComando != NULL)
	{
		if (actualizar && !pComando->EstaAbortado()) {
			pComando->Update();
			//if command is persistent... drop from bbdd
			GNC::GCS::IPersistentCommand* pPersistent = dynamic_cast<GNC::GCS::IPersistentCommand*>(pComando);
			if (pPersistent != NULL) {
				GNC::GCS::HistoryController::Instance()->SaveTask(pPersistent);
			}
		}
		else {
			LOG_DEBUG("ControladorComandos" , "IComando::Update no invocado");
		}
		//LOG_TRACE("ControladorComandos", "Procesando evento de comando finalizado");
		GNC::GCS::IEventsController::Instance()->ProcesarEvento(new GNC::GCS::Events::EventoProgresoComando(pComando, GNC::GCS::Events::EventoProgresoComando::TEP_Finalizado));
		delete pComando;
	}
	else {
		LOG_WARN("ControladorComandos", "Comando nulo. no se propagara el evento de fin de comando ni se actualizara");
		//std::cout << "ControladorComandos>> pComando = NULL!!!!" << std::endl;
	}

}

GNC::ControladorComandos::ListaNombreComandos GNC::ControladorComandos::GetComandosActivos()
{
	ListaNombreComandos lista;
	GNC::GCS::ILocker locker(this);
	for(MapaComandos::iterator it = m_ComandosLanzados.begin(); it!=m_ComandosLanzados.end(); ++it) {
		std::stringstream strstream;
		strstream << (*it).second->m_pComando->GetName() << ": " << (*it).second->GetTextoProgreso();
		lista.push_back( strstream.str());
	}
	return lista;
}

//endregion
