#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>

/*
 * Producer consumer with bound buffers example
 *
 * Jose Rogado, January 2015
 */
 
pthread_mutex_t mutex;
pthread_cond_t empty;;
pthread_cond_t full;

int count = 0;
int in = 0;
int out = 0;

#define N 10
#define SIZE 32

FILE *rfd, *wfd;


char buffer[N][SIZE];
int active = 1;

int get_data(char *data)
{
    if (fgets(data, SIZE, rfd) == NULL){
      // active = 0;
      return -1;
    }
   return(strlen(data));
}

void put_data(char *data)
{
	fputs(data, wfd);
	//fprintf(wfd, "%s\n", data);
	fflush(wfd);
}

void producer()
{
	char data[SIZE];
	int size;

	while(active) {
		if ((size = get_data(data)) < 0) {
			break;
		}
		pthread_mutex_lock(&mutex);
		if (count == N)
			// Espera que haja buffers vazios 
			pthread_cond_wait(&empty, &mutex);
		strncpy(buffer[in], data, size+1);
		// buffer[in] = data;
		in = (in + 1) % N;
		count++;
		pthread_mutex_unlock(&mutex);
		printf("Producer: count = %d\n", count);
		pthread_cond_signal(&full);
	}
	active = 0;
	pthread_cond_signal(&full);
	printf("Producer exiting active = %d\n", active);
	pthread_exit(NULL);
}

void consumer()
{
	char data[SIZE];

	while(active) {
		pthread_mutex_lock(&mutex);
		if (count == 0)
			// Espera que haja buffers cheios		
			pthread_cond_wait(&full, &mutex);
		strncpy(data, buffer[out], strlen(buffer[out])+1);
		//data = buffer[out];
		out = (out + 1) % N;
		count--;
		pthread_mutex_unlock(&mutex);
		printf("Consumer: count = %d\n", count);
		// Assinala buffers vazios
		pthread_cond_signal(&empty);
		put_data(data);
	}
	printf("Consumer exiting active = %d\n", active);
	pthread_exit(NULL);
}

char init_string[] = "Hello how are you?\n";

int main(int argc, char *argv[])
{
	
	pthread_t consumer_thread;
	pthread_t producer_thread;
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init (&full, NULL);
	pthread_cond_init (&empty, NULL);
	
   /* Open the first named pipe for reading */
	printf("Opening pipe1\n");
    rfd = fopen("FIFO1", "r");
    if (rfd == 0) {
        perror("open");
        exit(1);
    }	

    /* Open the second named pipe for writing */
	printf("Opening pipe2\n");
    wfd = fopen("FIFO2", "w");
    if (wfd == 0) {
        perror("open");
        exit(1);
    }
    
	//~ // Populate buffer pool to simulate full situation
	//~ int i;
	//~ for (i = 0; i < N; i++) {
		//~ strncpy(buffer[i], init_string, sizeof(init_string)+1);
		//~ count++;
		//~ in = (in + 1) % N;
	//~ }
	pthread_create(&producer_thread, NULL, (void *)(&producer), (void *)NULL);
	pthread_create(&consumer_thread, NULL, (void *)(&consumer), (void *)NULL);
	
	pthread_join(producer_thread, NULL);
	pthread_join(consumer_thread, NULL);
	printf("Exiting\n");
	return 0;
}
