#include "misc.h"
#include "event.h"
#include "rand48.h"
#include "math.h"
#include <stdio.h>
#include <stdlib.h>

typedef double TIME;

#ifdef NDEBUG
int db(){}
#else
#define db printf
#endif

#define slotSize 1.000001
#define NUsers 0    /* 0 means infinite */
#define lambda 0.183    /* global arrival rate */
#define x (lambda/600)  /* local retry rate, geared for ... hosts */
#define every 10000
#define print 1

void Transmit(void *);
void Check(void *);
void Done(void *);
void Lost(void *);
void EndOfSim(void *);

static int busy;   /* how many packets are currently on the link? */
static int Yes = 1, No = 0;
static int numBackLogged;
static long successes;


void Status(const char s[], const int backLogged)
{
    static int count;
    if(count % every < print)
	db("%.10g(%g): b:%d n:%d %s(%d)\n", EventNow(), successes/(EventNow()==0?1:EventNow()), busy, numBackLogged, s, backLogged);
    ++count;
}

/* p points to Yes or No and indicates if we're a backlogged transmitter */
void Transmit(void *p)
{
    int const backLogged = *(int*) p;

    Status("Transmit", backLogged);

    if(!backLogged) /* insert next NEW packet arrival */
	EventInsert(Transmit, -1/lambda * log(drand48()), &No);

    if(!busy)   /* OK so far */
	EventInsert(Check, 1.0, p);
    else    /* we collide immediately */
	EventInsert(Lost, 1.0, p);

    ++busy;
}


void Check(void *p)
{
    int const backLogged = *(int*)p;

    Status("Check", backLogged);

    --busy;
    if(!busy)   /* packet got through OK */
    {
	++successes;
	if(backLogged)
	    --numBackLogged;
    }
    else        /* we collided */
    {
	if(!backLogged)     /* we are now */
	    ++numBackLogged;
	EventInsert(Transmit, -1/x * log(drand48()), &Yes);
    }
}


void Lost(void *p)
{
    int const backLogged = *(int*)p;

    Status("Lost", backLogged);

    --busy;
    if(!backLogged)
	++numBackLogged;
    EventInsert(Transmit, -1/x * log(drand48()), &Yes);
}


void Die(void *p)
{
    printf("Die!\n");
    exit(0);
}


void Simulate(void)
{
    EventInfo *e;
    
    while((e = EventNext()))
	free(e);
}

int main(int argc, char *argv[])
{
    EventListInit(2000);
    EventInsert(Transmit, 0.0, &No);
    EventInsert(Die, 1000000.0, &No);

    Simulate();

    return 0;
}
