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

#define N 10

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condAuto = PTHREAD_COND_INITIALIZER;
pthread_cond_t condAutobus = PTHREAD_COND_INITIALIZER;
pthread_cond_t condKamion = PTHREAD_COND_INITIALIZER;
pthread_cond_t condHitnoVozilo = PTHREAD_COND_INITIALIZER;


#define NONE 0
#define A -1
#define B -2

#define AUTO 1
#define AUTOBUS 2
#define KAMION 3
#define HITNOVOZILO 4

int smer = NONE;
int brVozila = 0;
int brAuta = 0;
int brAutobusa = 0;
int brKamiona = 0;
int brHitnoVozilo = 0;
int flagImaHitnoVoziloA = 0;
int flagImaHitnoVoziloB = 0;


void* voziA(void* arg)
{
    long id = (long)arg;
    int tip = rand()%4+1;
    sleep(rand()%5+1);
    //auto
    if(tip == AUTO){
        pthread_mutex_lock(&m);
        while(smer == B || brKamiona > 0 || brAuta > 3 || flagImaHitnoVoziloB != 0)
        {
            printf("Vozilo ID: %ld TIP: AUTO(%d) CEKAM A smer\n", id, tip);
            pthread_cond_wait(&condAuto, &m);
        }
        smer = A;
        brVozila++;
        brAuta++;
        printf("Vozilo ID: %ld TIP: AUTO(%d) ulazi u tunel iz A smera\n", id, tip);
        pthread_mutex_unlock(&m);
        sleep(3);
        pthread_mutex_lock(&m);
        printf("Vozilo ID: %ld TIP: AUTO(%d) izlazi iz tunela iz A smera\n", id, tip);
        brAuta--;
        brVozila--;
        if(brVozila == 0 && flagImaHitnoVoziloB != 0)
        {
            smer = B;
            pthread_cond_broadcast(&condHitnoVozilo);

        }
        else{
        if(brVozila == 0)
            {
                smer = NONE;
                pthread_cond_broadcast(&condAuto);
                pthread_cond_broadcast(&condAutobus);
                pthread_cond_broadcast(&condKamion);
                pthread_cond_broadcast(&condHitnoVozilo);
            }
        }



        pthread_mutex_unlock(&m);

    }
    //autobus
    if(tip == AUTOBUS)
    {
        pthread_mutex_lock(&m);
        while(smer == B || brAutobusa > 0 || brKamiona > 0 || flagImaHitnoVoziloB != 0)
        {
            printf("Vozilo ID: %ld TIP: AUTOBUS(%d) CEKAM A smer\n", id, tip);
            pthread_cond_wait(&condAutobus, &m);
        }
        smer = A;
        brVozila++;
        brAutobusa++;
        printf("Vozilo ID: %ld TIP: AUTOBUS(%d) ulazi u tunel iz A smera\n", id, tip);
        pthread_mutex_unlock(&m);
        sleep(3);
        pthread_mutex_lock(&m);
        printf("Vozilo ID: %ld TIP: AUTOBUS(%d) izlazi iz tunela iz A smera\n", id, tip);
        brAutobusa--;
        brVozila--;
        if(brVozila == 0 && flagImaHitnoVoziloB != 0)
        {
            smer = B;
            pthread_cond_broadcast(&condHitnoVozilo);
        }
        else{
            if(brVozila == 0)
            {
                smer = NONE;
                pthread_cond_broadcast(&condAuto);
                pthread_cond_broadcast(&condAutobus);
                pthread_cond_broadcast(&condKamion);
                pthread_cond_broadcast(&condHitnoVozilo);
            }
            if(brAutobusa==0)
            {
                pthread_cond_broadcast(&condAutobus);
            }
        }
        pthread_mutex_unlock(&m);

    }
    //kamion
    if(tip == KAMION )
    {
        pthread_mutex_lock(&m);
        while(brVozila>0 || flagImaHitnoVoziloB != 0)
        {
            printf("Vozilo ID: %ld TIP: KAMION(%d) CEKAM A smer\n", id, tip);
            pthread_cond_wait(&condKamion, &m);
        }
        smer = A;
        brVozila++;
        brKamiona++;
        printf("Vozilo ID: %ld TIP: KAMION(%d) ulazi u tunel iz A smera\n", id, tip);
        pthread_mutex_unlock(&m);
        sleep(3);
        pthread_mutex_lock(&m);
        printf("Vozilo ID: %ld TIP: KAMION(%d) izlazi iz tunela iz A smera\n", id, tip);
        brVozila--;
        brKamiona--;
        if(brVozila == 0 && flagImaHitnoVoziloB != 0)
        {
            smer = B;
            pthread_cond_broadcast(&condHitnoVozilo);
        }
        else{
            if(brVozila == 0)
            {
                smer = NONE;
                pthread_cond_broadcast(&condAuto);
                pthread_cond_broadcast(&condAutobus);
                pthread_cond_broadcast(&condKamion);
                pthread_cond_broadcast(&condHitnoVozilo);

            }
        }



    }
    // hitno vozilo
    if(tip == HITNOVOZILO)
    {
        
        pthread_mutex_lock(&m);
        flagImaHitnoVoziloA = 1;
        while((smer == B && brVozila>0) || brKamiona > 0){
            printf("Vozilo ID: %ld TIP: HITNO VOZILO(%d) CEKAM A smer\n", id, tip);
            pthread_cond_wait(&condHitnoVozilo, &m);
        }
        smer = A;
        brHitnoVozilo++;
        brVozila++;
        printf("Vozilo ID: %ld TIP: HITNO VOZILO(%d) ulazi u tunel iz A smera\n", id, tip);
        pthread_mutex_unlock(&m);
        sleep(3);
        pthread_mutex_lock(&m);
        printf("Vozilo ID: %ld TIP: HITNO VOZILO(%d) izlazi iz tunela iz A smera\n", id, tip);
        brHitnoVozilo--;
        brVozila--;
        if(brVozila == 0){
            smer = NONE;
            pthread_cond_broadcast(&condAuto);
            pthread_cond_broadcast(&condAutobus);
            pthread_cond_broadcast(&condKamion);
            pthread_cond_broadcast(&condHitnoVozilo);
        }
        flagImaHitnoVoziloA = 0;

        pthread_mutex_unlock(&m);

        


    }

    return NULL;
}


