#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>

#define T 5
#define N 20
#define MAX_AUTA 3
#define MAX_AUTOBUSA 1

int smer[]={0,0};
int brAuta=0;
int brAutobusa=0;
int brKamiona=0;
int brHitnih=0;
int brHitnihCeka=0;

pthread_mutex_t mutex;
pthread_cond_t cond;

void status()
{
    printf("JUG: %d, SEVER: %d, AUTI: %d, BUSEVI: %d,KAMIONI: %d, HITNE:%d, CEKAJUCE_HITNE: %d\n",smer[0],smer[1],brAuta,brAutobusa,brKamiona,brHitnih,brHitnihCeka);
}
void *tunel(void* arg)
{
    long id =(long)arg;
    sleep(rand()%T);
    int tip=rand()%8;
        if(tip==0)//Auto iz juznog smera 
    {
        printf("<<AUTO sa JUGA id=%ld ceka da prodje kroz tunel\n",id);
        pthread_mutex_lock(&mutex);
    
        while(brAuta>=MAX_AUTA || brKamiona || brHitnihCeka || smer[1])
        {
            pthread_cond_wait(&cond,&mutex);
        }
        brAuta++;
        smer[0]++;
            
        pthread_mutex_unlock(&mutex);
        printf("--AUTO sa JUGA id=%ld proloazi kroz tunel\n",id);
        sleep(rand()%T);
        pthread_mutex_lock(&mutex);
        brAuta--;
        smer[0]--;
        if(smer[0]==0 || brAuta<MAX_AUTA)
        {
            pthread_cond_broadcast(&cond);
        }
            
        pthread_mutex_unlock(&mutex);
        printf(">>AUTO sa JUGA id=%ld je prosao kroz tunel\n",id);
    }
        if(tip==1)//Auto iz severnog smera
    {
        printf("<<AUTO sa SEVERA id=%ld ceka da prodje kroz tunel\n",id);
        pthread_mutex_lock(&mutex);
            
        while(brAuta>=MAX_AUTA || brKamiona || brHitnihCeka || smer[0])
        {
            pthread_cond_wait(&cond,&mutex);
        }
            
        brAuta++;
        smer[1]++;
            
        pthread_mutex_unlock(&mutex);
        printf("--AUTO sa SEVERA id=%ld proloazi kroz tunel\n",id);
        sleep(rand()%T);
        pthread_mutex_lock(&mutex);
        brAuta--;
        smer[1]--;
            
        if(smer[1]==0 || brAuta<MAX_AUTA)
        {
            pthread_cond_broadcast(&cond);
        }
        pthread_mutex_unlock(&mutex);
        printf(">>AUTO sa SEVERA id=%ld je prosao kroz tunel\n",id);
    }
        if(tip==2)//Autobus iz juznog smera
    {
        printf("<<AUTOBUS sa JUGA id=%ld ceka da prodje kroz tunel\n",id);
        pthread_mutex_lock(&mutex);
            
        while(brAutobusa>=MAX_AUTOBUSA || brKamiona || brHitnihCeka || smer[1])
        {
            pthread_cond_wait(&cond,&mutex);
        }
            
        brAutobusa++;
        smer[0]++;
            
        pthread_mutex_unlock(&mutex);
        printf("--AUTOBUS sa JUGA id=%ld proloazi kroz tunel\n",id);
        sleep(rand()%T);
        pthread_mutex_lock(&mutex);
        brAutobusa--;
        smer[0]--;
            
        if(smer[0]==0 || brAutobusa<MAX_AUTOBUSA)
        {
            pthread_cond_broadcast(&cond);
        }
        pthread_mutex_unlock(&mutex);
        printf(">>AUTOBUS sa JUGA id=%ld je prosao kroz tunel\n",id);
    }
        if(tip==3)//Autobus iz severnog smera
    {
        printf("<<AUTOBUS sa SEVERA id=%ld ceka da prodje kroz tunel\n",id);
        pthread_mutex_lock(&mutex);
            
        while(brAutobusa>=MAX_AUTOBUSA || brKamiona || brHitnihCeka || smer[0])
        {
            pthread_cond_wait(&cond,&mutex);
        }
        brAutobusa++;
        smer[1]++;
            
        pthread_mutex_unlock(&mutex);
        printf("--AUTOBUS sa SEVERA id=%ld proloazi kroz tunel\n",id);
        sleep(rand()%T);
        pthread_mutex_lock(&mutex);
        brAutobusa--;
        smer[1]--;
            
        if(smer[1]==0 || brAutobusa<MAX_AUTOBUSA)
        {
            pthread_cond_broadcast(&cond);
        }
        pthread_mutex_unlock(&mutex);
        printf(">>AUTOBUS sa SEVERA id=%ld je prosao kroz tunel\n",id);
    }
        if(tip==4)//Kamion iz juznog smera
    {
        printf("<<KAMION sa JUGA id=%ld ceka da prodje kroz tunel\n",id);
        pthread_mutex_lock(&mutex);
            
        while(brAuta ||brAutobusa || brKamiona || brHitnih || brHitnihCeka || smer[1])
        {
            pthread_cond_wait(&cond,&mutex);
        }
            
        brKamiona++;
        smer[0]++;
            
        pthread_mutex_unlock(&mutex);
        printf("--KAMION sa JUGA id=%ld proloazi kroz tunel\n",id);
        sleep(rand()%T);
        pthread_mutex_lock(&mutex);
        brKamiona--;
        smer[0]--;
            
        if(smer[0]==0 || brKamiona==0)
        {
            pthread_cond_broadcast(&cond);
        }
        pthread_mutex_unlock(&mutex);
        printf(">>KAMION sa JUGA id=%ld je prosao kroz tunel\n",id);
    }
        if(tip==5)//Kamion iz severnog smera
    {
        printf("<<KAMION sa SEVERA id=%ld ceka da prodje kroz tunel\n",id);
        pthread_mutex_lock(&mutex);
            
        while(brAuta ||brAutobusa || brKamiona || brHitnih || brHitnihCeka || smer[0])
        {
            pthread_cond_wait(&cond,&mutex);
        }
            
        brKamiona++;
        smer[1]++;
            
        pthread_mutex_unlock(&mutex);
        printf("--KAMION sa SEVERA id=%ld proloazi kroz tunel\n",id);
        sleep(rand()%T);
        pthread_mutex_lock(&mutex);
        brKamiona--;
        smer[1]--;
            
        if(smer[1]==0 || brKamiona==0)
        {
            pthread_cond_broadcast(&cond);
        }
        pthread_mutex_unlock(&mutex);
        printf(">>KAMION sa SEVERA id=%ld je prosao kroz tunel\n",id);
    }
        if(tip==6)//Hitna iz juznog smera
    {
        pthread_mutex_lock(&mutex);
        brHitnihCeka++;
            
        pthread_mutex_unlock(&mutex);
        printf("<<HITNA sa JUGA id=%ld ceka da prodje kroz tunel\n",id);
        pthread_mutex_lock(&mutex);
            
        while(brKamiona || smer[1])
        {
            pthread_cond_wait(&cond,&mutex);
        }
            
        brHitnihCeka--;
        if(brHitnihCeka==0)
        {
            pthread_cond_broadcast(&cond);
        }
            
        brHitnih++;
        smer[0]++;
            
        pthread_mutex_unlock(&mutex);
        printf("--HITNA sa JUGA id=%ld proloazi kroz tunel\n",id);
        sleep(rand()%T);
        pthread_mutex_lock(&mutex);
        brHitnih--;
        smer[0]--;
            
        if(smer[0]==0 || brHitnih==0)
        {
            pthread_cond_broadcast(&cond);
        }
        pthread_mutex_unlock(&mutex);
        printf(">>HITNA sa JUGA id=%ld je prosao kroz tunel\n",id);
    }
        if(tip==7)//Hitna iz severnog smera
    {
        pthread_mutex_lock(&mutex);
        brHitnihCeka++;
            
        pthread_mutex_unlock(&mutex);
        printf("<<HITNA sa SEVERA id=%ld ceka da prodje kroz tunel\n",id);
        pthread_mutex_lock(&mutex);
            
        while(brKamiona || smer[0])
        {
            pthread_cond_wait(&cond,&mutex);
        }
        brHitnihCeka--;
            
        if(brHitnihCeka==0)
        {
            pthread_cond_broadcast(&cond);
        }
            
        brHitnih++;
        smer[1]++;
            
        pthread_mutex_unlock(&mutex);
        printf("--HITNA sa SEVERA id=%ld proloazi kroz tunel\n",id);
        sleep(rand()%T);
        pthread_mutex_lock(&mutex);
        brHitnih--;
        smer[1]--;
            
        if(smer[1]==0 || brHitnih==0)
        {
            pthread_cond_broadcast(&cond);
        }
        pthread_mutex_unlock(&mutex);
        printf(">>HITNA sa SEVERA id=%ld je prosao kroz tunel\n",id);
    }
    pthread_exit(NULL);
}
int main()
{
    pthread_t nit[N];
    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);

    for(int i=0;i<N;i++)
    {
        pthread_create(&nit[i],NULL,tunel,(void*)i);
    }

    for(int i=0;i<N;i++)
    {
        pthread_join(nit[i],NULL);
    }
    return 0;

}