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

#define NONE 0
#define JUG 1
#define SEVER 2

#define MAXKOLA 3
#define MAXBUSA 1
#define MAXKAMIONA 1

int SMER = NONE;

#define MAXNITI 20

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t kola = PTHREAD_COND_INITIALIZER;
pthread_cond_t bus = PTHREAD_COND_INITIALIZER;
pthread_cond_t kamion = PTHREAD_COND_INITIALIZER;
pthread_cond_t hitna = PTHREAD_COND_INITIALIZER;

int brkola = 0;
int brbus = 0;
int brkamion = 0;
int brhitna = 0;
int hitnaceka = 0;
int brvozila = 0;

void* jug(void* arg)
{
    long id = (long)arg;

    int tip = rand() % 4 + 1;

    switch(tip)
    {
        case(1):
            sleep(rand()%5+1);
            printf("kola %ld ceka smer jug\n\n",id);
            pthread_mutex_lock(&m);
            while(SMER == SEVER || brkola >= MAXKOLA || brkamion > 0 || hitnaceka)
                pthread_cond_wait(&kola,&m);
            SMER=JUG;
            brkola++;
            brvozila++;
            pthread_mutex_unlock(&m);
            printf("kola %ld je u tunelu smer jug\n\n",id);
            sleep(rand()%3 +1);
            pthread_mutex_lock(&m);
            printf("kola %ld je izasao iz tunela smer jug\n\n",id);
            brkola--;
            brvozila--;
            if(hitnaceka && brvozila ==0)
            {
                SMER = NONE;
                pthread_cond_broadcast(&hitna);
            }
            
            else if(hitnaceka){
                SMER=JUG;
                pthread_cond_broadcast(&hitna);
            }
            else if(brvozila == 0)
            {
                SMER=NONE;
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
                pthread_cond_broadcast(&kamion);
            }
            else if(brkola<MAXKOLA || brbus== 0)
            {
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
            }
            pthread_mutex_unlock(&m);
            break;

        case(2):
            sleep(rand()%5+1);
            printf("bus %ld ceka smer jug\n\n",id);
            pthread_mutex_lock(&m);
            while(SMER==SEVER || brbus > 0 || brkamion > 0 || hitnaceka)
                pthread_cond_wait(&bus,&m);
            SMER=JUG;
            brbus++;
            brvozila++;
            pthread_mutex_unlock(&m);
            printf("bus %ld je u tunelu smer jug\n\n",id);
            sleep(rand()%3 +1);
            pthread_mutex_lock(&m);
            printf("bus %ld je izasao iz tunela smer jug\n\n",id);
            brbus--;
            brvozila--;
            if(hitnaceka && brvozila ==0)
            {
                SMER = NONE;
                pthread_cond_broadcast(&hitna);
            }
            
            else if(hitnaceka){
                SMER=JUG;
                pthread_cond_broadcast(&hitna);
            }
            else if(brvozila == 0)
            {
                SMER=NONE;
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
                pthread_cond_broadcast(&kamion);
            }
            if(brkola<MAXKOLA || brbus == 0){
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
            }
            pthread_mutex_unlock(&m);
            break;
        case(3):
            sleep(rand()%5+1);
            printf("kamion %ld ceka smer jug\n\n",id);
            pthread_mutex_lock(&m);
            while(SMER == SEVER || brvozila > 0 || hitnaceka)
                pthread_cond_wait(&kamion,&m);
            SMER=JUG;
            brvozila++;
            brkamion++;
            pthread_mutex_unlock(&m);
            printf("kamion %ld je u tunelu smer jug\n\n",id);
            sleep(rand()%3 +1);
            pthread_mutex_lock(&m);
            printf("kamion %ld je izasao iz tunela smer jug\n\n",id);
            brkamion--;
            brvozila--;
            if(hitnaceka && brvozila ==0)
            {
                SMER = NONE;
                pthread_cond_broadcast(&hitna);
            }
            
            else if(hitnaceka)
            {
                SMER = JUG;
                pthread_cond_broadcast(&hitna);
            }
            else if(brvozila == 0)
            {
                SMER=NONE;
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
                pthread_cond_broadcast(&kamion);
            }
            pthread_mutex_unlock(&m);
            break;
        case(4):
            sleep(rand()%5+1);
            printf("hitna %ld ceka smer jug\n\n",id);
            pthread_mutex_lock(&m);
            hitnaceka++;
            while(SMER == SEVER || brkamion)
                pthread_cond_wait(&hitna,&m);
            SMER=JUG;
            brhitna++;
            brvozila++;
            pthread_mutex_unlock(&m);
            printf("hitna %ld je u tunelu smer jug\n\n",id);
            sleep(rand()%3 +1);
            pthread_mutex_lock(&m);
            printf("hitna %ld je izasao iz tunela smer jug\n\n",id);
            brhitna--;
            brvozila--;
            hitnaceka--;
            if(hitnaceka && brvozila ==0)
            {
                SMER = NONE;
                pthread_cond_broadcast(&hitna);
            }
            
            else if(hitnaceka)
            {
                SMER = JUG;
                pthread_cond_broadcast(&hitna);
            }
            else if(brvozila == 0)
            {
                SMER=NONE;
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
                pthread_cond_broadcast(&kamion);
            }
            pthread_mutex_unlock(&m);
            break;
    }

    return NULL;
}


