#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "pthread.h"

#define S 20
#define J 20

#define AUTO 0
#define AUTOBUS 1
#define KAMION 2
#define HITNO 3

#define PRAZNO 0
#define SEVER 1
#define JUG 2

int smer=0;  // 0 - PRAZNO   1 - SEVER_JUG  2 - JUG_SEVER

pthread_cond_t condAuto;
pthread_cond_t condAutobus;
pthread_cond_t condKamion;
pthread_cond_t condHitno;
pthread_mutex_t mutex;

int broj_vozila=0;
int broj_automobila=0;
int broj_autobusa=0;
int broj_kamiona=0;
int hitno_vozilo_sever=0;
int hitno_vozilo_jug=0;
void* SeverJug(void* arg)
{
    long i=(long ) arg;
    int tip=rand()%4;
    sleep(rand()%5+1);
    if(tip==AUTO)
    {
        printf("Automobil %ld stize u tunel sa Severa\n",i);
        pthread_mutex_lock(&mutex);
        while(smer==JUG || broj_kamiona>0 || broj_automobila==3)
        {
            pthread_cond_wait(&condAuto,&mutex);
        }
        while((smer==SEVER || smer==PRAZNO) && hitno_vozilo_sever>0)
        {
            pthread_cond_wait(&condAuto,&mutex);
        }
        smer=SEVER;
        broj_automobila++;
        broj_vozila++;
        pthread_mutex_unlock(&mutex);
        printf("Automobil %ld prolazi kroz tunel sa Severa ka Jugu\n",i);
        sleep(1);
        printf("Automobil %ld izasao je iz tunela sa Severa ka Jugu\n",i);
        pthread_mutex_lock(&mutex);
        broj_automobila--;
        broj_vozila--;
        if(broj_vozila==0)
        {
            smer=PRAZNO;
        }
        pthread_cond_broadcast(&condAuto);
        pthread_cond_broadcast(&condAutobus);
        pthread_cond_broadcast(&condKamion);
        pthread_cond_broadcast(&condHitno);
        pthread_mutex_unlock(&mutex);
    }
    else if(tip==AUTOBUS)
    {
        printf("Autobus %ld stize u tunel sa Severa\n",i);
        pthread_mutex_lock(&mutex);
        while(smer==JUG || broj_kamiona>0 || broj_autobusa>0)
        {
            pthread_cond_wait(&condAutobus,&mutex);
        }
        while((smer==SEVER || smer==PRAZNO) && hitno_vozilo_sever>0)
        {
            pthread_cond_wait(&condAutobus,&mutex);
        }
        smer=JUG;
        broj_autobusa++;
        broj_vozila++;
        pthread_mutex_unlock(&mutex);
        printf("Autobus %ld prolazi kroz tunel sa Severa ka Jugu\n",i);
        sleep(2);
        printf("Autobus %ld izasao je iz tunela sa Severa ka Jugu\n",i);
        pthread_mutex_lock(&mutex);
        broj_autobusa--;
        broj_vozila--;
        if(broj_vozila==0)
        {
            smer=PRAZNO;
        }
        pthread_cond_broadcast(&condAuto);
        pthread_cond_broadcast(&condAutobus);
        pthread_cond_broadcast(&condKamion);
        pthread_cond_broadcast(&condHitno);
        pthread_mutex_unlock(&mutex);
    }
    else if(tip==KAMION)
    {
        printf("Kamion %ld stize u tunel sa Severa\n",i);
        pthread_mutex_lock(&mutex);
        while(smer==JUG || broj_vozila>0)
        {
            pthread_cond_wait(&condKamion,&mutex);
        }
        while((smer==SEVER || smer==PRAZNO) && hitno_vozilo_sever>0)
        {
            pthread_cond_wait(&condKamion,&mutex);
        }
        smer=SEVER;
        broj_kamiona++;
        broj_vozila++;
        pthread_mutex_unlock(&mutex);
        printf("Kamion %ld prolazi kroz tunel sa Severa ka Jugu\n",i);
        sleep(3);
        printf("Kamion %ld izasao je iz tunela sa Severa ka Jugu\n",i);
        pthread_mutex_lock(&mutex);
        broj_kamiona--;
        broj_vozila--;
        if(broj_vozila==0)
        {
            smer=PRAZNO;
        }
        pthread_cond_broadcast(&condAuto);
        pthread_cond_broadcast(&condAutobus);
        pthread_cond_broadcast(&condKamion);
        pthread_cond_broadcast(&condHitno);
        pthread_mutex_unlock(&mutex);
    }
    else if(tip==HITNO)
    {
        printf("Hitno vozilo %ld stize u tunel sa Severa\n",i);
        pthread_mutex_lock(&mutex);
        while(smer==JUG || broj_kamiona>0)
        {
            pthread_cond_wait(&condHitno,&mutex);
        }
        smer=SEVER;
        hitno_vozilo_sever++;
        broj_vozila++;
        pthread_mutex_unlock(&mutex);
        printf("Hitno vozilo %ld prolazi kroz tunel sa Severa ka Jugu\n",i);
        sleep(2);
        printf("Hitno vozilo %ld izaslo je iz tunela sa Severa ka Jugu\n",i);
        pthread_mutex_lock(&mutex);
        hitno_vozilo_sever--;
        broj_vozila--;
        if(broj_vozila==0)
        {
            smer=PRAZNO;
        }
        pthread_cond_broadcast(&condAuto);
        pthread_cond_broadcast(&condAutobus);
        pthread_cond_broadcast(&condKamion);
        pthread_cond_broadcast(&condHitno);
        pthread_mutex_unlock(&mutex);
    }

}
void* JugSever(void* arg)
{
    long i=(long ) arg;
    int tip=rand()%4;
    sleep(rand()%5+1);
    if(tip==AUTO)
    {
        printf("Automobil %ld stize u tunel sa Juga\n",i);
        pthread_mutex_lock(&mutex);
        while(smer==SEVER || broj_kamiona>0 || broj_automobila==3)
        {
            pthread_cond_wait(&condAuto,&mutex);
        }
        while((smer==JUG || smer==PRAZNO) && hitno_vozilo_jug>0)
        {
            pthread_cond_wait(&condAuto,&mutex);
        }
        smer=JUG;
        broj_automobila++;
        broj_vozila++;
        pthread_mutex_unlock(&mutex);
        printf("Automobil %ld prolazi kroz tunel sa Juga ka Severu\n",i);
        sleep(1);
        printf("Automobil %ld izasao je iz tunela sa Juga ka Severu\n",i);
        pthread_mutex_lock(&mutex);
        broj_automobila--;
        broj_vozila--;
        if(broj_vozila==0)
        {
            smer=PRAZNO;
        }
        pthread_cond_broadcast(&condAuto);
        pthread_cond_broadcast(&condAutobus);
        pthread_cond_broadcast(&condKamion);
        pthread_cond_broadcast(&condHitno);
        pthread_mutex_unlock(&mutex);
    }
    else if(tip==AUTOBUS)
    {
        printf("Autobus %ld stize u tunel sa Juga\n",i);
        pthread_mutex_lock(&mutex);
        while(smer==SEVER || broj_kamiona>0 || broj_autobusa>0)
        {
            pthread_cond_wait(&condAutobus,&mutex);
        }
        while((smer==JUG || smer==PRAZNO) && hitno_vozilo_jug>0)
        {
            pthread_cond_wait(&condAutobus,&mutex);
        }
        smer=JUG;
        broj_autobusa++;
        broj_vozila++;
        pthread_mutex_unlock(&mutex);
        printf("Autobus %ld prolazi kroz tunel sa Juga ka Severu\n",i);
        sleep(2);
        printf("Autobus %ld izasao je iz tunela sa Juga ka Severu\n",i);
        pthread_mutex_lock(&mutex);
        broj_autobusa--;
        broj_vozila--;
        if(broj_vozila==0)
        {
            smer=PRAZNO;
        }
        pthread_cond_broadcast(&condAuto);
        pthread_cond_broadcast(&condAutobus);
        pthread_cond_broadcast(&condKamion);
        pthread_cond_broadcast(&condHitno);
        pthread_mutex_unlock(&mutex);
    }
    else if(tip==KAMION)
    {
        printf("Kamion %ld stize u tunel sa Juga\n",i);
        pthread_mutex_lock(&mutex);
        while(smer==SEVER || broj_vozila>0)
        {
            pthread_cond_wait(&condKamion,&mutex);
        }
        while((smer==JUG || smer==PRAZNO) && hitno_vozilo_jug>0)
        {
            pthread_cond_wait(&condKamion,&mutex);
        }
        smer=JUG;
        broj_kamiona++;
        broj_vozila++;
        pthread_mutex_unlock(&mutex);
        printf("Kamion %ld prolazi kroz tunel sa Juga ka severu\n",i);
        sleep(3);
        printf("Kamion %ld izasao je iz tunela sa Juga ka severu\n",i);
        pthread_mutex_lock(&mutex);
        broj_kamiona--;
        broj_vozila--;
        if(broj_vozila==0)
        {
            smer=PRAZNO;
        }
        pthread_cond_broadcast(&condAuto);
        pthread_cond_broadcast(&condAutobus);
        pthread_cond_broadcast(&condKamion);
        pthread_cond_broadcast(&condHitno);
        pthread_mutex_unlock(&mutex);
    }
    else if(tip==HITNO)
    {
        printf("Hitno vozilo %ld stize u tunel sa Juga\n",i);
        pthread_mutex_lock(&mutex);
        while(smer==SEVER || broj_kamiona>0)
        {
            pthread_cond_wait(&condHitno,&mutex);
        }
        smer=JUG;
        hitno_vozilo_sever++;
        broj_vozila++;
        pthread_mutex_unlock(&mutex);
        printf("Hitno vozilo %ld prolazi kroz tunel sa Juga ka Severu\n",i);
        sleep(2);
        printf("Hitno vozilo %ld izaslo je iz tunela sa Juga ka Severu\n",i);
        pthread_mutex_lock(&mutex);
        hitno_vozilo_sever--;
        broj_vozila--;
        if(broj_vozila==0)
        {
            smer=PRAZNO;
        }
        pthread_cond_broadcast(&condAuto);
        pthread_cond_broadcast(&condAutobus);
        pthread_cond_broadcast(&condKamion);
        pthread_cond_broadcast(&condHitno);
        pthread_mutex_unlock(&mutex);
    }
}

int main()
{
    pthread_t threads[S+J];
    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&condAuto,NULL);
    pthread_cond_init(&condAutobus,NULL);
    pthread_cond_init(&condKamion,NULL);
    pthread_cond_init(&condHitno,NULL);

    for(int i=0;i<S;i++)
    {
        pthread_create(&threads[i],NULL,SeverJug,(void *)(long)(i+1));
    }
    for(int i=0;i<J;i++)
    {
        pthread_create(&threads[i+S],NULL,JugSever,(void*)(long)(i+1));
    }

    for(int i=0;i<S+J;i++)
    {
        pthread_join(threads[i],NULL);
    }

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&condAuto);
    pthread_cond_destroy(&condAutobus);
    pthread_cond_destroy(&condKamion);
    pthread_cond_destroy(&condHitno);
    for(int i=0;i<S+J;i++)
    {
        pthread_exit(&threads[i]);
    }

}