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

#define JUG 0
#define SEVER 1
#define NONE -1

#define N 10

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

int tunelSMER;
int autoTUNEL;
int busTUNEL;
int kamionTUNEL;
int hitnoTUNEL;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_auto = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_kamion = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_bus = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_hitnoVozilo = PTHREAD_COND_INITIALIZER;

void* prodjiTunel(void* arg){
    long ID = (long)arg;
    int tipVozila = rand()%4;
    int mojSMER = rand()%2;

    sleep(rand()%3);
    printf("\n-- ID:%ld -- TIP:%d -- SMER:%d\n",ID, tipVozila,mojSMER);

    if(tipVozila == AUTO){
        pthread_mutex_lock(&mutex);
        while( (tunelSMER != NONE && tunelSMER != mojSMER) || kamionTUNEL != 0 || autoTUNEL == 3){
            printf("-- ID:%ld -- ?cekam?\n",ID);
            pthread_cond_wait(&cond_auto, &mutex);
        }
        tunelSMER = mojSMER;
        autoTUNEL++;
        pthread_mutex_unlock(&mutex);
        
        printf("-- ID:%ld -- prolazim kroz tunel\n",ID);
        sleep(rand()%5+1);
        
        pthread_mutex_lock(&mutex);
        autoTUNEL--;
        if(autoTUNEL + kamionTUNEL + busTUNEL + hitnoTUNEL == 0){
            tunelSMER = NONE;
            pthread_cond_broadcast(&cond_auto);
            pthread_cond_broadcast(&cond_bus);
            pthread_cond_broadcast(&cond_kamion);
            pthread_cond_broadcast(&cond_hitnoVozilo);
        }
        else{
            pthread_cond_broadcast(&cond_auto);
            pthread_cond_broadcast(&cond_bus);
            pthread_cond_broadcast(&cond_hitnoVozilo);
        }
        pthread_mutex_unlock(&mutex);


    }

    if(tipVozila == BUS){
        pthread_mutex_lock(&mutex);
        while( (tunelSMER != NONE && tunelSMER != mojSMER) || kamionTUNEL != 0 || busTUNEL == 1){
            printf("-- ID:%ld -- ?cekam?\n",ID);
            pthread_cond_wait(&cond_auto, &mutex);
        }
        tunelSMER = mojSMER;
        busTUNEL++;
        pthread_mutex_unlock(&mutex);
        
        printf("-- ID:%ld -- prolazim kroz tunel\n",ID);
        sleep(rand()%5+1);
        
        pthread_mutex_lock(&mutex);
        busTUNEL--;
        if(autoTUNEL + kamionTUNEL + busTUNEL + hitnoTUNEL == 0){
            tunelSMER = NONE;
            pthread_cond_broadcast(&cond_auto);
            pthread_cond_broadcast(&cond_bus);
            pthread_cond_broadcast(&cond_kamion);
            pthread_cond_broadcast(&cond_hitnoVozilo);
        }
        else{
            // pthread_cond_broadcast(&cond_auto);
            pthread_cond_broadcast(&cond_bus);
            // pthread_cond_broadcast(&cond_hitnoVozilo);
        }
        pthread_mutex_unlock(&mutex);
    }

    if(tipVozila == KAMION){
        pthread_mutex_lock(&mutex);
        while((tunelSMER != NONE && tunelSMER != mojSMER) || kamionTUNEL != 0 || autoTUNEL != 0 || busTUNEL != 0){
            printf("-- ID:%ld -- ?cekam?\n",ID);
            pthread_cond_wait(&cond_auto, &mutex);
        }
        tunelSMER = mojSMER;
        kamionTUNEL++;
        pthread_mutex_unlock(&mutex);
        
        printf("-- ID:%ld -- prolazim kroz tunel\n",ID);
        sleep(rand()%5+1);
        
        pthread_mutex_lock(&mutex);
        kamionTUNEL--;
        if(autoTUNEL + kamionTUNEL + busTUNEL + hitnoTUNEL == 0){
            tunelSMER = NONE;
            pthread_cond_broadcast(&cond_auto);
            pthread_cond_broadcast(&cond_bus);
            pthread_cond_broadcast(&cond_kamion);
            pthread_cond_broadcast(&cond_hitnoVozilo);
        }
        else{
            pthread_cond_broadcast(&cond_auto);
            pthread_cond_broadcast(&cond_bus);
            pthread_cond_broadcast(&cond_hitnoVozilo);
            // pthread_cond_broadcast(&cond_kamion);
        }
        pthread_mutex_unlock(&mutex);
    }
    if(tipVozila == HITNO_VOZILO){
        pthread_mutex_lock(&mutex);
        while((tunelSMER != NONE && tunelSMER != mojSMER) || kamionTUNEL !=0){
            if(tunelSMER == mojSMER) printf("-- ID:%ld -- ?cekam?\n",ID);
            else printf("-- ID:%ld -- ?cekam da se promeni smer?\n",ID);
            pthread_cond_wait( &cond_hitnoVozilo, &mutex );
        }
        hitnoTUNEL++;
        tunelSMER = mojSMER;
        pthread_mutex_unlock(&mutex);
        sleep(rand()%5+1);
        printf("-- ID:%ld -- prolazim kroz tunel\n",ID);
        pthread_mutex_lock(&mutex);
        hitnoTUNEL--;
        pthread_cond_broadcast(&cond_auto);
        pthread_cond_broadcast(&cond_hitnoVozilo);
        pthread_cond_broadcast(&cond_kamion);
        pthread_cond_broadcast(&cond_bus);
        pthread_mutex_unlock(&mutex);



    }

    return NULL;

}



int main(){
    pthread_t vozila[N];
    tunelSMER = NONE;
    autoTUNEL = 0;
    busTUNEL = 0;
    kamionTUNEL = 0;
    hitnoTUNEL = 0;

    for(long i=0;i < N;i++){
        pthread_create(&vozila[i], NULL, prodjiTunel, (void*)i);
    }

    pthread_exit(NULL);
    return 0;
}