#include "tree.h"
#include "rand21.h"
#include "dom.h"
#include <stdlib.h>

#define exp2(tseed) (-log(rand2(tseed)))

point *dominating(double time,       /* Value of -M */
		  double pmin,       /* Proportion of points in */
				     /* dominating process retained */
				     /* in minimum process */
		  double exp_param,
		  long seed,         /* Time seed */
		  long seedtwo,      /* Mark seed */
		  long seedthree     /* Pos. seed */
		)
{
  int i=0;
  double sum=0;
  long iseed;
  long tseed;
  long mseed;
  long pseed;
  double nbtime;   /* New birth time */
  double ldtime=0; /* Last death time */
  point *newpoint;
  point *points=NULL;  /* Pointer to the tree of points.  */
                       /* Returned at end. */

  /* Initializations */
  iseed=seed;
  tseed=seed;
  mseed=seedtwo;
  pseed=seedthree;

/* This next chunk calculates a Poisson(exp\_param) using a 
   sum of exponentials, initializing a new point and inserting it 
   into the tree of points on each iteration. */
  for(sum=exp2(&iseed); sum<=exp_param; ++i){
    sum+=exp2(&iseed);                         /* Update Poisson */
					       /* parameter */

    newpoint=newnode(0,&tseed,&mseed,&pseed);  /* Initialize new */
					       /* point */

    points=insert_dom(points,newpoint); /* Insert new node in tree */
					/* of points */
  }

  ldtime+=exp1(&tseed)/exp_param;    /* Initialize last death time */

/* Initialize next birth time */
  if(i>0)
    nbtime=left(points)->birth;
  else
    nbtime=ldtime+1;

  while((ldtime<time) || (nbtime<time)){

    if(ldtime<=nbtime){
	  
/* Initialize new point */
      newpoint=newnode(ldtime,&tseed,&mseed,&pseed);

/* If new point born before nbtime or process currently empty */
      if((newpoint->birth < nbtime)||(points==NULL))
	nbtime=newpoint->birth;                  /* Update nbtime */

/* Insert new node in tree of points */
      points=insert_dom(points,newpoint);

      ldtime+=exp1(&tseed)/exp_param;           /* Update ldtime */
    }
    else{

/* Remove point and change nbtime */
      if(nbtime==left(points)->birth){
	points=remove_left(points);
      }
      else{  /* If we get here something is seriously wrong! */
	fprintf(stderr,"Serious error in algorithm warning!");
	exit(3);
      }

/* If process now empty ensure that the next thing to happen is 
   for a point to be born */
      if(points==NULL)
	nbtime=ldtime+1;
      else
	nbtime=left(points)->birth;
    }
  }

/* Now we decide which points are alive in the minimum process 
   and mark them as such. */
  applyinorder(points,in_min,&pmin);
/* Finally, we transform the tree so that it is ordered by death 
   times rather than birth times. */
  points=birth_to_death(points);

  return points;
}

void in_min(point * node, /* Used in conjunction with */
	    void *arg     /* applyinorder to initialize min\_life */
	    )             /* for each point using the value of */
			  /* *((double *)arg) for pmin */
{
  double *pmin;

  pmin = (double *) arg;

  if(node->mark > *pmin)
    node->min_life=0;
  else
    node->min_life=1;
}
