#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<unistd.h>
#include<pthread.h>

#define NUM_THREADS 20
int tipVozila[NUM_THREADS];
int smerVozila = -1;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int brAuta, brAutobusa, brKamiona, brHitnihVozila, brHVCeka = 0;
int brJug, brSever = 0;
int nekoCekao = 0;

void ispisiVozilo(int id, int idVozila, int idSmera) {
    if(idVozila == 0)
    {
        if(idSmera == 0)
        {
            printf("Vozilo %d je automobil i dolazi sa juga\n", id);
        } else printf("Vozilo %d je automobil i dolazi sa severa\n", id);
    }
    else if(idVozila == 1)
    {
        if(idSmera == 0)
        {
            printf("Vozilo %d je autobus i dolazi sa juga\n", id);
        } else printf("Vozilo %d je autobus i dolazi sa severa\n", id);
    }
    else if(idVozila == 2)
    {
        if(idSmera == 0)
        {
            printf("Vozilo %d je kamion i dolazi sa juga\n", id);
        } else printf("Vozilo %d je kamion i dolazi sa severa\n", id);
    }
    else
    {
        if(idSmera == 0)
        {
            printf("Vozilo %d je hitno vozilo i dolazi sa juga\n", id);
        } else printf("Vozilo %d je hitno vozilo i dolazi sa severa\n", id);
    }
}

void prosloVozilo(int id, int idVozila, int idSmera) {
    if(idVozila == 0)
    {
        if(idSmera == 0)
        {
            printf("Vozilo %d je automobil i dolazi sa juga je proslo\n", id);
        } else printf("Vozilo %d je automobil i dolazi sa severa je proslo\n", id);
    }
    else if(idVozila == 1)
    {
        if(idSmera == 0)
        {
            printf("Vozilo %d je autobus i dolazi sa juga je proslo\n", id);
        } else printf("Vozilo %d je autobus i dolazi sa severa je proslo\n", id);
    }
    else if(idVozila == 2)
    {
        if(idSmera == 0)
        {
            printf("Vozilo %d je kamion i dolazi sa juga je proslo\n", id);
        } else printf("Vozilo %d je kamion i dolazi sa severa je proslo\n", id);
    }
    else
    {
        if(idSmera == 0)
        {
            printf("Vozilo %d je hitno vozilo i dolazi sa juga je proslo\n", id);
        } else printf("Vozilo %d je hitno vozilo i dolazi sa severa je proslo\n", id);
    }
}

void *jug(void *tid)
{
    long id = (long)tid;

    sleep(rand() % 5);
    ispisiVozilo(id, tipVozila[id], 0);
    // printf("PRE\n");
    // printf("TIP VOZILA %d\n", tipVozila[id]);
    // printf("SMER %d\n", smerVozila);
    // printf("brAUTA %d\n", brAuta);
    // printf("brAutobusa %d\n", brAutobusa);
    // printf("brKamiona %d\n", brKamiona);
    // printf("brHitnihVozila %d\n", brHitnihVozila);
    // printf("brHVCeka %d\n", brHVCeka);
    // printf("brJug %d\n", brJug);
    // printf("brSever %d\n", brSever);
    
    pthread_mutex_lock(&mutex);
    if(smerVozila == -1)
        smerVozila = 0;
    
    while((tipVozila[id] == 0 && (brAuta > 3 || smerVozila == 1 || brKamiona > 0 || brHVCeka > 0)) || (tipVozila[id] == 1 && (brAutobusa > 0 || smerVozila == 1 || brKamiona > 0 || brHVCeka > 0)) || (tipVozila[id] == 2 && (smerVozila == 1 || brKamiona > 0 || brHVCeka > 0)) || (tipVozila[id] == 3 && (smerVozila == 1 || brKamiona > 0)))
    {       
        printf("vozilo %ld ceka\n", id);
        pthread_cond_wait(&cond, &mutex);
    }
    if(tipVozila[id] == 0)
        brAuta++;
    if(tipVozila[id] == 1)
        brAutobusa++;
    if(tipVozila[id] == 2)
        brKamiona++;
    if(tipVozila[id] == 3)
    {
        brHitnihVozila++;
    }
    brJug++;
    pthread_mutex_unlock(&mutex);

    printf("Vozilo %ld je pocelo da prelazi tunel\n", id);
    sleep(rand() % 3);
    
    
    pthread_mutex_lock(&mutex);
    prosloVozilo(id, tipVozila[id], 0);
    if(tipVozila[id] == 0)
        brAuta--;
    if(tipVozila[id] == 1)
        brAutobusa--;
    if(tipVozila[id] == 2)
        brKamiona--;
    if(tipVozila[id] == 3)
    {
        brHitnihVozila--;
    }
        
    brJug--;

    if(brJug == 0)
    {
        smerVozila = 1;
    }
    pthread_cond_broadcast(&cond);
    pthread_mutex_unlock(&mutex);

    // printf("brjug: %d, brSever: %d, smer: %d\n", brJug, brSever, smerVozila);
    // printf("brojAuta: %d, brojAutobusa: %d, brojKamiona: %d, brojHitnihVozila: %d, brHV: %d\n", brAuta, brAutobusa, brKamiona, brHitnihVozila, brHVCeka);
}