void* voziB(void* arg)
{
    long id = (long)arg;
    int tip = rand()%4+1;
    sleep(rand()%5+1);
    //auto
    if(tip == AUTO){
        pthread_mutex_lock(&m);
        while(smer == A || brKamiona > 0 || brAuta > 3 || flagImaHitnoVoziloA != 0)
        {
            printf("Vozilo ID: %ld TIP: AUTO(%d) CEKAM B smer\n", id, tip);
            pthread_cond_wait(&condAuto, &m);
        }
        smer = B;
        brVozila++;
        brAuta++;
        printf("Vozilo ID: %ld TIP: AUTO(%d) ulazi u tunel iz B smera\n", id, tip);
        pthread_mutex_unlock(&m);
        sleep(3);
        pthread_mutex_lock(&m);
        printf("Vozilo ID: %ld TIP: AUTO(%d) izlazi iz tunela iz B smera\n", id, tip);
        brAuta--;
        brVozila--;
        if(brVozila == 0 && flagImaHitnoVoziloA != 0)
        {
            smer = A;
            pthread_cond_broadcast(&condHitnoVozilo);
        }
        else{
        if(brVozila == 0)
            {
                smer = NONE;
                pthread_cond_broadcast(&condAuto);
                pthread_cond_broadcast(&condAutobus);
                pthread_cond_broadcast(&condKamion);
                pthread_cond_broadcast(&condHitnoVozilo);
            }
        }


        pthread_mutex_unlock(&m);

    }
    //autobus
    if(tip == AUTOBUS)
    {
        pthread_mutex_lock(&m);
        while(smer == A || brAutobusa > 0 || brKamiona > 0 || flagImaHitnoVoziloA != 0)
        {
            printf("Vozilo ID: %ld TIP: AUTOBUS(%d) CEKAM B smer\n", id, tip);
            pthread_cond_wait(&condAutobus, &m);
        }
        smer = B;
        brVozila++;
        brAutobusa++;
        printf("Vozilo ID: %ld TIP: AUTOBUS(%d) ulazi u tunel iz B smera\n", id, tip);
        pthread_mutex_unlock(&m);
        sleep(3);
        pthread_mutex_lock(&m);
        printf("Vozilo ID: %ld TIP: AUTOBUS(%d) izlazi iz tunela iz B smera\n", id, tip);
        brAutobusa--;
        brVozila--;
        if(brVozila == 0 && flagImaHitnoVoziloA){
            smer = A;
            pthread_cond_broadcast(&condHitnoVozilo);
        }
        else{
            if(brVozila == 0)
            {
                smer = NONE;
                pthread_cond_broadcast(&condAuto);
                pthread_cond_broadcast(&condAutobus);
                pthread_cond_broadcast(&condKamion);
                pthread_cond_broadcast(&condHitnoVozilo);
            }
            if(brAutobusa==0)
            {
                pthread_cond_broadcast(&condAutobus);
            }
        }
        pthread_mutex_unlock(&m);

    }
    //kamion
    if(tip == KAMION)
    {
        pthread_mutex_lock(&m);
        while(brVozila>0 || flagImaHitnoVoziloA != 0)
        {
            printf("Vozilo ID: %ld TIP: KAMION(%d) CEKAM B smer\n", id, tip);
            pthread_cond_wait(&condKamion, &m);
        }
        smer = B;
        brVozila++;
        brKamiona++;
        printf("Vozilo ID: %ld TIP: KAMION(%d) ulazi u tunel iz B smera\n", id, tip);
        pthread_mutex_unlock(&m);
        sleep(3);
        pthread_mutex_lock(&m);
        printf("Vozilo ID: %ld TIP: KAMION(%d) izlazi iz tunela iz B smera\n", id, tip);
        brVozila--;
        brKamiona--;
        if(brVozila == 0 && flagImaHitnoVoziloA)
        {
            smer = A;
            pthread_cond_broadcast(&condHitnoVozilo);
        }
        if(brVozila == 0)
        {
            smer = NONE;
            pthread_cond_broadcast(&condAuto);
            pthread_cond_broadcast(&condAutobus);
            pthread_cond_broadcast(&condKamion);
            pthread_cond_broadcast(&condHitnoVozilo);

        }



    }
    // hitno vozilo
    if(tip == HITNOVOZILO)
    {
        
        pthread_mutex_lock(&m);
        flagImaHitnoVoziloB = 1;
        while((smer == A && brVozila>0) || brKamiona > 0){
            printf("Vozilo ID: %ld TIP: HITNO VOZILO(%d) CEKAM B smer\n", id, tip);
            pthread_cond_wait(&condHitnoVozilo, &m);
        }
        smer = B;
        brHitnoVozilo++;
        brVozila++;
        printf("Vozilo ID: %ld TIP: HITNO VOZILO(%d) ulazi u tunel iz B smera\n", id, tip);
        pthread_mutex_unlock(&m);
        sleep(3);
        pthread_mutex_lock(&m);
        printf("Vozilo ID: %ld TIP: HITNO VOZILO(%d) izlazi iz tunela iz B smera\n", id, tip);
        brHitnoVozilo--;
        brVozila--;
        if(brVozila == 0){
            smer = NONE;
            pthread_cond_broadcast(&condAuto);
            pthread_cond_broadcast(&condAutobus);
            pthread_cond_broadcast(&condKamion);
            pthread_cond_broadcast(&condHitnoVozilo);
        }
        flagImaHitnoVoziloB = 0;

        pthread_mutex_unlock(&m);

        


    }
    return NULL;
}

int main()
{
    srand(time(NULL));
    pthread_t vozila[N];
    printf("pocetak\n\n\n\n");
    for(long i = 0; i<N; i++)
    {
        if(i%2==0)
        {
            pthread_create(vozila+i, NULL, voziA, (void*)i);
        }
        else
        {
            pthread_create(vozila+i, NULL, voziB, (void*)i);
        }
    }
    pthread_exit(NULL);

    printf("\nProsli svi\n");
    return 0;
}