#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
#include <errno.h>
#include <malloc.h>
#include "semaphore.h"

#define CAPACITY 10

int verbose = 0;
int interval = 1000;

typedef struct timeval Timeval;

typedef struct {
  // put your code here
} Environment;

Environment *make_environment ()
{
  Environment *env = (Environment *) malloc (sizeof (Environment));
  // put your code here
  return env;
}

/* DRANDOM: choose a random floating-point number between zero and
   one, based on a 31-bit random integer */

double drandom ()
{
  return (double) (random() & 0x7fffffff) / (double) 0x7fffffff;
}

/* CHOOSE FROM EXPONENTIAL : choose a value from an exp distribution
   with the given parameter lambda */

double choose_from_exponential (double lambda)
{
  double x;

  do x = drandom (); while (x == 0.0);
  return -log (drandom ()) / lambda;
}

/* MICROSLEEP: sleep for the specified number of microseconds */

void microsleep (int usecs)
{
  Timeval time[1];
  time->tv_sec = 0;
  time->tv_usec = usecs;
  select (0, NULL, NULL, NULL, time);
}

/* RANDOM_SLEEP: choose a random number with mean=duration and
   sleep for that number of microseconds */

void random_sleep (double duration)
{
  int time = (int) choose_from_exponential (1/duration);
  microsleep (time);
}

/* PRODUCER: the producer loops forever, filling the coke machine */

void *producer_entry (void *arg)
{
  Environment *env = (Environment *) arg;

  while (1) {

    // put your code here

    printf ("I put a coke in the machine.");

    // put your code here

    random_sleep (1.0);
  }
}

/* CONSUMER: the consumer drinks ten cokes and then collapses in
   a sugar/caffeine induced coma */

void *consumer_entry (void *arg)
{
  int i;
  Environment *env = (Environment *) arg;

  for (i=0; i<10; i++) {
    // put your code here

    printf ("I took a coke.");

    // put your code here

    random_sleep (2.0);
  }

  pthread_exit (NULL);
}

int main ()
{
  Environment *env;
  pthread_t producer;
  pthread_t consumer;
  int i, ret;

  env = make_environment ();

  srandom (17);

  ret = pthread_create (&producer, NULL, producer_entry, (void *) env);
  if (ret == -1) {
    perror ("pthread_create failed");
    exit (-1);
  }

  for (i=0; i<2; i++) {
    ret = pthread_create (&consumer, NULL, consumer_entry, (void *) env);
    if (ret == -1) {
      perror ("pthread_create failed");
      exit (-1);
    }
  }

  ret = pthread_join (producer, NULL);
  if (ret == -1) {
    perror ("pthread_join failed");
    exit (-1);
  }
  
  return 0;
}