void *sever(void *tid)
{
    long id = (long)tid;
    ispisiVozilo(id, tipVozila[id], 1);
    // printf("PRE\n");
    // printf("TIP VOZILA %d\n", tipVozila[id]);
    // printf("SMER %d\n", smerVozila);
    // printf("brAUTA %d\n", brAuta);
    // printf("brAutobusa %d\n", brAutobusa);
    // printf("brKamiona %d\n", brKamiona);
    // printf("brHitnihVozila %d\n", brHitnihVozila);
    // printf("brHVCeka %d\n", brHVCeka);
    // printf("brJug %d\n", brJug);
    // printf("brSever %d\n", brSever);
    
    pthread_mutex_lock(&mutex);
    if(smerVozila == -1)
        smerVozila = 1;
    while((tipVozila[id] == 0 && (brAuta > 3 || smerVozila == 0 || brKamiona > 0 || brHVCeka > 0)) || (tipVozila[id] == 1 && (brAutobusa > 0 || smerVozila == 0 || brKamiona > 0 || brHVCeka > 0)) || (tipVozila[id] == 2 && (smerVozila == 0 || brKamiona > 0 || brHVCeka > 0)) || (tipVozila[id] == 3 && (smerVozila == 0 || brKamiona > 0)))
    {  
        printf("vozilo %ld ceka\n", id);
        pthread_cond_wait(&cond, &mutex);
    }
        
    if(tipVozila[id] == 0)
        brAuta++;
    if(tipVozila[id] == 1)
        brAutobusa++;
    if(tipVozila[id] == 2)
        brKamiona++;
    if(tipVozila[id] == 3)
    {
        brHitnihVozila++;
    }
        
    brSever++;
    pthread_mutex_unlock(&mutex);

    printf("Vozilo %ld je pocelo da prelazi tunel\n", id);
    sleep(rand() % 3);

    
    pthread_mutex_lock(&mutex);
    prosloVozilo(id, tipVozila[id], 1);
    if(tipVozila[id] == 0)
        brAuta--;
    if(tipVozila[id] == 1)
        brAutobusa--;
    if(tipVozila[id] == 2)
        brKamiona--;
    if(tipVozila[id] == 3)
        brHitnihVozila--;
    brSever--;

    if(brSever == 0)
    {
        smerVozila = 0;
    }
    pthread_cond_broadcast(&cond);
    pthread_mutex_unlock(&mutex);

    // printf("brjug: %d, brSever: %d, smer: %d\n", brJug, brSever, smerVozila);
    // printf("brojAuta: %d, brojAutobusa: %d, brojKamiona: %d, brojHitnihVozila: %d, brHV: %d\n", brAuta, brAutobusa, brKamiona, brHitnihVozila, brHVCeka);
}


int main() {
    pthread_t threads[NUM_THREADS];
    srand(time(NULL));
    long t;
    for(t=0; t<NUM_THREADS; t++)
    {
        int vozilo = rand() % 4;
        tipVozila[t] = vozilo;
        
        if(vozilo == 0)
        {
            int smer = rand() % 2;
            if(smer == 0)
                {
                    pthread_create(threads + t, NULL, sever, (void*)t);
                } 
                else
                {
                    pthread_create(threads + t, NULL, jug, (void*)t);
                }
        }
        else if(vozilo == 1)
        {
            int smer = rand() % 2;
            if(smer == 0)
                {
                    pthread_create(threads + t, NULL, sever, (void*)t);
                } 
                else
                {
                    pthread_create(threads + t, NULL, jug, (void*)t);
                }
        } 
        else if(vozilo == 2)
        {
            int smer = rand() % 2;
            if(smer == 0)
                {
                    pthread_create(threads + t, NULL, sever, (void*)t);
                } 
                else
                {
                    pthread_create(threads + t, NULL, jug, (void*)t);
                }
        } 
        else
        {
            int smer = rand() % 2;
            if(smer == 0)
                {
                    pthread_create(threads + t, NULL, sever, (void*)t);
                } 
                else
                {
                    pthread_create(threads + t, NULL, jug, (void*)t);
                }
        }
    }

    for(t = 0; t<NUM_THREADS; t++)
    {
        pthread_join(threads[t], NULL);
    }

    pthread_exit(NULL);
}