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

int S = 10;
int J = 10;

pthread_mutex_t mutex;
pthread_cond_t condS;
pthread_cond_t condJ;

int smer = 0; // 0 - neutralni, 1 - sever , 2 - jug\

int u_tunelu = 0; // broj vozila u tunelu
int tunel_auto = 0; // broj auta u tunelu
int tunel_bus = 0;
int tunel_kamion = 0;
int tunel_hitna = 0;

int ceka_hitna_s = 0; // da li sa severne strane ceka hitna
int ceka_hitna_j = 0; // da li sa juzne strane ceka hitna 


void * workS( void * i)
{
    long index = (long) i;

    while (1)
    {
        int vozilo = rand() % 4; // 0 - auto, 1 - bus, 2 - kamion, 3 - hitno vozilo
        sleep(rand()%5);
        
        if( vozilo == 0)
        {
            printf("Tunelu je sa severa prisao auto %ld \n", index);

            pthread_mutex_lock(&mutex);
            while ( smer == 2 || tunel_auto >= 3 || tunel_kamion >= 1 || ceka_hitna_s >= 1 )
            {
                pthread_cond_wait(&condS, &mutex);
            }
            u_tunelu ++;
            smer = 1;
            tunel_auto ++;
            //printf("Tunel je prosao sa severa auto %ld \n", index);
            pthread_mutex_unlock(&mutex);

            sleep(rand()%5);
            printf("Tunel je prosao sa severa auto %ld \n", index);

            pthread_mutex_lock(&mutex);
            u_tunelu --;
            tunel_auto --;
            if( u_tunelu == 0 )
            {
                smer = 0;
                pthread_cond_broadcast(&condJ); //nema nikog
                pthread_cond_broadcast(&condS);
            }
            else if ( tunel_auto < 3) 
            {
                pthread_cond_broadcast(&condS); // izasla su kola, mogu neka druga kola da udju
            }
            pthread_mutex_unlock(&mutex);

        }

        else if( vozilo == 1)
        {
            printf("Tunelu je sa severa prisao bus %ld \n", index);

            pthread_mutex_lock(&mutex);
            while ( smer == 2 || tunel_kamion >= 1 || ceka_hitna_s >= 1 || tunel_bus >= 1)
            {
                pthread_cond_wait(&condS, &mutex);
            }
            u_tunelu ++;
            smer = 1;
            tunel_bus ++;
            //printf("Tunel je prosao sa severa bus %ld \n", index);
            pthread_mutex_unlock(&mutex);

            sleep(rand()%5);
            printf("Tunel je prosao sa severa bus %ld \n", index);

            pthread_mutex_lock(&mutex);
            u_tunelu --;
            tunel_bus --;
            if( u_tunelu == 0 )
            {
                smer = 0;
                pthread_cond_broadcast(&condJ);
                pthread_cond_broadcast(&condS);
            }
            else if ( tunel_bus < 1) // izasao je bus, mogu da se nalaze kola, ali to ne sprecava neki drugi bus
            {
                pthread_cond_broadcast(&condS);
            }
            pthread_mutex_unlock(&mutex);
        }

        else if( vozilo == 2)
        {
            printf("Tunelu je sa severa prisao kamion %ld \n", index);

            pthread_mutex_lock(&mutex);
            while ( smer == 2 || tunel_kamion >= 1 || ceka_hitna_s >= 1 || tunel_bus >= 1 || tunel_auto >= 1 || tunel_hitna >= 1)
            {
                pthread_cond_wait(&condS, &mutex);
            }
            u_tunelu ++;
            smer = 1;
            tunel_kamion ++;
            //printf("Tunel je prosao sa severa kamion %ld \n", index);
            pthread_mutex_unlock(&mutex);

            sleep(rand()%5);
            printf("Tunel je prosao sa severa kamion %ld \n", index);

            pthread_mutex_lock(&mutex);
            u_tunelu --;
            tunel_kamion --;
            if( u_tunelu == 0 )
            {
                smer = 0;
                pthread_cond_broadcast(&condJ);
                pthread_cond_broadcast(&condS);
            }
            pthread_mutex_unlock(&mutex);
        }

        else if( vozilo == 3)
        {
            printf("Tunelu je sa severa prislo hitno vozilo %ld \n", index);

            pthread_mutex_lock(&mutex);
            ceka_hitna_s ++;
            pthread_mutex_unlock(&mutex);

            pthread_mutex_lock(&mutex);
            while ( smer == 2 || tunel_kamion >= 1 )
            {
                pthread_cond_wait(&condS, &mutex);
            }
            ceka_hitna_s --;
            u_tunelu ++;
            smer = 1;
            tunel_hitna ++;
            //printf("Tunel je proslo sa severa hitno vozilo %ld \n", index);
            pthread_mutex_unlock(&mutex);

            sleep(1);
            printf("Tunel je proslo sa severa hitno vozilo %ld \n", index);

            pthread_mutex_lock(&mutex);
            u_tunelu --;
            tunel_hitna --;
            if( u_tunelu == 0 )
            {
                smer = 0;
                pthread_cond_broadcast(&condJ);
                pthread_cond_broadcast(&condS);
            }
            else
            {
                pthread_cond_broadcast(&condS);
            }
            pthread_mutex_unlock(&mutex);
        }
    }

}

