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


typedef struct node
{
	int Value;
	struct node *Next;
}node;

typedef struct
{
	node *Head;
	node *Tail;  
	pthread_mutex_t Mutex;
}queue;

node *alloc_node(int Value, node *Next)
{
  	node *NewNode = malloc(sizeof(node));
  	NewNode->Value = Value;
  	NewNode->Next = Next;
      
	return NewNode;
}

// NOTE: we are not going to talk about threads.
// the lock and unlock functions prevent the threads to execute the locked part at the same time,
// which could lead to errors
void enqueue(queue *Queue, int Value)
{
	node *NewNode = alloc_node(Value, 0);
	pthread_mutex_lock(&Queue->Mutex);
	if(Queue->Tail)
		Queue->Tail->Next = NewNode;
	Queue->Tail = NewNode;
	if(!Queue->Head)
	{
		Queue->Head = NewNode;
	}
	pthread_mutex_unlock(&Queue->Mutex);
}


int dequeue(queue *Queue)
{
	pthread_mutex_lock(&Queue->Mutex);
	node *First = Queue->Head;
	int Result = First->Value;
	Queue->Head = First->Next;
	free(First);
	pthread_mutex_unlock(&Queue->Mutex);
	return Result;
}

node *peak(queue *Queue)
{
	return Queue->Head;
}

queue CommunicationQueue;

void *Producer_Proc(void *ptr)
{
	int Seed = atoi((char *)ptr);
	srand(Seed);
	for (int i = 0; i < 100; i ++)
	{
		enqueue(&CommunicationQueue, (rand()%10)+1);
	}
	return 0;
}

int main(int argc, char **argv)
{
	CommunicationQueue.Head = 0;
	CommunicationQueue.Tail = 0;
	pthread_mutex_init(&CommunicationQueue.Mutex,0); 

	pthread_t Producer;

	pthread_create(&Producer, 0, Producer_Proc, (void *)argv[1]);

	// TODO: print 50 times the sum of the last two numbers from the queue
	// don't forget to check if there is even anything on the queue 

	pthread_join(Producer, 0);

	return 0;
}
