#include "CarreraHilos.h"

// Definición de variables globales
coche_t Coches[N_COCHES];
volatile int clasificacionFinal[N_COCHES];
volatile int posicion = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

/**
 * Simula el comportamiento de un coche en una carrera, ejecutado por un hilo.
 * 
 * La función representa la salida, recorrido (con tiempo aleatorio) y llegada de un coche,
 * actualizando de forma segura una clasificación global mediante un mutex.
 * 
 * @param arg Puntero a un objeto de tipo coche_t con información del coche (id y cadena).
 * @return void* Retorna NULL al finalizar el hilo.
 */
void *funcion_coche(void *arg)
{
    coche_t *pcoche = (coche_t *)arg;
    int aleatorio;
    unsigned int semilla = (pcoche->id) + pthread_self();

    printf("Salida de %s %d\n", pcoche->cadena, pcoche->id);
    fflush(stdout);

    aleatorio = rand_r(&semilla) % 10;
    sleep(aleatorio);

    printf("Llegada de %s %d\n", pcoche->cadena, pcoche->id);

    pthread_mutex_lock(&mutex);
    clasificacionFinal[posicion] = pcoche->id;
    posicion++;
    pthread_mutex_unlock(&mutex);

    pthread_exit(NULL);
}

/** 
 * Muestra un coche generado 
 * con codigo ASCII
 */
void mostrarMensajeAscii()
{
    printf("                       ____________________\n");
    printf("                     //|           |        \\\n");
    printf("                   //  |           |          \\\n");
    printf("      ___________//____|___________|__________()\\__________________\n");
    printf("    /__________________|_=_________|_=___________|_________________{}\n");
    printf("    [           ______ |           | .           | ==  ______      { }\n");
    printf("  __[__        /##  ##\\|           |             |    /##  ##\\    _{# }_\n");
    printf(" {_____)______|##    ##|___________|_____________|___|##    ##|__(______}\n");
    printf("             /  ##__##                              /  ##__##        \\\n");
    printf("----------------------------------------------------------------------------\n");
    printf("                          ¡Bienvenido a la carrera de coches!\n");
}

int main(void)
{
    mostrarMensajeAscii();
    pthread_t hilosCoches[N_COCHES];
    int i;

    printf("Se inicia proceso de creación de hilos...\n\n");
    printf("SALIDA DE COCHES\n");

    for (i = 0; i < N_COCHES; i++)
    {
        Coches[i].id = i;
        Coches[i].cadena = "Coche";

        if (pthread_create(&hilosCoches[i], NULL, funcion_coche, (void *)&Coches[i]) != 0)
        {
            perror("Error al crear hilo");
            exit(EXIT_FAILURE);
        }
    }

    printf("Proceso de creación de hilos terminado\n\n");

    for (i = 0; i < N_COCHES; i++)
    {
        if (pthread_join(hilosCoches[i], NULL) != 0)
        {
            perror("Error al esperar el hilo");
            exit(EXIT_FAILURE);
        }
    }

    // Mostramos la clasificación final
    printf("Clasificación final:\n");
    printf("+---------------------------------+\n");
    printf("| Posición |       Coche         |\n");
    printf("+---------------------------------+\n");
    for (i = 0; i < N_COCHES; i++)
    {
        printf("|    %2d    |     Coche %2d       |\n", i + 1, clasificacionFinal[i]);
    }
    printf("+---------------------------------+\n");

    return 0;
}