void * workJ( void * i)
{
    long index = (long) i;

    while(1)
    {

        int vozilo = rand() % 4; // 0 - auto, 1 - bus, 2 - kamion, 3 - hitno vozilo
        sleep(rand()%5);
        
        if( vozilo == 0)
        {
            printf("Tunelu je sa juga prisao auto %ld \n", index);

            pthread_mutex_lock(&mutex);
            while ( smer == 1 || tunel_auto >= 3 || tunel_kamion >= 1 || ceka_hitna_j >= 1 )
            {
                pthread_cond_wait(&condJ, &mutex);
            }
            u_tunelu ++;
            smer = 2;
            tunel_auto ++;
            //printf("Tunel je prosao sa juga auto %ld \n", index);
            pthread_mutex_unlock(&mutex);

            sleep(rand()%5);
            printf("Tunel je prosao sa juga auto %ld \n", index);

            pthread_mutex_lock(&mutex);
            u_tunelu --;
            tunel_auto --;
            if( u_tunelu == 0 )
            {
                smer = 0;
                pthread_cond_broadcast(&condJ); //nema nikog
                pthread_cond_broadcast(&condS);
            }
            else if ( tunel_auto < 3) 
            {
                pthread_cond_broadcast(&condJ); // izasla su kola, mogu neka druga kola da udju
            }
            pthread_mutex_unlock(&mutex);

        }

        else if( vozilo == 1)
        {
            printf("Tunelu je sa juga prisao bus %ld \n", index);

            pthread_mutex_lock(&mutex);
            while ( smer == 1 || tunel_kamion >= 1 || ceka_hitna_j >= 1 || tunel_bus >= 1)
            {
                pthread_cond_wait(&condJ, &mutex);
            }
            u_tunelu ++;
            smer = 2;
            tunel_bus ++;
            //printf("Tunel je prosao sa juga bus %ld \n", index);
            pthread_mutex_unlock(&mutex);

            sleep(rand()%5);
            printf("Tunel je prosao sa juga bus %ld \n", index);

            pthread_mutex_lock(&mutex);
            u_tunelu --;
            tunel_bus --;
            if( u_tunelu == 0 )
            {
                smer = 0;
                pthread_cond_broadcast(&condJ);
                pthread_cond_broadcast(&condS);
            }
            else if ( tunel_bus < 1) // izasao je bus, mogu da se nalaze kola, ali to ne sprecava neki drugi bus
            {
                pthread_cond_broadcast(&condJ);
            }
            pthread_mutex_unlock(&mutex);
        }

        else if( vozilo == 2)
        {
            printf("Tunelu je sa juga prisao kamion %ld \n", index);

            pthread_mutex_lock(&mutex);
            while ( smer == 1 || tunel_kamion >= 1 || ceka_hitna_j >= 1 || tunel_bus >= 1 || tunel_auto >= 1 || tunel_hitna >= 1)
            {
                pthread_cond_wait(&condJ, &mutex);
            }
            u_tunelu ++;
            smer = 1;
            tunel_kamion ++;
            //printf("Tunel je prosao sa juga kamion %ld \n", index);
            pthread_mutex_unlock(&mutex);

            sleep(rand()%5);
            printf("Tunel je prosao sa juga kamion %ld \n", index);

            pthread_mutex_lock(&mutex);
            u_tunelu --;
            tunel_kamion --;
            if( u_tunelu == 0 )
            {
                smer = 0;
                pthread_cond_broadcast(&condJ);
                pthread_cond_broadcast(&condS);
            }
            pthread_mutex_unlock(&mutex);
        }

        else if( vozilo == 3)
        {
            printf("Tunelu je sa juga prislo hitno vozilo %ld \n", index);

            pthread_mutex_lock(&mutex);
            ceka_hitna_j++;
            pthread_mutex_unlock(&mutex);

            pthread_mutex_lock(&mutex);
            while ( smer == 1 || tunel_kamion >= 1 )
            {
                pthread_cond_wait(&condJ, &mutex);
            }
            ceka_hitna_j--;
            u_tunelu ++;
            smer = 1;
            tunel_hitna ++;
            //printf("Tunel je proslo sa juga hitno vozilo %ld \n", index);
            pthread_mutex_unlock(&mutex);

            sleep(1);
            printf("Tunel je proslo sa juga hitno vozilo %ld \n", index);

            pthread_mutex_lock(&mutex);
            u_tunelu --;
            tunel_hitna --;
            if( u_tunelu == 0 )
            {
                smer = 0;
                pthread_cond_broadcast(&condJ);
                pthread_cond_broadcast(&condS);
            }
            pthread_mutex_unlock(&mutex);
        }
    }

}



int main()
{
    pthread_t threads[S+J];

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init (&condS, NULL);
    pthread_cond_init (&condJ, NULL);

    for(long i = 0; i < S; i++)
    {
        pthread_create(threads + i , NULL, workS, (void *) i);
    }

    for(long i = 0; i < J; i++)
    {
        pthread_create(threads + S + i , NULL, workJ, (void *) i);
    }

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

    pthread_cond_destroy(&condJ);
    pthread_cond_destroy(&condS);
    pthread_mutex_destroy(&mutex);

    return 0;
}