/*** There was some bug in James' do_creation ***/
/*** I need to introduce metabolites to the environment***/

/* This file holds the procedures for running through the population */
/* and letting the critters execute their metabolisms.  This happens */
/* in an interleaved fashion, so that each critter gets a chance to do */
/* one reaction and then it is the next critters turn.  We keep */
/* cycling through the population until the critter with the longest */
/* metabolism has finished.*/

#include <stdio.h>
#include "types.h"
#include "metab_cycle.h"
#include "debug.h"

#define EXAMINE 1   /*local debugging constant*/

#define GUTSIZE 1 /*This scales linearly the amount of food a critter */
		  /*is allowed to keep in its gut as a function of its */
		  /*metabolism length.*/

/* Ideally we'd like to avoid giving a critter a "turn" to metabolize */
/* once it has finished with its entire metabolism.  So I have set up */
/* a doubly linked list.  When a critter finishes, it cuts itself out */
/* of the doubly linked list.  We keep running through the remaining */
/* population until it is empty.  This means we have to restore the */
/* doubly linked list at the start.  But that is easy because the */
/* population already has the doubly linked list in "p_next" and */
/* "p_prev." */

  /* If there are no more metabolism reactions in the population to */
  /* do, the_population->metabolizer should be NULL, since everyone */
  /* should have cut themselves out of the metabolizing list.  If so, */
  /* this returns TRUE, else it returns FALSE.*/

Boolean empty(Population *the_population)
{
#ifdef DEBUG
  printf(" ---in empty---\n");
#endif

  if (the_population->metabolizer == NULL) return TRUE;
  else return FALSE;

#ifdef DEBUG
  printf(" ---end empty---\n");
#endif
}



  /* If a critter has finished iterating through its metabolism this */
  /* returns TRUE, but if it is not done yet, it returns FALSE.*/

Boolean done_metabolizing(Critter *little_dude)
{
#ifdef DEBUG
  printf(" ---checking done_metabolizing---\n");
  if (little_dude == NULL) printf("YIKES! Trying to check a null critter.\n");
#endif

  if (little_dude->next_reaction == NULL) return TRUE;
  else return FALSE;
}


  /* When an organism has finished with its metabolism and has been */
  /* cut out of the list, it should reset its metabolism so that */
  /* "do_next_reaction" will do the first reaction in its */
  /* metabolism.*/

void reset_metabolism(Critter *little_dude)
{
#ifdef DEBUG
  printf(" ---in reset_metabolism---\n");
#endif

  little_dude->next_reaction = little_dude->fast_metabolism;

#ifdef DEBUG
  printf(" ---end reset_metabolism---\n");
#endif
}


void do_next_reaction(Critter *little_dude, Population *the_population)
{
#ifdef EXAMINE
  printf(" ---in do_next_reaction---\n");
#endif

  if (little_dude->next_reaction->reaction_type==CREATION)
      do_creation(little_dude);
  else
      do_breakdown(little_dude);

  /*WARNING: this is confusing.  We have a field in Critter called */
  /*"next_reaction" and a field in the Reaction structure called */
  /*"next_reaction."  So this looks a bit wierd, but we are just */
  /*getting the next reaction in the Critter's fast metabolism linked */
  /*list.*/

  little_dude->next_reaction = little_dude->next_reaction->next_reaction;

#ifdef EXAMINE
  printf(" ---end do_next_reaction---\n");
#endif
}



