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

// 0 AUTO, 1 AUTOBUS, 2 KAMION, 3 HITNA

#define VOZILA 31   

pthread_mutex_t lock;
pthread_mutex_t cond;

int smer = 0; // 0 A, 1 B
int brojAuta = 0;
int brojAutobusa = 0;
int brojHitne = 0;
int kamionNaMostu = 0;

typedef struct
{
    int tip; 
    int smer;
    int id;
    
 } Vozilo;

void udjiUTunel(Vozilo v)
{
    pthread_mutex_lock(&lock);
    if(v.tip == 0) 
    {
        while (smer != 0 && smer != v.smer && brojAuta > 3) || kamionNaMostu
            pthread_cond_wait(&cond, &lock); 
    }

    else if(v.tip == 1)
    {
        while(smer !=0 && smer != v.smer && brojAutobusa > 0 ) || kamionNaMostu
            pthread_cond_wait(&cond, &lock);

    }

    else if(v.tip == 2)
    {
        while(brojAuta == 0 || brojAutobusa == 0 || brojHitne == 0) 
            pthread_cond_wait(&cond, &lock);
    }
    
    else if(v.tip == 3)
    {
        while (smer !=0 && smer != v.smer) || kamionNaMostu
            pthread_cond_wait(&regularWork);
    }

    if(v.tip == 0)
        smer = v.smer;

    brojAuta++;

    if(v.tip == 1)
        brojAutobusa++;

    if(v.tip == 2)
        kamionNaMostu = 1;

    if(v.tip == 3)
        brojHitne++;

    pthread_mutex_unlock(&lock); 

}

void izadjiIzTunela(Vozilo v)
{
    pthread_mutex_lock(&lock);

    brojAuta --;

    if(v.tip == 1)
        brojAutobusa--;

    if(v.tip == 2)
        kamionNaMostu = 0;

    if(v.tip == 3)
        brojHitne--;

    if(brojAuta == 0)
        smer = 0;

    pthread_cond_broadcast(&cond);
    pthread_mutex_unlock(&lock);
}

void* vozilo_thread(void* arg)
{
    Vozilo v = *(Vozilo*) arg;

    sleep(rand()% 4);

    udjiUTunel(v);
    sleep(3);
    izadjiIzTunela(v);

    return NULL;
}

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

    pthread_t niti[VOZILA];
    Vozilo vozila[VOZILA];

    pthread_mutex_init(&lock, NULL);
    pthread_cond_init(&cond, NULL);

    for (int i=0; i < VOZILA; i++)
    {
        vozila[i].id = i;
        vozila[i].tip = rand() % 4 + 1;
        vozila[i].smer = rand() % 2 + 1;

        pthread_create(&niti[i], NULL, vozilo_thread, &vozila[i]);

    }

    for (int i=0; i < VOZILA; i++)
    {
        pthread_join(niti[i], NULL);
    }

    pthread_mutex_destroy(&lock);
    pthread_cond_destroy(&cond);


    return 0;
}







