/* setup.C
 *
 * Code to read a network configuration file and build the network.
 *
 * There are lots of tedious details in this file.  You don't need to
 * understand the setupNetwork() function for this assignment.
 *
 * This has been modified to avoid using <strstream.h>.
 */


#include <stdio.h>
#include <iostream.h>
#include <fstream.h>
#include "io.h"
#include "station.h"
#include "section.h"
#include "platform.h"
#include "train.h"
#include "xy.h"
#include "defs.h"

Section *lookupSection( char *name );
Platform *lookupPlatform( char *name );
Station *lookupStation( char *name );
void setPlatformSections();


/* Copy from inputString to buffer until a space is reached.  Advance
 * the inputString pointer beyond that space.
 */


void CopyUntilSpace( char * &inputString, char *buffer )

{
  while (*inputString == ' ' && *inputString != '\0')
    inputString++;

  while (*inputString != ' ' && *inputString != '\0')
    *(buffer++) = *(inputString++);

  *buffer = '\0';		// end of word
}


/* Set up the network by reading the configuration from a file. See the
 * sample file, "network1" for a description of the format.
 */

void setupNetwork( char *configFileName )

{
  char *str;
  FILE *f;
  char buff[100];

  f = fopen( configFileName, "r" );

  if (f == NULL) {
    cerr << "Error: Couldn't open network configuration file, " << configFileName << ".\n";
    abort();
  }

  while (true) {

    str = collectText(f);	// get next statement from config file
    if (str == NULL)
      break;			// stop at end of file

    {
      char buff[100], temp[100];
      xyCoord xy;
      char *s = str;		// s keeps track of current position in input string

      CopyUntilSpace( s, buff ); // read first word of statement
      if (*s == '\0') break;

      // Act upon different types of statement

      // ---------------- STATION ----------------

      if (strcmp(buff,"station") == 0) {

	Station *station;

	CopyUntilSpace( s, buff ); // station name
	station = new Station( buff );
	allStations.add( station );

	while (true) {		// read platforms
	  Platform *platform;
	  CopyUntilSpace( s, buff ); // platform name
	  if (*s == '\0') break;
	  platform = new Platform( buff );
	  platform->station = station;
	  allPlatforms.add( platform );
	}
	
      // ---------------- MAIN ----------------

      } else if (strcmp(buff,"main") == 0) {
	
	xyCoord prevXY, nextXY;
	Platform *platform;
	Section *section, *prevSection;

	CopyUntilSpace( s, temp ); // read first coords
	sscanf( temp, "(%f,%f)", &prevXY.x, &prevXY.y );

	prevSection = NULL;

	while (true) {
	  CopyUntilSpace( s, buff ); // read section name
	  if (*s == '\0') break;
	  CopyUntilSpace( s, temp ); // read next coords
	  sscanf( temp, "(%f,%f)", &nextXY.x, &nextXY.y );
	  platform = lookupPlatform( buff ); // find corresponding platform
	  if (strcmp(buff,"x") == 0)
	    section = new Section( NULL, MAIN, platform, prevXY.x, prevXY.y, nextXY.x, nextXY.y );
	  else
	    section = new Section( buff, MAIN, platform, prevXY.x, prevXY.y, nextXY.x, nextXY.y );
	  allSections.add( section );
	  // update prev (0) and next (1) sections
	  section->adjMain[0] = prevSection;
	  if (prevSection != NULL)
	    prevSection->adjMain[1] = section;
	  prevXY = nextXY;
	  prevSection = section;
	}
	prevSection->adjMain[1] = NULL;

      // ---------------- SWITCH ----------------

      } else if (strcmp(buff,"switch") == 0) {

	char switchName[100], sect0[100], end0[100], sect1[100], end1[100];
	Section *section0, *section1, *switchSection;
	int dir0, dir1;
	
	CopyUntilSpace( s, switchName ); // read the switch info
	CopyUntilSpace( s, sect0 );
	CopyUntilSpace( s, end0 );
	CopyUntilSpace( s, sect1 );
	CopyUntilSpace( s, end1 );

	// Convert text to sections and directions

	section0 = lookupSection( sect0 );
	if (section0 == NULL) {
	  cerr << "Error: Above line " << lineNum << ", section " << sect0 << " is unknown.\n";
	  abort();
	}

	if (strcmp(end0,"front") == 0)
	  dir0 = 1;
	else if (strcmp(end0,"rear") == 0)
	  dir0 = 0;
	else {
	  cerr << "Error: Above line " << lineNum << ", expected `front' or `rear' but got " << end0 << ".\n";
	  abort();
	}

	section1 = lookupSection( sect1 );
	if (section1 == NULL) {
	  cerr << "Error: Above line " << lineNum << ", section " << sect1 << " is unknown.\n";
	  abort();
	}

	if (strcmp(end1,"front") == 0)
	  dir1 = 1;
	else if (strcmp(end1,"rear") == 0)
	  dir1 = 0;
	else {
	  cerr << "Error: Above line " << lineNum << ", expected `front' or `rear' but got " << end1 << ".\n";
	  abort();
	}

	// Update the data

	switchSection = new Section( switchName, SWITCH, NULL,
				     dir0 == 0 ? section0->x0 : section0->x1,
				     dir0 == 0 ? section0->y0 : section0->y1,
				     dir1 == 0 ? section1->x0 : section1->x1,
				     dir1 == 0 ? section1->y0 : section1->y1 );

	switchSection->setStatus( RED );

	if (section0->adjBranch[dir0] != NULL) {
	  cerr << "Error: More than one branch attached to one end of section " << *section0 << ".\n";
	  abort();
	}
	section0->adjBranch[dir0] = switchSection;
	switchSection->adjMain[0] = section0;

	if (section1->adjBranch[dir1] != NULL) {
	  cerr << "Error: More than one branch attached to one end of section " << *section1 << ".\n";
	  abort();
	}
	section1->adjBranch[dir1] = switchSection;
	switchSection->adjMain[1] = section1;

	allSections.add( switchSection );

      // ---------------- PLATFORMS ----------------

      } else if (strcmp(buff,"platforms") == 0) {

	for (int src=0; src<allStations.size(); src++)
	  for (int dst=0; dst<allStations.size(); dst++) {

	    char buff[100];
	    Platform *platform;

	    CopyUntilSpace( s, buff );
	    if (strcmp(buff,".") == 0)
	      platform = NULL;
	    else {
	      platform = lookupPlatform( buff );
	      if (platform == NULL) {
		cerr << "Error: Above line " << lineNum << ", platform "
		     << buff << " is not recognized.\n";
		abort();
	      }
	    }

	    allStations[src]->destPlatforms.add( platform );
	  }

      // ---------------- ARRIVALS ----------------

      } else if (strcmp(buff,"arrivals") == 0) {

	for (int src=0; src<allStations.size(); src++)
	  for (int dst=0; dst<allStations.size(); dst++) {
	    float mean;
	    CopyUntilSpace( s, temp );
	    sscanf( temp, "%f", &mean );
	    allStations[src]->means.add( mean*60 ); // convert minutes to seconds
	  }

      // ---------------- TRANSFERS ----------------

      } else if (strcmp(buff,"transfers") == 0) {

	for (int src=0; src<allStations.size(); src++)
	  for (int dst=0; dst<allStations.size(); dst++) {

	    char buff[100];
	    Station *nextStation;

	    CopyUntilSpace( s, buff );
	    if (strcmp(buff,".") == 0)
	      nextStation = allStations[dst];
	    else {
	      nextStation = lookupStation( buff );
	      if (nextStation == NULL) {
		cerr << "Error: Above line " << lineNum << ", station "
		     << buff << " is not recognized.\n";
		abort();
	      }
	    }

	    allStations[src]->nextStation.add( nextStation );
	  }

      // ---------------- TRAIN ----------------

      } else if (strcmp(buff,"train") == 0) {

	char buff[100];
	Platform *platform;
	Train *train;
	PathElement pe;

	setPlatformSections();

	CopyUntilSpace( s, buff );
	platform = lookupPlatform(buff);
	if (platform == NULL) {
	  cerr << "Error: Above line " << lineNum << ", platform " << buff << " is unrecognized.\n";
	  abort();
	}

	train = new Train( platform->section );

	while (true) {

	  Station *nextStation;
	  Section *nextSection;

	  CopyUntilSpace( s, buff ); // read path element name
	  if (*s == '\0') break;

	  if (strcmp(buff,"reverse") == 0) {
	    
	    pe = PathElement(); // reversing element

	  } else {
	    
	    nextStation = lookupStation( buff );
	    if (nextStation != NULL)
	      pe = PathElement( nextStation ); // station element

	    else {

	      nextSection = lookupSection( buff );
	      if (nextSection != NULL)
		pe = PathElement( nextSection ); // switch element

	      else {

		cerr << "Error: Above line " << lineNum << ", path element '"
		     << buff << "' is unrecognized.\n";
		abort();
	      }
	    }
	  }
	  
	  train->path.add( pe );
	}

	allTrains.add( train );
	
      } else {

	cerr << "Error: unrecognized statment ABOVE line " << lineNum << " of "
	     << configFileName << ": " << buff << "\n";
	abort();
      }
    }
  }

  setPlatformSections();

  // output everything

#if 0
  cout << "Stations:\n";
  for (int i=0; i<allStations.size(); i++) {

    Station *s = allStations[i];
    cout << "  " << *s << endl;

    // Destination information

    for (int j=0; j<allStations.size(); j++)
      if (j != i) {
	cout << "    to " << allStations[j]->name << ": "
	     << *s->destPlatforms[j] << ", "
	     << s->means[j] << ", "
	     << *s->nextStation[j] << endl;
      }
  }

  cout << "Platforms:\n";
  for (int i=0; i<allPlatforms.size(); i++) {
    Platform *p = allPlatforms[i];
    cout << "  " << *p << " in " << *p->station << " on section " << *p->section << endl;
  }

  cout << "Sections:\n";
  for (int i=0; i<allSections.size(); i++) {
    Section *s = allSections[i];
    cout << "  ";
    if (s->type() == SWITCH)
      cout << "switch ";
    cout << *s << " positioned at (" << s->x0 << "," << s->y0 << ")(" << s->x1 << "," << s->y1 << ")"
	 << ", prev " << *s->adjMain[0] << ", next " << *s->adjMain[1]
	 << ", status " << s->status() << endl;
  }

  cout << "Trains:\n";
  for (int i=0; i<allTrains.size(); i++) {
    Train *t = allTrains[i];
    cout << "  " << *t << " on section " << *t->sections[0] << ":";
    for (int j=0; j<t->path.size(); j++)
      cout << " " << t->path[j];
    cout << endl;
  }

#endif
}


/* Find the platform of this name
 */

Platform *lookupPlatform( char *name )

{
  for (int i=0; i<allPlatforms.size(); i++)
    if (strcmp(name,allPlatforms[i]->platformName) == 0)
      return allPlatforms[i];
  return NULL;
}


/* Find the station of this name
 */

Station *lookupStation( char *name )

{
  for (int i=0; i<allStations.size(); i++)
    if (strcmp(name,allStations[i]->name) == 0)
      return allStations[i];
  return NULL;
}


/* Find the section of this name
 */

Section *lookupSection( char *name )

{
  for (int i=0; i<allSections.size(); i++) {
    Section *s = allSections[i];
    if (s->sectionName != NULL  && strcmp(name,s->sectionName) == 0)
      return s;
  }
  return NULL;
}


// Set the platform track sections

void setPlatformSections()

{
  static bool done = false;

  if (done)
    return;

  for (int i=0; i<allPlatforms.size(); i++) {
    Platform *p = allPlatforms[i];
    p->section = lookupSection( p->platformName );
    if (p->section == NULL) {
      cerr << "Error: Platform " << *p << " has no corresponding track section of the same name\n";
      abort();
    }
  }
  
  done = true;
} 