void do_breakdown(Critter *little_dude)
{
#ifdef EXAMINE
  printf(" ---in do_breakdown---\n");
#endif

    if (little_dude->gut[little_dude->next_reaction->first_reactant]>0)
      {
	get_energy(little_dude);
	--little_dude->gut[little_dude->next_reaction->first_reactant];
	++little_dude->gut[little_dude->next_reaction->second_reactant];
      }
    else if (little_dude->mouth!=NULL) /*check to see if mouth is latched on somewhere*/
      {
        if (little_dude->mouth->gut[little_dude->next_reaction->first_reactant]>0)
          {
            get_energy(little_dude);
            --little_dude->mouth->gut[little_dude->next_reaction->first_reactant];
	    --little_dude->mouth->amt_food;
            ++little_dude->gut[little_dude->next_reaction->second_reactant];
	    ++little_dude->amt_food;
          }
      }
    else if (the_population->environment[little_dude->next_reaction->first_reactant]>0)
      {
	get_energy(little_dude);
	--the_population->environment[little_dude->next_reaction->first_reactant];
	++little_dude->gut[little_dude->next_reaction->second_reactant];
	++little_dude->amt_food;
      }

#ifdef EXAMINE
  printf(" ---end do_breakdown---\n");
#endif
}


  /*This procedure locates the two reactants and performs a creation */
  /*reaction.  There are some subtleties here.  First the critter */
  /*looks in its own gut for the reactant.  If it is not there, it */
  /*checks the critter it is attached to via its mouth.  If it is not */
  /*there, it checks the environment.  However, if there is only one */
  /*reactant of the desired type in one of those places, we have to */
  /*avoid taking it twice, but we can't take a reactant until we know */
  /*we can find both to perform the reaction.  But that is only true */
  /*if we are using two of the same kind of reactants.*/

void do_creation(Critter *little_dude)
{
  Gut *first_gut;
  Gut *second_gut;
  Critter *first_critter,  *second_critter;
  int first_react, second_react, product;
  Boolean bypass; /*This flags if the second gut pointer has to bypass*/

#ifdef EXAMINE
  printf(" ---in do_creation---\n");
#endif

  first_critter = NULL;
  second_critter = NULL;
  bypass  = FALSE;  
  first_react = little_dude->next_reaction->first_reactant;
  second_react = little_dude->next_reaction->second_reactant;

  /*Find the first reactant*/

  if (little_dude->gut[first_react]>0) 
    {
      first_gut=little_dude->gut;
      first_critter = little_dude;
    }
  else 
    if (little_dude->mouth != NULL &&
	little_dude->mouth->gut[first_react]>0)
      {
	first_gut = little_dude->mouth->gut;
	first_critter = little_dude->mouth;
      }
  else 
    if (the_population->environment[first_react]>0) 
      first_gut=the_population->environment;
  else first_gut=NULL;

#ifdef EXAMINE
  printf(" ---between stuff in do_creation---\n");
#endif


  /*Find the second reactant.*/

  if (little_dude->gut[second_react]>0) 
    {
      second_gut = little_dude->gut;
      second_critter = little_dude;
    }
  else 
    if (little_dude->mouth != NULL &&
	little_dude->mouth->gut[second_react]>0)
      {
	second_gut = little_dude->mouth->gut;
	second_critter = little_dude->mouth;
      }
  else 
    if(the_population->environment[second_react]>0) 
      second_gut=the_population->environment;
  else second_gut=NULL;

#ifdef EXAMINE
  printf(" ---middle of do_creation---\n");
#endif

  second_gut = avoid_pointer_collision(first_react, second_react,
				       first_gut, second_gut,
				       little_dude, &second_critter); 

  /*Now actually do the creation.*/
  if ((first_gut!=NULL) && (second_gut!=NULL))
    {
      --first_gut[first_react];
      if (first_critter != NULL) --first_critter->amt_food;

      --second_gut[second_react];
      if (second_critter != NULL) --second_critter->amt_food;

      product = first_react + second_react;

      ++little_dude->gut[product];
      ++little_dude->amt_food;
    }

#ifdef EXAMINE
  printf(" ---end do_creation---\n");
#endif
}

  /*This procedure checks the two gut pointers, and the reactants to */
  /*make sure we don't use the same reactant twice in a creation */
  /*reaction.  If it finds a problem, it attempts to fix it by */
  /*reassigning the second gut pointer.  The double pointer is a */
  /*kludge to modify the second_critter as well as returning the */
  /*possibly new second_gut.*/

