void handler(int sig){
  printf("\nCTRL+C captured\n");
  printf("Terminating processes & set free resources\n");
  finalizarProcesos();
  liberarRecursos();
  _exit(EXIT_SUCCESS);
}
void AdministradorGeneral::run(int cantidadDeLugares, float costoHora, int tiempoEjecucion,int cantidadEstacionamientos)
{
	// Genero un vector dinamico y lo inicializo para evitar los warning de compilador y de valgrind
	char recibido[BUFFSIZE];
	int q;

	for (q=0; q<BUFFSIZE; q++) {
		recibido[q] = 0;
	}

	stringstream mensajeLog;


	//Inicializa el tiempo en el cronometro y arranca el tiempo a correr en la simulacion
	Cronometro::obtenerCronometro()->setTiempoASimular(tiempoEjecucion);
	Cronometro::obtenerCronometro()->iniciarTiempo();

	cout << "Inicio de la simulacion..." << endl;

	//Crea las memorias compartidas asociadas a cada uno de los estacionamientos y los
	//vectores de posiciones libres
	this->inicializaciones(cantidadEstacionamientos,cantidadDeLugares);

	Cola<mensaje> colaMensajes( (char*)ARCHIVO_COLA_MENSAJES,'a');

	// Creo otra cola para las consultas, cada estacionamiento va a tener un proceso escuchando esta cola
	Cola<mensaje> colaConsultas( (char*)ARCHIVO_COLA_MENSAJES_CONSULTAS,'a');

	// cantidadEstacionamientos+1 es el valor que va a filtrar el proceso ppal para recibir mensajes
	int msjPpal = cantidadEstacionamientos+1;

	this->pConsola = fork();

	if( this->pConsola != 0)
	{

		// Guardo los pids de los estacionamientos
		pid_t pEstacionamientos[cantidadEstacionamientos];

		Log::getInstance()->loguear("Soy el proceso principal - el Administrador General");
		for(int i=1;i<=cantidadEstacionamientos;i++)
		{
			this->totalSumatoriaEstacionamientos+=i;
			pid_t pEstacionamiento = fork();

			if(pEstacionamiento == 0)
			{
				Estacionamiento estacionamiento(i, msjPpal);
				estacionamiento.run(cantidadDeLugares,costoHora,tiempoEjecucion);
				Cronometro::destruir();
				return;
			} else {
				mensajeLog.str("");
				mensajeLog << "Estacionamiento " << i << " pid: " << pEstacionamiento;
				Log::getInstance()->loguear(mensajeLog.str());
				pEstacionamientos[i-1] = pEstacionamiento;
			}
		}
		//Soy el proceso administrador general

		// Variable para llevar el control del fin de la simulacion
		int sumatoriaEstacionamientosCerrados = 0;
		bool salir = false;

		while (!salir)
		{
			mensaje datoLeido;
			mensaje datoEnviado;
			colaMensajes.leer(msjPpal, &datoLeido);


			datoEnviado.from = msjPpal;
			datoEnviado.mtype = datoLeido.from;

			mensajeLog.str("");
			mensajeLog << "ProcPrincipal - acabo de recibir: " << datoLeido.msj;
			Log::getInstance()->loguear(mensajeLog.str());

			stringstream retorno;

			switch (datoLeido.msj[0])
			{

				case 'a': {
					Log::getInstance()->loguear("Ingreso una 'a' por consola");

					int fromOriginal = datoLeido.from;

					char * token = strtok(datoLeido.msj, "|");
					token = strtok(NULL, "|");

					int nroEstacionamiento = atoi(token);
					datoEnviado.mtype = nroEstacionamiento;

					stringstream consulta;
					consulta << "a";
					strcpy(datoEnviado.msj,(char*)consulta.str().c_str());

					// Aca tiene que mandar el msj a la cola de consultas
					colaConsultas.escribir(datoEnviado);

					colaConsultas.leer(msjPpal,&datoLeido);

					datoEnviado.mtype = fromOriginal;
					datoEnviado.from = msjPpal;

					retorno << "La cantidad actual de autos en el estacionamiento " << nroEstacionamiento << " es : " << datoLeido.msj;

					strcpy(datoEnviado.msj, retorno.str().c_str());
					colaMensajes.escribir(datoEnviado);
					break;
				}
				case 'm': {
					Log::getInstance()->loguear("Ingreso una 'm' por consola");

					int fromOriginal = datoLeido.from;

					char * token = strtok(datoLeido.msj, "|");
					token = strtok(NULL, "|");

					int nroEstacionamiento = atoi(token);
					datoEnviado.mtype = nroEstacionamiento;

					stringstream consulta;
					consulta << "m";
					strcpy(datoEnviado.msj,(char*)consulta.str().c_str());

					// Aca tiene que mandar el msj a la cola de consultas
					colaConsultas.escribir(datoEnviado);

					colaConsultas.leer(msjPpal,&datoLeido);

					datoEnviado.mtype = fromOriginal;
					datoEnviado.from = msjPpal;

					retorno << "El monto recaudado hasta el momento en el estacionamiento " << nroEstacionamiento << " es : " << datoLeido.msj;

					strcpy(datoEnviado.msj, retorno.str().c_str());
					colaMensajes.escribir(datoEnviado);
					break;
				}
				case 'q': {
					Log::getInstance()->loguear("Ingreso una 'q' por consola");

					retorno << "q";

					for(int i=1;i<=cantidadEstacionamientos;i++)
					{
						datoEnviado.mtype = i;
						strcpy(datoEnviado.msj,(char*)retorno.str().c_str());

						colaConsultas.escribir(datoEnviado);
					}

					salir = true;

					break;
				}
				case 'p': {
					char * token = strtok(datoLeido.msj, "|");
					token = strtok(NULL, "|");

					mensajeLog.str("");
					mensajeLog << "ProcPrincipal - Saco del vector de posiciones libres la posicion: " << token;
					Log::getInstance()->loguear(mensajeLog.str());

					int pos = atoi(token);

					// Elimino la posicion libre del estacionamiento correspondiente
					this->lugares[datoLeido.from-1].quitarPosicionLibre(pos);

					break;
				}
				case 'd': {
					char * token = strtok(datoLeido.msj, "|");
					token = strtok(NULL, "|");

					mensajeLog.str("");
					mensajeLog << "ProcPrincipal - Agrego al  vector de posiciones libres la posicion: " << token;
					Log::getInstance()->loguear(mensajeLog.str());

					int pos = atoi(token);

					// Agrego la posicion libre al estacionamiento correspondiente
					this->lugares[datoLeido.from-1].agregarPosicionLibre(pos);
					//this->agregarPosicionLibre(pos);

					break;
				}
				case 'f': {

					sumatoriaEstacionamientosCerrados+=datoLeido.from;

					mensajeLog.str("");
					mensajeLog << "ProcPrincipal - La suma del numero de estacionamientos cerrados es " << sumatoriaEstacionamientosCerrados;
					Log::getInstance()->loguear(mensajeLog.str());

					if(sumatoriaEstacionamientosCerrados == this->totalSumatoriaEstacionamientos)
					{
						cout << "Fin de la simulacion, ingrese 'q' para terminar el programa" << endl;
					}

					break;
				}
				case 'r': {

					int nroPosicion = this->lugares[datoLeido.from-1].getPosicionAleatoria();

					retorno << nroPosicion;
					strcpy(datoEnviado.msj,retorno.str().c_str());


					mensajeLog.str("");
					mensajeLog << "ProcPrincipal - Estacionamiento " << datoLeido.from << " pide una posicion, le envio: " << nroPosicion;
					Log::getInstance()->loguear(mensajeLog.str());

					colaMensajes.escribir(datoEnviado);

					break;
				}
				default: {

					cout << "Comando invalido! Ingrese 'a' seguido del nro de estacionamiento para ver la cantidad de autos estacionados, ";
					cout << "'m' seguido del nro de estacionamiento para conocer el monto recaudado ";
					cout << " o 'q' para finalizar el programa" << endl;
					break;
				}
			}
		}

		int estado;
		for(int i=0;i<cantidadEstacionamientos;i++)
		{
			waitpid(pEstacionamientos[i],&estado,0);

			mensajeLog.str("");
			mensajeLog << "Liberado el estacionamiento... " << i+1 << " pid: " << pEstacionamientos[i];
			Log::getInstance()->loguear(mensajeLog.str());

		}
		waitpid(this->pConsola, &estado,0);

		colaMensajes.destruir();
		colaConsultas.destruir();
		liberarRecursos(cantidadEstacionamientos,cantidadDeLugares);
	}
	else
	{

		// cantidadEstacionamientos+2 es el mtype para la consola
		int msjConsola = cantidadEstacionamientos+2;

		// Proceso consola
		stringstream mensajeLog;
		mensajeLog << "Soy el proceso consola esperando el ingreso por pantalla.";
		Log::getInstance()->loguear(mensajeLog.str());

		mensaje datoEnviar;
		mensaje datoLeer;

		datoEnviar.mtype = msjPpal;
		datoEnviar.from = msjConsola;

		bool salir = false;
		// Para terminar el programa, el usuario debe escribir 'Q' o 'q'
		while (!salir) {


			cout << "Ingrese un comando: ( 'a' seguido del nro de estacionamiento para averiguar la cantidad de autos estacionados ";
			cout << "o 'm' seguido del nro de estacionamiento para averiguar el monto recaudado )" << endl;
			cin.getline(recibido, BUFFSIZE);

			char * primerParametro = strtok(recibido, " ");


			stringstream ssRecibido;
			char letra = tolower(primerParametro[0]);
			ssRecibido << letra << "|";

			// Valido las opciones de entrada
			if (letra == 'a' || letra == 'm' || letra == 'q' ) {

				char * segundoParametro = strtok(NULL, " ");
				int nroEstacionamiento = 0;
				if (segundoParametro!=NULL){
					nroEstacionamiento = atoi((char*)segundoParametro);
					ssRecibido << nroEstacionamiento;
				}

				if (nroEstacionamiento <= cantidadEstacionamientos) {

					strcpy(datoEnviar.msj,ssRecibido.str().c_str());

					colaMensajes.escribir(datoEnviar);

					if (letra != 'q') {
						colaMensajes.leer(msjConsola,&datoLeer);

						cout << datoLeer.msj << endl;
					} else {
						salir = true;
					}
				} else {
					cout << "Numero de estacionamiento invalido, debe ser menor o igual a " << cantidadEstacionamientos << endl;
				}

			} else {
				cout << "Comando invalido." << endl;
			}

		}

		mensajeLog.str("");
		mensajeLog << "Consola - Termina el proceso: " << getpid() << " (consola)";
		Log::getInstance()->loguear(mensajeLog.str());

	}

	Cronometro::destruir();
}
int perderVida(bool porDeadlock) {
	if (sacarVida(personaje) > 0) {
		if (porDeadlock) {
			log_debug(logger, "El personaje %s perdio una vida, ahora le quedan (%d), causa:DEADLOCK", personaje->nombre, personaje->vidas);
		} else {
			log_debug(logger, "El personaje %s perdio una vida, ahora le quedan (%d) causa:SIGTERM", personaje->nombre, personaje->vidas);
		}

		if (!porDeadlock) {
			log_debug(logger, "Notificando muerte al planificador. Personaje:%s", personaje->nombre);
			notificarMuerte(socketPlanificador);
			esperarConfirmacionDelPlanificador(socketPlanificador);
			log_debug(logger, "Notifico la liberacion de recursos. Personaje:%s", personaje->nombre);
			liberarRecursos(socketNivel);
		} else if (porDeadlock) {
			MPS_MSG* mensajeAEnviar = malloc(sizeof(MPS_MSG));
			mensajeAEnviar->PayloadDescriptor = MUERTE_POR_DEADLOCK;
			mensajeAEnviar->PayLoadLength = sizeof(char);
			mensajeAEnviar->Payload = personaje->simbolo;
			log_debug(logger, "Notifico muerte por deadlock al nivel. Personaje:%s", personaje->nombre);
			enviarMensaje(socketNivel, mensajeAEnviar);
			free(mensajeAEnviar);
		}
		MPS_MSG* mensajeARecibir = malloc(sizeof(MPS_MSG));
		recibirMensaje(socketNivel, mensajeARecibir);
		if (mensajeARecibir->PayloadDescriptor != MUERTE_CORRECTA) {
			return EXIT_FAILURE;
		}
		free(mensajeARecibir);
		close(socketPlanificador);
		close(socketNivel);
		int resultado = procesar();
		if (resultado == 1) {
			return EXIT_FAILURE;
		}
		finalizar();
	} else {
		if (porDeadlock) {
			log_debug(logger, "El personaje %s se quedo sin vidas, causa:DEADLOCK", personaje->nombre, personaje->vidas);
		} else {
			log_debug(logger, "El personaje %s se quedo sin vidas, causa:SIGTERM", personaje->nombre, personaje->vidas);
		}
		if (!porDeadlock) {
			log_debug(logger, "Notificando muerte al planificador. Personaje:%s", personaje->nombre);
			notificarMuerte(socketPlanificador);
			esperarConfirmacionDelPlanificador(socketPlanificador);
			log_debug(logger, "Notifico la liberacion de recursos. Personaje:%s", personaje->nombre);
			liberarRecursos(socketNivel);
		} else if (porDeadlock) {
			MPS_MSG* mensajeAEnviar = malloc(sizeof(MPS_MSG));
			mensajeAEnviar->PayloadDescriptor = MUERTE_POR_DEADLOCK;
			mensajeAEnviar->PayLoadLength = sizeof(char);
			mensajeAEnviar->Payload = personaje->simbolo;
			log_debug(logger, "Notifico muerte por deadlock al nivel. Personaje:%s", personaje->nombre);
			enviarMensaje(socketNivel, mensajeAEnviar);
			free(mensajeAEnviar);
		}
		MPS_MSG* mensajeARecibir = malloc(sizeof(MPS_MSG));
		recibirMensaje(socketNivel, mensajeARecibir);
		if (mensajeARecibir->PayloadDescriptor != MUERTE_CORRECTA) {
			return EXIT_FAILURE;
		}
		free(mensajeARecibir);
		close(socketPlanificador);
		close(socketNivel);
		int levantarConfig = levantarPersonaje(path);
		if (levantarConfig == 1) {
			return EXIT_FAILURE;
		}
		int resultado = procesar();
		if (resultado == 1) {
			return EXIT_FAILURE;
		}
		finalizar();
	}
	return EXIT_SUCCESS;
}
int main(int argc, char *argv[]){
  
  /* 5º Variables que necesita el programa */
  /* Ejemplo:
     FILE *fp...
     int nProcesos...
     char *patron */

  /* 6º Controlar el numero de argumentos */
  if(argc < /*DEPENDENCIA*/){
    fprintf(stderr,"Error, Use: programa ...\n");
    _exit(EXIT_FAILURE);
  }

  /* 7º Instalador del manejador de señal de CTRL+C */
  if(signal(SIGINT,handler) == SIG_ERR){
    fprintf(stderr,"Error in Installation of signal handler\n");
    _exit(EXIT_FAILURE);
  }

  /* 8º Reservar memoria para la tabla de procesos */
  g_pids = malloc(g_numProc * sizeof(struct TablaProcesos));

  /* 9º Creacion de procesos */
  /* Depende del tipo de programa
     algo que no se puede incluir en el esqueleto */
  /* EJEMPLO:
     fork()..exec()
     
     fork()
     .exec()
     .
     fork()
     exec()

     fork()
     .exec()
     ..fork()
     ..exec()

  /* 10º Esperar a que los procesos finalicen */
  /* Depende tambien del tipo de programa */

  /* EJEMPLO:
     Cuando solo los procesos de un tipo terminan:
     while(numProcesosA > 0)

     Cuando tenemos que esperar a que todos terminen:
     while(numProc > 0)

     Siempre hay que ir borrando los procesos de la tabla:
     g_pids[i].pid = 0; Ya que ningun proceso va a tener la pid = 0; */
  
  /* 11º Finalizar Procesos */
  finalizarProcesos();

  /* 12º Liberar Recursos */
  liberarRecursos();
  
  return EXIT_SUCCESS;

}