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

#define N 10

#define AUTO 0
#define BUS 1
#define KAMION 2
#define HITNO 3 

int broj_auto = 0;
int broj_bus = 0;
int broj_kamion = 0;
int broj_vozila = 0;
int smer = -1;
int ceka_hitno = 0;

char* vozila[] = {"AUTO", "BUS", "KAMION", "HITNO"};

pthread_mutex_t mutex;
pthread_cond_t cv;

void prodji(int id, int moj_smer, int vrsta) {

    pthread_mutex_lock(&mutex);

    if (vrsta == HITNO)
        ceka_hitno++;

    if (vrsta == AUTO) {
        while ((broj_vozila > 0 && (moj_smer != smer)) 
        || broj_kamion > 0 
        || (broj_auto >= 3 && (moj_smer == smer)) 
        || (ceka_hitno > 0))
            pthread_cond_wait(&cv, &mutex);

        if (broj_vozila == 0) {
            smer = moj_smer;
        }

        broj_auto++;
        broj_vozila++;

    } else if (vrsta == BUS) {
        while ((broj_vozila > 0 && (moj_smer != smer)) 
        || broj_kamion > 0 
        || (broj_bus > 0 && (moj_smer == smer)) 
        || (ceka_hitno > 0))
            pthread_cond_wait(&cv, &mutex);

        if (broj_vozila == 0) {
            smer = moj_smer;
        }

        broj_bus++;
        broj_vozila++;

    } else if (vrsta == KAMION) {
        while (broj_vozila > 0
        || ceka_hitno > 0)
            pthread_cond_wait(&cv, &mutex);

        smer = moj_smer;
        broj_kamion++;
        broj_vozila++;

    } else {
        while ((broj_vozila > 0 && (moj_smer != smer)) 
        || broj_kamion > 0)
            pthread_cond_wait(&cv, &mutex);

        if (broj_vozila == 0) {
            smer = moj_smer;
        }

        ceka_hitno--;
        broj_vozila++;
    }

    printf("Nit %d vrsta %s moj smer %d trenutni smer %d --- ULAZIM\n", id, vozila[vrsta], moj_smer, smer);

    pthread_mutex_unlock(&mutex);

    sleep(rand()%5);

    pthread_mutex_lock(&mutex);

    if (vrsta == AUTO) {
        broj_auto--;
    } else if (vrsta == BUS) {
        broj_bus--;
    } else if (vrsta == KAMION) {
        broj_kamion--;
    }

    broj_vozila--;

    printf("Nit %d vrsta %s moj smer %d trenutni smer %d --- IZLAZIM\n", id, vozila[vrsta], moj_smer, smer);

    if (broj_vozila == 0) {
        smer = -1;
    }

    pthread_cond_broadcast(&cv);

    pthread_mutex_unlock(&mutex);
}

void* zadatak(void* arg) {

    int id = *(int *)arg;

    int moj_smer = rand() % 2;
    int vrsta = rand() % 4;

    sleep(rand()%5);

    printf("Nit %d vrsta %s smer %d --- CEKAM\n", id, vozila[vrsta], moj_smer);

    prodji(id, moj_smer, vrsta);

    return NULL;
}
 
int main() {
    srand(time(NULL));

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cv, NULL);

    pthread_t niti[N];
    int ids[N];

    for (int i = 0; i < N; i++) {
        ids[i] = i;
        pthread_create(&niti[i], NULL, zadatak, &ids[i]);
        printf("Nit %d --- KREIRAM\n", ids[i]);
    }

    for (int i = 0; i < N; i++) {
        pthread_join(niti[i], NULL);
        printf("Nit %d --- BRISEM\n", ids[i]);
    }

    return 0;
}