Gut *avoid_pointer_collision(int first_react, int second_react, 
			     Gut *first_gut, Gut *second_gut, 
			     Critter *dude, Critter **p_second_critter)
{
  Critter *second_critter;
  
#ifdef EXAMINE
  printf(" ---in avoid_pointer_collision---\n");
#endif
  
  second_critter = NULL;
  
  if (first_react == second_react && first_gut == second_gut &&
      first_gut != NULL && first_gut[first_react] <= 1)
    {   /*Try to find a better second gut.*/
      
      if (dude->mouth != NULL &&
	  (first_gut != dude->mouth->gut &&
	   dude->mouth->gut[second_react] > 0))
	{
	  second_gut = dude->mouth->gut;
	  *p_second_critter = dude->mouth;
	}
      else 
	if (first_gut != the_population->environment && 
	    the_population->environment[second_react] > 0)
	  second_gut = the_population->environment;
	else second_gut = NULL;
      
    }

#ifdef EXAMINE
  printf(" ---end avoid_pointer_collision---\n");
#endif
  
  return second_gut;
}


  /* The energy a critter gets from a reaction x -> y is 
     2^(x-y) - 1.  For example 2->1 = 2 - 1.  And 
     4->2 = 4 - 1. */

void get_energy(Critter *little_dude) /* give critter energy */
  {
  int energy_gain;
  int difference;

#ifdef EXAMINE
  printf(" ---in get_energy---\n");
#endif
  
  difference = little_dude->next_reaction->first_reactant -
               little_dude->next_reaction->second_reactant;

  if (difference > 0)
    {
      energy_gain = (1 << difference) - 1;
      little_dude->energy += energy_gain;
    }

#ifdef EXAMINE
  printf(" ---end get_energy---\n");
#endif
}     





int square (int x)
  {
  return x * x;
}

  /*This chooses a random metabolite in the critter's gut and removes */
  /*it.  The metabolite is put back into the environment.  It keeps */
  /*doing this until the amount of food in the critter's gut is below */
  /*the limit (GUTSIZE * metabolism length).*/

void gut_leveler(Critter *little_dude)
{
  int gut_size;
  int which_one;
  int counter;
  
  gut_size= GUTSIZE * little_dude->meta_len;

  while (little_dude->amt_food > gut_size)
    {
      which_one = uniform(little_dude->amt_food) + 1;
      
      for (counter = 0; counter <= NUM_METABOLYTES; counter++)
	{
	  which_one = which_one - little_dude->gut[counter];
	  
	  if (which_one<=0) {
	    --little_dude->gut[counter]; /*remove it from the gut*/
	    --little_dude->amt_food;
	    the_population->environment[counter]++; /*put it in the environment*/
	    counter = NUM_METABOLYTES; /*aborts the for loop.*/
	  }
	}
    }    
}







  }



  /* This procedure removes a critter from the doubly linked list of */
  /* critters who haven't yet finished their metabolism.*/

void cut_out_critter(Critter *little_dude, Population *the_population)
{
#ifdef DEBUG
  printf(" ---in cut_out_critter---\n");
#endif

#ifdef EXAMINE
  printf("I'm cutting myself out: %d\n", little_dude->id_num);
#endif


  if(done_metabolizing(little_dude))
    {
      if (little_dude->prev_metabolizer == NULL)
	the_population->metabolizer = little_dude->next_metabolizer;
      else
	{
	  little_dude->prev_metabolizer->next_metabolizer =
	    little_dude->next_metabolizer; 
	}
      
      if (little_dude->next_metabolizer != NULL)
	{
	  little_dude->next_metabolizer->prev_metabolizer =
	    little_dude->prev_metabolizer; 
	}
      
      little_dude->next_metabolizer = NULL;
      little_dude->prev_metabolizer = NULL;
      reset_metabolism(little_dude);
    }

#ifdef EXAMINE
  print_brief_metabolizers(the_population);
#endif


#ifdef DEBUG
  printf(" ---end cut_out_critter---\n");
#endif
}


  /* This is identical to "iterate_once" below except for one thing.*/
  /* The first time through the metabolizers, the pointers are all */
  /* NULL for the next and previous metabolizer.  We need to reset */
  /* these on the fly.*/

