/* brain-read.cc -- read in the little lap scripts, set up the brain
   objects.  Also, the INTerface function... (er, maybe!)

   New of SenseTest and Comp both do some parsing as well, see
   brain-objs.cc/hh

   $Log: brain-read.cc,v $
   Revision 1.1  1997/11/03 23:34:20  jo
   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:34:11  joanna
   Initial revision

*/

/*
FIXME
remember to make sure that the LAPs are sorted by reward, that's
a necessary invariant that brain-objs (Comp) assumes.
*/

#include <stdio.h>
#include <fstream.h>
#include <stream.h>
#include <math.h>
#include <GetOpt.h>
#include <time.h>
#include <unistd.h>
#include "em.hh"
#include "brain-objs.hh"
#include "brain-read.hh"

static char rcsid[] ="$Id: brain-read.cc,v 1.1 1997/11/03 23:34:20 jo Exp $";

#define LINESIZE 2056


void read_brains(char * filename, char * pathname = 0) {
  char line [LINESIZE], name[NAMESIZE], stuff [LINESIZE], pattern[512];

  sprintf(line, "%s/%s", pathname, filename);
  cerr << "Opening " << line << " ...";
  ifstream lapfile(line);
  if (!lapfile) {
    sprintf(line, "%s.lap", line);
    lapfile.open(line);
  }
  if (!lapfile) {
    cerr << "Cannot open script file " << filename << "!\n";
    ::exit (-3);
  }
  while (lapfile.getline(line, LINESIZE)) {
    if (sscanf(line, "%*[#;]%[^\n]", stuff) || // starts with a comment
	line[0] == 0)                          // or just blank
      continue;

    // want -- sscanf(line, "(%NAMESIZEs %LINESIZE[^])\n", name, stuff);
    sprintf(pattern, "(%%%ds %%%d[^\n]", NAMESIZE, LINESIZE); 
    if (sscanf(line, pattern, name, stuff) != 2) {
      cerr << "Can't find name and rest of list in line " << line << " !\n";
      ::exit(-3);
    }
    cerr << "\n  Reading " << name << ".";
    read_lap (name, stuff);
  } // while lines in file
  cerr << "\nDone reading.\n";
  lapfile.close();

  // Connect all the bits together, make sure everything called is real!
  // If reading more than one file, should do this last.
  Comp cop;
  cop.check_comp();

} // read_brains


void read_lap(char * name, char * stuff) {
  char trigst[LINESIZE], lapst[LINESIZE], complapst[LINESIZE];
  int place = 0; int resnum; Braintype bt = LAP;

  // First -- parse everything into strings
  getlist (trigst, stuff, place);
  cerr << "  Trigger is " << trigst;
  getlist (lapst, stuff, place);
  cerr << "\n     Lap is " << lapst;
  if ((resnum = sscanf(&(stuff[place]), " DRIVE (%s", complapst))) {
    bt = DRIVE;
    // the above complapst is discarded; it's just to force the count
    getlist (complapst, stuff, place); // should check only a ) left!
    // create lap w/o trigger, drive with
    cerr << "\n     Drive! " << complapst ;
  } // if drive
  else if ((resnum = sscanf(&(stuff[place]), " (%s", complapst))) {
    bt = COMP;
    // the above complapst is discarded; it's just to force the count
    getlist (complapst, stuff, place); // should check only a ) left!
    // create lap w/o trigger, comp with 
    cerr << "\n     Comp! " << complapst ;
  } // else if comp

  // Now -- make our chunks!
  static Brain * empty[1] = {0};
  Brain ** lapar = make_primarray(trigst);
  Trig * trig = new Trig(lapar);
  lapar = make_primarray(lapst);
  switch (bt) {
  case LAP:
    Lap::add_lap (name, lapar, trig);
    break;
  case COMP:
    Comp::add_comp (name, complapst, trig);
    // the "goal" lap is only a trigger
    Lap::add_lap (name, empty, new Trig(lapar)); 
    break;
  case DRIVE:
    Drive::add_drive (name, complapst, trig);
    // the "goal" lap is only a trigger
    Lap::add_lap (name, empty, new Trig(lapar)); 
    break;
  default: // quiet some noise in the compile -- TRIG, ACT, SENSE and BRAIN 
    break;
  } // switch bt, as set above
} // read_lap

/* this changes both list (its result) and place (advancing the counter)
   both should already have memory allocated!
*/

void getlist (char *list, char *stuff, int &place) {
  while (stuff[place] != '(' && stuff[place]) place++;
  if (!stuff[place]) {
    cerr << "List never started!  Looking at " << stuff << " starting from "
      << place << "\n";
    ::exit(-3);
  };
  place++; int brack = 0, lpl;
  for (lpl = 0; stuff[place] && brack != -1; lpl++, place++) {
    list[lpl] = stuff[place];
    if (stuff[place] == '(') brack++;
    if (stuff[place] == ')') brack--;
  }
  if (brack != -1) {
    cerr << "List never ended!  Looking at " << stuff << " got to "
      << place << "\n";
    ::exit(-3);
  };
  list[--lpl] = 0;  // overwrite last ')'
} // getlist
  
/* creates and allocates an array of primitives */
Brain ** make_primarray(char * stuff) {
  int placeinc, resnum;
  char namest[NAMESIZE], valst[NAMESIZE];

  // first, count the number of elements
  int piec, place;
  for (piec = 0, place = 0; stuff[place] != 0; piec++) {
    resnum = 
      sscanf (&(stuff[place]), " (%s %[^)])%n", namest, valst, &placeinc);
    if (!resnum)
      resnum = sscanf (&(stuff[place]), " %s%n", namest, &placeinc);
    if (!resnum)
      break;  // hopefully out of the "for" loop
    place += placeinc;
  } // for piec
  Brain ** barb = new Brain * [piec+1];
  // now, build the array
  for (piec = 0, place = 0; stuff[place] != 0; piec++) {
    resnum = 
      sscanf (&(stuff[place]), " (%s %[^)])%n", namest, valst, &placeinc);
    if (resnum)  // found sense
      barb[piec] = new Sense(namest, valst);
    else { // (! resnum) not a sense
      resnum = sscanf (&(stuff[place]), " %s%n", namest, &placeinc);
      if (resnum)  
	barb[piec] = new Act(namest);
      else // found nothing!
	break;  // hopefully out of the "for" loop
    } // else not a sense
    place += placeinc;
  } // for piec
  barb[piec] = 0;
  return (barb);
} // make_primarray

