/* section.h
 *
 * The section class, which represents one section of track.  A train
 * moves from section to section, sometimes lying completely within
 * one section and sometimes overlapping two adjacent sections.  The
 * section is responsible for reporting to the controller when a train
 * enters it or leaves it.  The section also has a status, RED,
 * YELLOW, or GREEN, which determines the speed at which trains may
 * traverse it (RED: no trains allowed, YELLOW: slow trains, GREEN:
 * any speed).
 *
 * A section is connected at each end to other sections.  Usually, it
 * is only connected to one other section on each end.  However, there
 * may be a switch (a branch in the track) at one end, in which case
 * that end has two adjacent sections.  In this figure, each section
 * lies between two Os.
 *
 *    --O--------O------------O--
 *                \
 *                 \
 *                  \
 *    --O------------O--------O--
 * 
 * A section is directed, with one end labelled 0 and the other
 * labelled 1.  A section may also have an platform beside it (when
 * the section is inside a station).
 */


#ifndef SECTION_H
#define SECTION_H

#include <math.h>
#include <string.h>
#include <iostream.h>
#include "defs.h"
#include "controller.h"
#include "main.h"

class Platform;
class Train;


class Section {

  friend class Controller;	// The Controller may modify that section status
  friend void setupNetwork(char *c); // setupNetwork() can initialize

  SectionType   typ;		// type: MAIN, SWITCH, SIDING
  SectionStatus stat;		// status, set by controller: RED, YELLOW, GREEN
  float len;			// length of section, in metres
  Platform * adjPlatform;	// platform beside this section (could be NULL)
  bool trainPresent;		// true iff train occupies section

  int ident;			// unique identifier

  static int nextIdent;		// counter to generate identifiers

  // Any of the following adjacent sections could be NULL.

  Section * adjMain[2];		// adjacent sections on main line: [0] = rear, [1] = front
  Section * adjBranch[2];	// adjacent sections on branch: [0] = rear, [1] = front

public:

  char *sectionName;		// name (sometimes NULL)
  float x0,y0,x1,y1;		// ends of section.
  bool reversed;		// (x0,y0) and (x1,y1) are reversed (used for drawing only)
  bool frozenStatus;		// True -> can't change status (during an accident)

  // Constructor
 
  Section( char *name, SectionType t, Platform *p, float xx0, float yy0, float xx1, float yy1 ) {
    typ = t;
    stat = GREEN;
    adjPlatform = p;
    x0 = xx0; y0 = yy0;
    x1 = xx1; y1 = yy1;
    reversed = false;
    len = sqrt( (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1) );
    trainPresent = false;
    if (name != NULL)
      name = strdup(name);
    sectionName = name;
    ident = nextIdent++;
    adjBranch[0] = NULL;
    adjBranch[1] = NULL;
    frozenStatus = false;
  }    

  // Upon entering a section, (x0,y0) and (x1,y1) are swapped if
  // necessary so that the train is travelling FROM (x0,y0) TO
  // (x1,y1).  Also, adjMain[0] and adjBranch[0] are made the main and
  // branch section FROM WHICH THE TRAIN CAME and adjMain[1] and
  // adjBranch[1] are made those TOWARD WHICH THE TRAIN IS TRAVELLING.

  void orientSection( Section *fromSection ) {
    if (fromSection == adjMain[1] || fromSection == adjBranch[1]) // coming from wrong end
      reverseSection();
  }

  void orientSectionReversed( Section *toSection ) {
    if (toSection == adjMain[0] || toSection == adjBranch[0]) // going to wrong end
      reverseSection();
  }

  // When a train enters or leaves the section, it tells the section
  // of this by calling one of the following functions which, in turn,
  // tells the controller.  The *this argument is THIS section.

  void trainIsEnteringSection( Train *t, Section *fromSection ) {
    orientSection( fromSection );
    trainPresent = true;
    controller.trainIsEnteringSection( t, this );
  }

  void trainIsLeavingSection( Train *t ) {
    trainPresent = false;
    controller.trainIsLeavingSection( t, this );
  }

  // Reverse coordinates and adjMain and adjBranch

  void reverseSection();
  void reverseOccupiedSection();

  // Some access functions that allow variables to be read, but not
  // modified, by external code.

  void setStatus( SectionStatus newStat ) { if (!frozenStatus) stat = newStat; }
  void setOccupied( bool flag )           { trainPresent = flag; }

  SectionStatus status()              { return stat; }
  SectionType type()                  { return typ; }
  float length()                      { return len; }
  Section * nextMainSection()         { return adjMain[1]; }
  Section * prevMainSection()         { return adjMain[0]; }
  Section * nextBranchSection()       { return adjBranch[1]; }
  Section * prevBranchSection()       { return adjBranch[0]; }
  Platform * platform()               { return adjPlatform; }
  bool occupied()                     { return trainPresent; }

  // Output operators

  void draw();

  friend ostream& operator << ( ostream& stream, Section const &s ) {
    if (&s == NULL)
      stream << "(null)";
    else {
      stream << "S" << s.ident;
      if (s.sectionName != NULL)
	stream << " (" << s.sectionName << ")";
    }
    return stream;
  }
};

#endif