void first_iteration(Population *the_population)
{
  Critter *current_critter;
  Critter *temp;

#ifdef DEBUG
  printf(" ---in first_iteration---\n");
#endif

#ifdef EXAMINE
  print_brief_pop(the_population);
#endif

  /*reset the start of the metabolizer list.*/
  the_population->metabolizer = the_population->critters;

#ifdef EXAMINE
  if (!check_metabolizer_ptrs(the_population))
    printf("YIKES, there is a non-null ptr in the metabolizers.\n");
#endif

  for(current_critter = the_population->metabolizer;
      current_critter != NULL;)
    {
      /*reset the next_metabolizer pointer and the next guy's */
      /*prev_metabolism pointer.*/
      if (current_critter->next_metabolizer == NULL)
	{
#ifdef EXAMINE
  if (the_context->time_step == 38) 
    printf(" ---about to reset metab ptrs---\n");
#endif
	  current_critter->next_metabolizer = current_critter->p_next;
#ifdef EXAMINE
  if (the_context->time_step == 38) 
    printf(" ---about to reset metab prev ptrs---\n");
#endif
	  if (current_critter->next_metabolizer != NULL)
	    current_critter->next_metabolizer->prev_metabolizer =
	      current_critter;
	}


      if (!done_metabolizing(current_critter))
	do_next_reaction(current_critter, the_population);

      if (done_metabolizing(current_critter))
	{
	  /* Because cutting out a critter NULL's the next_metabolizer */
	  /* field, I have to work around it with a temporary variable.*/
#ifdef EXAMINE
  printf(" ---about to cut out---\n");
#endif

	  temp = current_critter;
	  current_critter = temp->next_metabolizer;
	  cut_out_critter(temp, the_population);
#ifdef EXAMINE
  printf(" ---done cutting out---\n");
#endif
	}
      else 
	{
#ifdef EXAMINE
  if (the_context->time_step == 38) 
    printf(" ---about to go to next critter---\n");
#endif
	  current_critter = current_critter->next_metabolizer;
	}
    }

#ifdef EXAMINE
  print_metabolizers(the_population);
#endif

#ifdef DEBUG
  printf(" ---end first_iteration---\n");
#endif
}



  /* This procedure lets everyone remaining in the metabolizers list */
  /* execute one reaction.  The for loop checks to make sure the */
  /* organisms isn't actually done (and for some reason not cut out of */
  /* the list) then it calls "do_next_reaction."  When it comes back, */
  /* we check to see if the organisms has finished now.  If so, we */
  /* carefully update the current_critter pointer for the next */
  /* critter, and then cut that critter out of the metabolism linked */
  /* list.  If the critter is not done, it is left in the list and we */
  /* simply go on to the next critter in the metabolism list.*/

void iterate_once(Population *the_population)
{
  Critter *current_critter;
  Critter *temp;

#ifdef DEBUG
  printf(" ---in iterate_once---\n");
#endif

  for(current_critter = the_population->metabolizer;
      current_critter != NULL;)
    {
      if (!done_metabolizing(current_critter))
	do_next_reaction(current_critter, the_population);

      if (done_metabolizing(current_critter))
	{
	  /* Because cutting out a critter NULL's the next_metabolizer */
	  /* field, I have to work around it with a temporary variable.*/
	  temp = current_critter;
	  current_critter = temp->next_metabolizer;
	  cut_out_critter(temp, the_population);
	}
      else current_critter = current_critter->next_metabolizer;
    }

#ifdef EXAMINE
  print_metabolizers(the_population);
#endif


#ifdef DEBUG
  printf(" ---end iterate_once---\n");
#endif

}

void let_critters_metabolize(Population *the_population)
{
#ifdef DEBUG
  printf(" ---in let_critters_metabolize---\n");
#endif

  first_iteration(the_population);

  while(the_population->metabolizer != NULL)
    iterate_once(the_population);

#ifdef DEBUG
  printf(" ---end let_critters_metabolize---\n");
#endif
}
