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

pthread_mutex_t count_mutex     = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t count_mutex2     = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  condition_var   = PTHREAD_COND_INITIALIZER;
pthread_t thread1, thread2, thread3, thread4;


pthread_barrier_t barrier1; 
pthread_barrierattr_t attr;
//pthread_barrier_init(&barrier1, &attr, num_threads);


int zero_joined;
void *functionCount1();
void *functionCount2();
int  count = 0;
#define COUNT_DONE  10
#define COUNT_HALT1  3
#define COUNT_HALT2  6

int here[] = {0, 0, 0, 0};

main()
{
   //pthread_t thread1, thread2, thread3, thread4;
	unsigned int t_ids[] = {0, 1, 2, 3};   // = (unsigned int *)malloc( sizeof(unsigned int) * Threads );
	pthread_barrier_init(&barrier1, &attr, 4);

   pthread_create( &thread1, NULL, &functionCount1, (void*)&t_ids[0]);
   pthread_create( &thread2, NULL, &functionCount1, (void*)&t_ids[1]);
	pthread_create( &thread3, NULL, &functionCount1, (void*)&t_ids[2]);
	pthread_create( &thread4, NULL, &functionCount1, (void*)&t_ids[3]);


  pthread_join( thread1, NULL);
   pthread_join( thread2, NULL);
	pthread_join( thread3, NULL);
	pthread_join( thread4, NULL);

   printf("Final count: %d\n",count);

   exit(0);
}

// Write numbers 1-3 and 8-10 as permitted by functionCount2()

void *functionCount1(void *tids)
{
	int i = 0;
	unsigned int id = *(unsigned int*)tids;
	printf("joined %u\n\n", id);
	int open = 0;

	for(i=0; i<12; i++){
		//pthread_cond_wait( &condition_var, &count_mutex );
		sleep(1);
		pthread_barrier_wait(&barrier1);
		printf("t%u p%d\n", id, i);
		//block of cude !!!!!!!!!!!!!!!!!


		//here[id] = 1;  //finished with this thread's work


		//pthread_mutex_lock( &count_mutex );
		//	while(!all_finished){
		///		pthread_cond_wait( &condition_var, &count_mutex );  //wait untill all threads are finished
		//	}
		//pthread_mutex_unlock( &count_mutex );

		//if(id == 0){
		//	count=0;
		//	zero_joined = 1;
		//	pthread_cond_broadcast(&condition_var);
		//	printf("%u reset\n", id);
		//}else{
		//	while(zero_joined == 0)
		//		sleep(1);
		//}

		//here[id] = 1;
		//pthread_mutex_lock( &count_mutex );
		//here[id] = 1;
		//while(open != 4){
		//	open = 0;
		//	for(i=0; i<4; i++){
		//		if(here[i])
		//			open++;
		//	}
		//	pthread_cond_wait( &condition_var, &count_mutex );

		//}
		//pthread_mutex_unlock( &count_mutex );
		//sleep(1);


		//while(count != 4){
		//	sleep(1);
		//}

		//pthread_cond_wait( &condition_var, &count_mutex );
		//pthread_mutex_lock( &count_mutex );
		//if(id == 0){
		//	count=0;
		//	pthread_cond_broadcast(&condition_var);
		//	//pthread_cond_signal( &condition_var );
		//	printf("%u reset\n", id);
		//	//count=0;
		//}

		//pthread_cond_wait( &condition_var, &count_mutex );

		printf("%u passed\n", id);

		//pthread_mutex_unlock( &count_mutex );
	}
}

/*
		pthread_mutex_lock( &count_mutex );
		first++;
		pthread_mutex_unlock( &count_mutex );

		pthread_mutex_lock( &count_mutex2 );
		count++;
		
		sleep(untill all processes have passed gate 1);

		pthread_mutex_unlock( &count_mutex2 );


		printf("%u done.\n", id);


		if(id == 0){
			printf("%u locked\n", id);
			//first = 1;
			sleep(2);
   			//pthread_join( thread1, NULL);

			pthread_cond_signal( &condition_var );
   			//pthread_join( thread2, NULL);
    		//pthread_join( thread3, NULL);
    		//pthread_join( thread4, NULL);

			//pthread_cond_signal( &condition_var );

			//pthread_cond_wait( &condition_var, &count_mutex );
			printf("\nunlocked!\n");
		}else{
			sleep(1);
			pthread_cond_wait( &condition_var, &count_mutex );
			//pthread_cond_signal( &condition_var );
		}
*/
		//printf("%u done.\n", id);
		//pthread_mutex_unlock( &count_mutex );
		//if(first){
		//	pthread_cond_wait( &condition_var, &count_mutex );
		//	printf("unlocked!\n");
		//	first = 1;
		//}







	   //for(;;)
   		//{

      // Lock mutex and then wait for signal to relase mutex

		//if(id == 0)
		//	sleep(5);

	//if(id == 1)
      //pthread_mutex_lock( &count_mutex );

      // Wait while functionCount2() operates on count
      // mutex unlocked if condition varialbe in functionCount2() signaled.

	//if(id == 1)
	//here[id] = 1;
	//for(i=0; i<4; i++){
	//	if(i != id)
	//		if(here[i]){
	//			first = 0;
	//			break;
	//		}
			//if(here[i] == 1 && i != id)
			//first = 0;
	//}
	//memset((void*)here, '\0', sizeof(int)*4);
	//if(first){
	//	pthread_cond_signal( &condition_var );
		//memset((void*)here, '\0', sizeof(int)*4);
	//}
	//first = 0;
	//for(i=0; i<4; i++){

		//pthread_mutex_lock( &count_mutex );

		//if(id != 1)
		//	pthread_cond_wait( &condition_var, &count_mutex );

		
	//	printf("t%u: sleeping\n", id);
	//	sleep(1);


		//pthread_mutex_unlock( &count_mutex );
	//	for(i=0; i<4; i++){
			
	//	pthread_cond_wait( &condition_var, &count_mutex );
//		if(id == 1){
			//printf("t%u: sleeping\n", id);
			//sleep(4);
	//	if(id == 1){
	//		pthread_cond_signal( &condition_var );
	//		printf("t%u: unlocked\n\n", id);
	//	}
//		}else{
//			printf("t%u: waiting for t1 to unlock\n", id);
  //    		pthread_cond_wait( &condition_var, &count_mutex );
	//		printf("t%u: passed\n", id);
		//}

	//}
	

      //count++;
      //printf("ID: %u\n", id);

	//if(id == 1)
      //pthread_mutex_unlock( &count_mutex );

      //if(count >= COUNT_DONE) return(NULL);
    //}
//}

// Write numbers 4-7

void *functionCount2()
{
    for(;;)
    {
       pthread_mutex_lock( &count_mutex );

       if( count < COUNT_HALT1 || count > COUNT_HALT2 )
       {
          // Condition of if statement has been met. 
          // Signal to free waiting thread by freeing the mutex.
          // Note: functionCount1() is now permitted to modify "count".
          pthread_cond_signal( &condition_var );
       }
       else
       {
          count++;
          printf("Counter value functionCount2: %d\n",count);
       }

       pthread_mutex_unlock( &count_mutex );

       if(count >= COUNT_DONE) return(NULL);
    }

}
