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

#define N 10

typedef struct vozilo{

    long id;
    int tip_vozila; //automobil-0, autobus-1, kamion-2, hitno vozilo-3 
}Vozilo;

pthread_mutex_t mutex;
pthread_cond_t cond;
int vozila_u_tunelu=0;

void *work(void *arg){

    Vozilo *thr_podaci=(Vozilo*)arg;
    int tip_vozila = thr_podaci->tip_vozila;
    int kamion_u_tunelu=0;

    int smer = rand() % 2; 
    int prioritet = -1;

    pthread_mutex_lock(&mutex);
    while((vozila_u_tunelu>0 && smer!=(1-smer)) || prioritet==1  || kamion_u_tunelu==1 || (tip_vozila==0 && vozila_u_tunelu>3)) pthread_cond_wait(&cond,&mutex);

    if(thr_podaci->tip_vozila == 3){ //hitno vozilo

        vozila_u_tunelu++;
        prioritet=1;
        pthread_mutex_unlock(&mutex);

        sleep(2);
  
        pthread_mutex_lock(&mutex);
        vozila_u_tunelu--;
        if(prioritet==1) prioritet = -1;
        if(vozila_u_tunelu==0) smer = (1-smer); 
        pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&mutex);

        printf("Hitno vozilo %ld je proslo kroz tunel iz smera %s.\n", thr_podaci->id, smer? "jug" : "sever");
        return NULL;
    }
    else if(thr_podaci->tip_vozila == 2){//kamion
        vozila_u_tunelu++;
        kamion_u_tunelu=1;
        prioritet=0;
        pthread_mutex_unlock(&mutex);
        
        sleep(2);

        pthread_mutex_lock(&mutex);
        vozila_u_tunelu--;
        if(prioritet==0) prioritet = -1;
        if(vozila_u_tunelu==0) smer = (1-smer);
        if(kamion_u_tunelu==1){
            kamion_u_tunelu=0;
            pthread_cond_broadcast(&cond);
        }
        pthread_mutex_unlock(&mutex);

        printf("Kamion %ld je prosao kroz tunel iz smera %s.\n", thr_podaci->id, smer? "jug" : "sever");
        return NULL;
    }
    else if(thr_podaci->tip_vozila == 1){ //autobus
        vozila_u_tunelu++;
        prioritet=0;
        pthread_mutex_unlock(&mutex);

        sleep(2);

        pthread_mutex_lock(&mutex);
        vozila_u_tunelu--;
        if(prioritet==0) prioritet = -1;
        if(vozila_u_tunelu==0) smer = (1-smer);
        pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&mutex);

        printf("Autobus %ld je prosao kroz tunel iz smera %s.\n", thr_podaci->id, smer? "jug" : "sever");
        return NULL;
    }
    else{//automobil
        vozila_u_tunelu++;
        prioritet=0;
        pthread_mutex_unlock(&mutex);

        sleep(2);

        pthread_mutex_lock(&mutex);
        vozila_u_tunelu--;
        if(prioritet==0) prioritet = -1;
        if(vozila_u_tunelu==0) smer = (1-smer);
        pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&mutex);

        printf("Automobil %ld je prosao kroz tunel iz smera %s.\n", thr_podaci->id, smer? "jug" : "sever");
        return NULL;
    }
}

int main(){

    srand(time(NULL));
    
    pthread_t *niti=malloc(N*sizeof(pthread_t));
    Vozilo *niti_podaci=malloc(N*sizeof(Vozilo));

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

    for(long i=0; i<N; i++){

        niti_podaci[i].id = (i+1);
        niti_podaci[i].tip_vozila = rand() % 4;
    }

    for(long i=0; i<N; i++){
        pthread_create(&niti[i],NULL,work,&niti_podaci[i]);
    }

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

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    free(niti_podaci);
    free(niti);

    return 0;
}