void* sever(void* arg)
{
    long id = (long)arg;

    int tip = rand() % 4 + 1;

    switch(tip)
    {
        case(1):
            sleep(rand()%5+1);
            printf("kola %ld ceka smer sever\n\n",id);
            pthread_mutex_lock(&m);
            while(SMER == JUG || brkola >= MAXKOLA || brkamion > 0 || hitnaceka)
                pthread_cond_wait(&kola,&m);
            SMER=SEVER;
            brkola++;
            brvozila++;
            pthread_mutex_unlock(&m);
            printf("kola %ld je u tunelu smer sever\n\n",id);
            sleep(rand()%3 +1);
            pthread_mutex_lock(&m);
            printf("kola %ld je izasao iz tunela smer sever\n\n",id);
            brkola--;
            brvozila--;
            if(hitnaceka && brvozila ==0)
            {
                SMER = NONE;
                pthread_cond_broadcast(&hitna);
            }
            
            else if(hitnaceka){
                SMER=SEVER;
                pthread_cond_broadcast(&hitna);
            }
            else if(brvozila == 0)
            {
                SMER=NONE;
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
                pthread_cond_broadcast(&kamion);
            }
            else if(brkola<MAXKOLA || brbus == 0)
            {
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
            }
            pthread_mutex_unlock(&m);
            break;

        case(2):
            sleep(rand()%5+1);
            printf("bus %ld ceka smer sever\n\n",id);
            pthread_mutex_lock(&m);
            while(SMER==JUG || brbus > 0 || brkamion > 0 || hitnaceka)
                pthread_cond_wait(&bus,&m);
            SMER=SEVER;
            brbus++;
            brvozila++;
            pthread_mutex_unlock(&m);
            printf("bus %ld je u tunelu smer sever\n\n",id);
            sleep(rand()%3 +1);
            pthread_mutex_lock(&m);
            printf("bus %ld je izasao iz tunela smer sever\n\n",id);
            brbus--;
            brvozila--;
            if(hitnaceka && brvozila ==0)
            {
                SMER = NONE;
                pthread_cond_broadcast(&hitna);
            }
            
            else if(hitnaceka){
                SMER=SEVER;
                pthread_cond_broadcast(&hitna);
            }
            else if(brvozila == 0)
            {
                SMER=NONE;
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
                pthread_cond_broadcast(&kamion);
            }
            if(brkola<MAXKOLA || brbus == 0){
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
            }
            pthread_mutex_unlock(&m);
            break;
        case(3):
            sleep(rand()%5+1);
            printf("kamion %ld ceka smer sever\n\n",id);
            pthread_mutex_lock(&m);
            while(SMER == JUG || brvozila > 0 || hitnaceka)
                pthread_cond_wait(&kamion,&m);
            SMER=SEVER;
            brvozila++;
            brkamion++;
            pthread_mutex_unlock(&m);
            printf("kamion %ld je u tunelu smer sever\n\n",id);
            sleep(rand()%3 +1);
            pthread_mutex_lock(&m);
            printf("kamion %ld je izasao iz tunela smer sever\n\n",id);
            brkamion--;
            brvozila--;
            if(hitnaceka && brvozila ==0)
            {
                SMER = NONE;
                pthread_cond_broadcast(&hitna);
            }
            
            else if(hitnaceka)
            {
                SMER = SEVER;
                pthread_cond_broadcast(&hitna);
            }
            else if(brvozila == 0)
            {
                SMER=NONE;
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
                pthread_cond_broadcast(&kamion);
            }
            pthread_mutex_unlock(&m);
            break;
        case(4):
            sleep(rand()%5+1);
            printf("hitna %ld ceka smer sever\n\n",id);
            pthread_mutex_lock(&m);
            hitnaceka++;
            while(SMER == JUG || brkamion)
                pthread_cond_wait(&hitna,&m);
            SMER=SEVER;
            brhitna++;
            brvozila++;
            pthread_mutex_unlock(&m);
            printf("hitna %ld je u tunelu smer sever\n\n",id);
            sleep(rand()%3 +1);
            pthread_mutex_lock(&m);
            printf("hitna %ld je izasao iz tunela smer sever\n\n",id);
            brhitna--;
            brvozila--;
            hitnaceka--;
            if(hitnaceka && brvozila ==0)
            {
                SMER = NONE;
                pthread_cond_broadcast(&hitna);
            }
            
            else if(hitnaceka)
            {
                SMER = SEVER;
                pthread_cond_broadcast(&hitna);
            }
            else if(brvozila == 0)
            {
                SMER=NONE;
                pthread_cond_broadcast(&hitna);
                pthread_cond_broadcast(&kola);
                pthread_cond_broadcast(&bus);
                pthread_cond_broadcast(&kamion);
            }
            pthread_mutex_unlock(&m);
            break;
    }

    return NULL;
}


int main(){
    pthread_t NITI[MAXNITI];

    for(long i=0; i<MAXNITI; i++)
    {
        if(i%2) pthread_create(NITI + i, NULL, jug,(void*)i);
        else pthread_create(NITI + i, NULL, sever,(void*)i);
    }
    pthread_exit(NULL);

    return 0;
}