#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>

#define MSG_SZ 1024
#define NUM_FILOSOFOS 5
#define IZQUIERDO 0
#define DERECHO 1
#define LIBRE 0
#define OCUPADO 1

int fds[NUM_FILOSOFOS];
/*

*/
int tenedores[NUM_FILOSOFOS] = { LIBRE,LIBRE,LIBRE,LIBRE,LIBRE};
pthread_mutex_t  locks[NUM_FILOSOFOS];

void dormir(int id) {
    char msg[MSG_SZ];
    int tiempo = rand();
    tiempo %= 10;
    sprintf(msg,"Filosofo %d durmiendo %d segundos ...\n",id,tiempo);
    write(fds[id],msg,strlen(msg));
    sleep(tiempo);
    return;
}

void obtener_tenedor(int id,int tipo) {
    char msg[MSG_SZ];
    int indice ;
#ifdef MUTEX
    pthread_mutex_lock (&locks[indice]);
#endif
    if ( tipo == IZQUIERDO ) {
      indice = id+IZQUIERDO;  
    } else if (tipo == DERECHO ) {
      indice = (id+DERECHO)%NUM_FILOSOFOS;
    }
    tenedores[indice] = OCUPADO;
    sprintf(msg,"Filosofo %d OCUPANDO tenedor %d\n",id,indice);
    write(fds[id],msg,strlen(msg));
}

void liberar_tenedor(int id,int tipo) {
    int indice ;
    char msg[MSG_SZ];
    if ( tipo == IZQUIERDO ) {
      indice = id+IZQUIERDO;  
    } else if (tipo == DERECHO ) {
      indice = (id+DERECHO)%NUM_FILOSOFOS;
    }
    tenedores[indice] = LIBRE;
    sprintf(msg,"Filosofo %d LIBERANDO tenedor %d\n",id,indice);
    write(fds[id],msg,strlen(msg));
#ifdef MUTEX
    pthread_mutex_unlock (&locks[indice]);
#endif
}

void comer(int id ) {
   char msg[MSG_SZ];
   int tiempo = rand();
   tiempo %= 10;
   sprintf(msg,"Filosofo %d comiendo por %d segundos...\n",id,tiempo);
   write(fds[id],msg,strlen(msg));
   sleep(tiempo);

}
void * existir(void *param) {
   char msg[MSG_SZ];
   int fin =0;
   int id =  (int)param;
   sprintf(msg,"Filosofo %d existiendo\n" ,id);
   write(fds[id],msg,strlen(msg));
   while (!fin) {
      dormir(id);
      obtener_tenedor(id,IZQUIERDO);
      obtener_tenedor(id,DERECHO);
      comer(id);
      liberar_tenedor(id,IZQUIERDO);
      liberar_tenedor(id,DERECHO);
   } 
   pthread_exit((void *)0);
}
int main(int argc, char * argv[]) {
   pthread_t threads[NUM_FILOSOFOS]; /*arreglo de hilos*/
   int t;
   int idthread;
   int fd;
   unlink("filosofos.log");
   fd=open("filosofos.log",O_WRONLY|O_CREAT,S_IRUSR | S_IWUSR | S_IRGRP);
   if (fd < 0) {
     perror("Error al abrir log");
     exit(-1);
   }
   for (t=0;t<NUM_FILOSOFOS;t++) {
     fds[t] = dup(fd);
   }
   close(fd);

   #ifdef MUTEX
   printf("Ejecutando con control de concurrencia\n");
   for (t=0;t<NUM_FILOSOFOS;t++) {
     pthread_mutex_init(&locks[t],0);
   }
   #endif
   for (t=0;t<NUM_FILOSOFOS;t++) {
      idthread = pthread_create(&threads[t],(pthread_attr_t *)0,existir,(void *)t);       
      if ( idthread ) { perror(" pthread_create"); exit(-1); }
   }
   pthread_exit((void *)0);
}
