/* brain-objs.cc -- a few extra things not in brain-objs.hh, mostly to do
   with reading the files in to start with.

$Log: brain-objs.cc,v $
Revision 1.1  1999/12/27 23:48:46  joanna
Initial revision

Revision 1.3  1997/09/10 01:36:43  joanna
works with robs stuff -- fixed loads more chaining problems,
new rob libraries.  Interactive rob ringrose, not piped yet.

Revision 1.1  1997/08/10 18:25:59  joanna
Initial revision

*/

#include <stdio.h>
#include <stream.h>
// #include <signal.h>
// #include <time.h>
#include "monx.hh"
#include "brain-objs.hh"

static char rcsid[] = "$Id: brain-objs.cc,v 1.1 1999/12/27 23:48:46 joanna Exp joanna $";
/* Brain */

ostream &operator<<(ostream &os, Brain &r) {
  r.print(&os);
  return (os);
} // operator << for Brain

/* this procedure is for reading in lap files -- since C doesn't let
   us create functions on the fly, we have to essentially encode the
   tests on sensor values into something standard (and quickly evaluated)
*/

void Sense::encode_test(char *testst) {
  // first, choose tester and prepare input
  switch (testst[0]) {
  case '!': 
    tester = '!'; testst = &(testst[1]); break;
  case '<': 
    tester = '<'; testst = &(testst[1]); break;
  case '>': 
    tester = '>'; testst = &(testst[1]); break;
  default:
    tester = '='; break;
  } // switch testst[0]

  if (testst[0] == '\'')  // word values tend to start with lisp quote
    testst = &(testst[1]);  // but we don't need it!

  thresh = encode_test_lookup(testst);
} // Sense:: encode_test

// now, a giant stupid hand coded lookup table of values.  Grrr...
// no "eval" in C!   HACKME FIXME breaks for new libraries...

/* possible key words:  (listed by line so emacs can sort them for you)
   
add these?
   blockthresh
   darkthresh
   clutterthresh
   doorthresh

   blocked
   clear
   cluttered
   dark
   nil
   t
*/
int Sense::encode_test_lookup(char *testst) {
  switch (testst[0]) {
    /*
      case 'b': 
      return ((int) BLOCKED);
      case 'c':
      switch (testst[2]) {
      case 'e': 
      return ((int) CLEAR);
      case 'u': 
      return ((int) CLUTTERED);
      }
      case 'd':
      return ((int) DARK);
      */
  case 'n': 
    return ((int) false);
  case 't':
    return ((int) true);
  default:
    cerr << "Unknown sense value " << testst << " argh (barf barf) ack!";
    cerr << "\n  (cough cough) applied to sense " << name << ".\n";
    ::exit (-3);
  }
} // Sense::encode_test_lookup


/* 
  this procedure should only be run once, at startup, after having
  read in and created objects for all the competences, now we go back
  and connect them to each other and their laps or prims.

  As usual, this could do more error checking... it assumes you've cut off
  the beginning and ending parens, so there's just a string of lists
  of lapname, reward, and optionally loss and recovery info.
*/

void Comp::check_comp () { 
  Comp *comp; 

  Comps.reset();
  while ((comp = (Comp *) Comps.next())) {
    comp->do_check();
  } // while each comp
} // Comp::check_comp

void Comp::do_check () {
  int place = 0, placeinc; // place in the string
  char lapname[NAMESIZE];  int reward, loss, recover;  // stuff you read
  int resnum;

  lapnum = count_laps();
  LAPs = new Brain * [lapnum];
  rewards = new int [lapnum];
  int ixi;
  for (ixi = 0; ixi < lapnum; ixi++) {
    resnum = sscanf (&(lapstring[place]), "( %s %d %n %d %d %n", 
		     lapname, &reward, &placeinc, &loss, &recover, &placeinc);
    place += placeinc;
    LAPs[ixi] = find_lap_comp(lapname);
    if (!LAPs[ixi]) {
      cerr << "No such Comp or FAP " << lapname << "!\n";
      exit (-1);
    }
    rewards[ixi] = reward;
    if (resnum > 3) {
      if (loss_rate == 0) {
	loss_rate = new int[lapnum];  recover_rate = new int[lapnum]; 
	priority = new float[lapnum];  // share habituation info
	// make sure non-habituators are initted correctly!
	for (int oxen = 0; oxen < lapnum; oxen++)
	  recover_rate[oxen] = loss_rate[oxen] = 0; 
      }
      loss_rate[ixi] = loss; recover_rate[ixi] = recover;
    } // if there was habituation info
    resnum = sscanf (&(lapstring[place]), ") %n", &placeinc);
    place += placeinc;
  } // for each lap
  if (loss_rate != 0) // if habit info, initialize prorities
      for (ixi = 0; ixi < lapnum; ixi++)
	priority[ixi] = rewards[ixi];
} // Comp::do_check

/*
  This is a bit of a misnomer -- we don't know what class the name is
  when we start looking!  Names should only be ambiguous in that a Comp
  will have a goal LAP of the same name -- we assume you mean the Comp
  unless _this_ is the comp, since only that comp should have use of its
  goal.
*/
Brain * Comp::find_lap_comp(char *mystery) {
  Brain * res;
  // search comps if not looking for own goal
  if (strcmp(name, mystery) && (res = Comps.safefind(mystery)))
    return (res);
  // otherwise search laps
  Lap * lap = new Lap;
  if ((res = lap->find_lap(mystery))) {
    return (res);
  }
  return (0);
} // Comp::find_lap_comp
