// $Source: /usr/local/SimSoft/Sfx3D/src/gsl/modell.cpp,v $
// $Revision: 1.2 $
// $Author: baum $
// $Date: 2001/11/29 15:18:09 $
//
// Login name of the user who locked the revision
// $Locker:  $
// Tag name used to checkout the file
// $Name:  $
// State assigned to revision
// $State: Exp $
//
//
// $Log: modell.cpp,v $
// Revision 1.2  2001/11/29 15:18:09  baum
// -Realzeitsteuerung eingebaut
// -Handsteuerung eingebaut
//

#include <stdio.h>
#include <stdarg.h>

#include "XGraph/XGraph.h"

#define _MODELL_CPP
#include "modell.h"

#include "Kalender.h"
#include "Messung.h"
#include "geometry.h"

#include "Vec3D.h"
#include "Angle.h"

#include "Array.h"
#include "IniFile.h"
#include "StrmSet.h"
#include "Messager.h"
#include "FileSys.h"

#include "sfx.h"
#include "baustein.h"
#include "layout.h"
#include "quelle.h"
#include "senke.h"
#include "staufoer.h"
#include "kettfoer.h"
#include "weiche.h"
#include "vwagen.h"
#include "maschine.h"
#include "drehpuff.h"
#include "mehrfachlader.h"
#include "laufkran.h"
#include "regal.h"
#include "absregal.h"
#include "regalver.h"
#include "poolver.h"
#include "komm.h"
#include "kommver.h"

#include "arbplan.h"
#include "route.h"
#include "ereignis.h"
#include "prozess.h"
#include "programm.h"
#include "fts.h"
#include "ftsladep.h"

// LCE
/*
typedef void* (*newObject) ();
HINSTANCE lceLibrary;
*/
//LCE

Array<typBaustein> baustein (20);

SFXModel *MySFXModel;
bool Sfx3D_on = false;
Ustring ExpName;
Ustring ExtName;
//==================================================================
//		Implementation
//		for class SFXModel
//==================================================================

// constructor
// model-string is path with modelname!!!!
/**< ObjOutputPath ergaenzt, um Ausgaben in verschiedenen Verzeichnisse umlenken zu koennen. Rudi: 02.08.2002.*/

SFXModel::SFXModel (const Ustring& model, bool plantControl , bool realTime, bool hla)
  : ObjModelPath     (model), ObjOutputPath     (model),
  	 ObjModelName   (model), ObjModelExtension   (NULL),
    ObjModelSpace    (),      ObjTGB         (NULL),
    ObjPermanents    (10),    ObjTemporaries (10),
    ObjWorkSchedules (5),     ObjRoutes      (20),
    ObjProcesses     (5),
    ObjRunning       (false),
    ObjCycle         (false), ObjCycleFreez  (false),
    ObjTrace         (false), ObjDebug       (false),
    ObjInitDebug     (false), ObjPrgDebug    (false),
    ObjPlantControl  (plantControl),
    ObjRealTime      (realTime),
    ObjHla           (hla) {

  int   pos = ObjModelPath.len () - 1;
  char *str = ObjModelPath.str ();

  while ((str[pos] != '\\') && (str[pos] != '/') && (pos >= 0))
    pos--;

  pos++;
  ObjModelPath.delPart (pos, (ObjModelPath.len () - (pos)));
  ObjOutputPath.delPart (pos, (ObjOutputPath.len () - (pos)));

  ObjModelName.delPart (0, pos);
  pos = 0;
  str = ObjModelName.str ();

  while ((str[pos] != '.') && (str[pos] != '\0')) pos++;
  if (str[pos] == '.')
    ObjModelName.delPart (pos - 1, (ObjModelName.len () - (pos + 1)));

  init ();

}


/**
 * constructor
 *
 * @param model Modellname
 * @param extension Modellendung
 * @param plantControl Modelltechnik ein- oder ausgeschaltet
 * @param realTime Realzeitsteuerung
 *
 */
/**< ObjOutputPath ergaenzt, um Ausgaben in verschiedenen Verzeichnisse umlenken zu koennen. Rudi: 02.08.2002.*/
SFXModel::SFXModel (const Ustring& model, const Ustring& extension, bool plantControl /*= false*/, 
    bool realTime /*= false*/, bool hla)
  : ObjModelPath     (model), ObjOutputPath     (model),
    ObjModelName   (model), ObjModelExtension   (extension),
    ObjModelSpace    (),      ObjTGB         (NULL),
    ObjPermanents    (10),    ObjTemporaries (10),
    ObjWorkSchedules (5),     ObjRoutes      (20),
    ObjProcesses     (5),
    ObjRunning       (false),
    ObjCycle         (false), ObjCycleFreez  (false),
    ObjTrace         (false), ObjDebug       (false),
    ObjInitDebug     (false), ObjPrgDebug    (false),
    ObjPlantControl  (plantControl),
    ObjRealTime      (realTime),
    ObjHla           (hla) {


  int   pos = ObjModelPath.len () - 1;
  char *str = ObjModelPath.str ();

  while ((str[pos] != '\\') && (str[pos] != '/') && (pos >= 0))
    pos--;

  pos++;
  ObjModelPath.delPart (pos, (ObjModelPath.len () - (pos)));
  ObjOutputPath.delPart (pos, (ObjOutputPath.len () - (pos)));

  ObjModelName.delPart (0, pos);
  pos = 0;
  str = ObjModelName.str ();

  while ((str[pos] != '.') && (str[pos] != '\0')) pos++;
  if (str[pos] == '.')
    ObjModelName.delPart (pos - 1, (ObjModelName.len () - (pos + 1)));

  init ();

}

// destructor
SFXModel::~SFXModel () {
  SimTime now (SimTime::convertSysClock ());
  cout << "ZEIT=";
  Modellzeit ().print (cout, SimTime::OutputFormat ());
  cout << " Simulation von \"" << ObjModelName.str () << "\" beendet:";
  cout.width (2);
  cout << now.Hours () << ":";
  cout.width (2);
  cout << now.Minutes () << ":";
  cout.width (2);
  cout << now.Seconds () << endl;

  PrgModul->callPrgFunc ("exit_prog");

  // Temporaries will remove in the destructors
  while (ObjTemporaries.Last ())   delete ObjTemporaries.Last ();
  while (ObjWorkSchedules.Last ()) delete ObjWorkSchedules.removeLast ();
  int lastRoute = ObjRoutes.Last ();
  for (int i = 0; i <= lastRoute; ) {
    DynArray <typTransportRoute>* r = ObjRoutes[i++];
    if (r) {
      while (r->Last ()) delete r->removeLast ();
      delete r;
    }
  }
  while (ObjProcesses.Last ())     delete ObjProcesses.removeLast ();

  // Permaments will remove in the destructors
  while (ObjPermanents.Last ())    delete ObjPermanents.Last ();

  baustein.removeAll ();

	if (ObjTGB)
  		delete ObjTGB;
  Pattern::clean ();
  IniFile::cleanup ();

/*	if (zLCE_Kern != NULL) {
		zLCE_Kern->end();
   }
   */
}

void SFXModel::load () {
  if (ObjPermanents.isEmpty ()) {
    ObjTGB = new TGBLib ();
    Msg.Status ("Lese TGS");
    readTGS ();
    Msg.Status ("Lese TTP");
    readTTP ();
    Msg.Status ("Lese TST");
    readTST ();
    Msg.Status ("Lese TBV");
    readTBV ();
    Msg.Status ("Lese TAS");
    readTAS ();
    Msg.Status ("Lese TFK");
    readTFK ();
    Msg.Status ("Lese TLM");
    readTLM ();
    Msg.Status ("Lese TPV");
    readTPV ();
    Msg.Status ("Lese TZT");
    readTZT ();
    Msg.Status ("Lese TMW");
    readTMW ();
    PrgModul->callPrgFunc ("init_prog");

    // LCE_Kern initialisieren
    /*
    newObject lceObj;
    lceLibrary = LoadLibrary("LCE.dll");
    Ustring dir = FileSystem::CurrentDir();
    if (lceLibrary != NULL) {
      lceObj = (newObject) (GetProcAddress(lceLibrary, "@LCE_Kern@createLCE_Kern$qv"));
      if (lceObj != NULL) {
         zLCE_Kern = (LCE_InterfaceKern*) (lceObj());
         zLCE_Kern->init (ObjModelName, ObjModelPath, ObjWorkSchedules);         
      }
      for (ObjWorkSchedules.First (); ObjWorkSchedules (); ObjWorkSchedules++) {
         ObjWorkSchedules()->setDlzRegister (new Register ());
         ObjWorkSchedules()->setBestandGeschichte (new Geschichte ());      
      }
    } 
    */ 
    // LCE_Kern initialisieren

    SimTime now (SimTime::convertSysClock ());
    cout << "ZEIT=";
    Modellzeit ().print (cout, SimTime::OutputFormat ());
    cout << " Simulation von \"" << ObjModelName.str () << "\" beginnt:";
    cout.width (2);
    cout << now.Hours () << ":";
    cout.width (2);
    cout << now.Minutes () << ":";
    cout.width (2);
    cout << now.Seconds () << endl;
  }
}

bool SFXModel::run  () {
  return (ObjRunning = true);
}

bool SFXModel::stop () {
  return (ObjRunning = false);
}

bool SFXModel::isRunning () const {
  return ObjRunning;
}

const Ustring& SFXModel::ModelName () const {
  return ObjModelName;
}

const Ustring& SFXModel::ModelExtension () const {
  return ObjModelExtension;
}

const Ustring& SFXModel::ModelPath () const {
  return ObjModelPath;
}

/**< Ergaenzt, um Ausgaben in verschiedenen Verzeichnisse umlenken zu koennen. Rudi: 02.08.2002.*/
Ustring& SFXModel::OutputPath () {
  return ObjOutputPath;
}

void SFXModel::setOutputPath (Ustring path) {
  ObjOutputPath = path;
}

TGBLib *SFXModel::TGBLibrary () const {
  return ObjTGB;
}


/*
XMLHandler *SFXModel::ModelXMLHandler () const {
  return ObjXMLHandler;
}
*/

Space *SFXModel::ModelSpace () const {
  return (Space *)&ObjModelSpace;
}

bool SFXModel::Cycle () const {
  return (ObjCycleFreez ? false : ObjCycle);
}

bool SFXModel::setCycle (bool cycle) {
  return (ObjCycle = cycle);
}

bool SFXModel::freezCycle () {
  ObjCycleFreez = true;
  return ObjCycle;
}

bool SFXModel::restoreCycle () {
  ObjCycleFreez = false;
  return ObjCycle;
}

bool SFXModel::RealTime () const {
  return ObjRealTime;
}

bool SFXModel::Hla () const {
  return ObjHla;
}

bool SFXModel::Trace () const {
  return ObjTrace;
}

bool SFXModel::setTrace (bool trace) {
  return (ObjTrace = trace);
}

bool SFXModel::Speech    () const {
  return ObjSpeech;
}

bool SFXModel::setSpeech (bool speech) {
  return (ObjSpeech = speech);
}

bool SFXModel::Debug () const {
  return ObjDebug;
}

bool SFXModel::setDebug (bool debug) {
  return (ObjDebug = debug);
}

bool SFXModel::InitDebug () const {
  return ObjInitDebug;
}

bool SFXModel::setInitDebug (bool debug) {
  return (ObjInitDebug = debug);
}

bool SFXModel::PrgDebug  () const {
  return ObjPrgDebug;
}

bool SFXModel::setPrgDebug  (bool debug) {
  return (ObjPrgDebug = debug);
}

bool SFXModel::PlantControl () const {
  return ObjPlantControl;
}

double SFXModel::Release () const{
  return ObjRelease;
}

void SFXModel::insertPermanent (const typBaustein& bst, const GeoObject& gObj) {
  ObjPermanents.insert (bst, gObj);
}

void SFXModel::removePermanent (const typBaustein& bst) {
  ObjPermanents.remove (bst);
}

typBaustein* SFXModel::findPermanent (unsigned nr) const {
  for (typBaustein* b = ObjPermanents.First (); b; b = ObjPermanents.Next ())
    if (b->Nummer () == nr) return b;
  return NULL;
}

const Map<typBaustein, GeoObject>& SFXModel::Permanents  () const {
  return ObjPermanents;
}

void SFXModel::insertTemporary (const typTransportEinheit& TE, const GeoObject& gObj) {
  ObjTemporaries.insert (TE, gObj);
}

void SFXModel::removeTemporary (const typTransportEinheit& TE) {
  GeoObject* go = ObjTemporaries.remove (TE);
  if (ObjModelSpace.MySelection ()->hasSelection (*go))
    ObjModelSpace.MySelection ()->remove (*go);
}

typTransportEinheit* SFXModel::findTemporary (unsigned id) const {
  for (typTransportEinheit* w = ObjTemporaries.First (); w; w = ObjTemporaries.Next ())
    if (w->ID () == id) return w;
  return NULL;
}

const Map<class typTransportEinheit, GeoObject>& SFXModel::Temporaries () const {
  return ObjTemporaries;
}

typTransportRoute *SFXModel::findRoute (typBaustein* startPerm, typBaustein* destPerm) const {
  DynArray <typTransportRoute>* r = ObjRoutes[startPerm->Nummer ()];
  if (r) {
    for (r->First (); (*r) (); (*r)++)
      if ((*r) ()->Stationen ().Last () == destPerm)
        return (*r) ();
  }
  Msg.Error ("SFXModel::findRoute (...)",
              "Modellzeit %f \nRoute von %i nach %i nicht gefunden!",
              Modellzeit().inMinutes(), startPerm->Nummer (), destPerm->Nummer ());
  return NULL;
}

typArbeitsplan *SFXModel::findWorkSchedule (unsigned nr) const {
  for (ObjWorkSchedules.First (); ObjWorkSchedules (); ObjWorkSchedules++)
    if ((ObjWorkSchedules ()->Nummer () == nr))
      return ObjWorkSchedules ();

  Msg.Error ("SFXModel::findWorkSchedule (...)", 
              "Modellzeit %f \nArbeitsplan Nummer %i nicht gefunden!",Modellzeit().inMinutes(), nr);
  return NULL;
}

typArbeitsplan *SFXModel::findWorkScheduleByArticle (unsigned nr, typBaustein* startBst) const {
  for (ObjWorkSchedules.First (); ObjWorkSchedules (); ObjWorkSchedules++)
    if ((ObjWorkSchedules ()->BestandsListe ().First ()->Artikel () == nr)
        && (ObjWorkSchedules ()->Vorgaenge ().First ()->ZielBaustein () == startBst))
      return ObjWorkSchedules ();

  Msg.Error ("SFXModel::findWorkScheduleByArticle (...)", 
             "Modellzeit %f \nArtikel Nummer %i nicht gefunden!",Modellzeit().inMinutes(), nr);
  return NULL;
}

typProzess* SFXModel::findProcess (unsigned nr, bool fatal) const {
  for (ObjProcesses.First (); ObjProcesses (); ObjProcesses++)
    if (ObjProcesses ()->Nummer () == nr)
      return ObjProcesses ();
  if (fatal) 
  Msg.Error ("SFXModel::findProcess (...)", 
             "Modellzeit %f \nProzess Nummer %i nicht gefunden!", Modellzeit().inMinutes(), nr);
  return NULL;
}

const DynArray<typArbeitsplan>& SFXModel::WorkSchedules () const {
  return ObjWorkSchedules;
}

const DynArray<typProzess>& SFXModel::Processes () const {
  return ObjProcesses;
}

void SFXModel::readTGS () {
	unsigned nr, typ;
  	typFtsVerwalter* FtsVerwalter;
  	if (!strcmp (ObjModelExtension.str(), ".xml")) {

	/*
   	unsigned anzahlMaschinen, anzahlQuellen, anzahlTransportbausteine;

   	ObjXMLHandler = new XMLHandler (Ustring (ObjModelPath + ObjModelName + ".xml").str ());

      anzahlMaschinen = ObjXMLHandler->CountElementsOfTag ("Maschine");

      for (unsigned m = 1; m <= anzahlMaschinen; m++) {
      	Ustring identValue = Ustring("M") + Ustring (m);
      	typ = atoi(ObjXMLHandler->GetChildElementValue(2, "Sfx-Bausteintyp", "Maschine", 2, "Inv-Nr", identValue.str()));
      	baustein [m] = new typMaschine (m, typ);

			baustein [m]->typTGSlesen (*file);
  			if (ObjInitDebug)
     			baustein [m]->typTGSschreiben (cout);
         
      }

		anzahlQuellen = ObjXMLHandler->CountElementsOfTag ("Quelle");

      for (unsigned m = 1; m <= anzahlQuellen; m++) {
      	baustein [anzahlMaschinen + m] = new typQuelle (anzahlMaschinen + m, 1);

			baustein [anzahlMaschinen + m]->typTGSlesen (*file);
  			if (ObjInitDebug)
     			baustein [anzahlMaschinen + m]->typTGSschreiben (cout);

      }
	*/
  	} else {

		InputFile *file = new InputFile (Ustring (ObjModelPath + ObjModelName + ".2gs").str ());
  		if (!file)
    		Msg.Error ("SFXModel::readTGS (...)", "Can't find file \"%s\"!!!",
               		Ustring(ObjModelPath + ObjModelName + ".2gs").str ());

      SFXToken tok;
  		tok.findSentence (3, *file);
  		file->jump (200); // EOL

  		while (tok.findNextSentence (*file)) {
    		tok.nextToken (*file);
    		nr = atoi (tok ());
    		tok.nextToken (*file);
    		typ = atoi (tok ());
    		switch (typ) {
         	case tLayout               : baustein [nr] = new typLayout (nr, typ);
            	                          break;
         	case tQuelle               : baustein [nr] = new typQuelle (nr, typ);
               	                       break;
         	case tSenke                : baustein [nr] = new typSenke (nr, typ);
   	                                   break;
	         case tStaufoerderer        : baustein [nr] = new typLinearStaufoerderer(nr, typ);
      	                                break;
         	case tRechtsKurvenStaufoerderer: baustein [nr] = new typRechtsKurvenStaufoerderer(nr, typ);
            	                          break;
         	case tLinksKurvenStaufoerderer: baustein [nr] = new typLinksKurvenStaufoerderer(nr, typ);
            	                          break;
         	case tWeiche               : baustein [nr] = new typWeiche (nr, typ);
            	                          break;
         	case tVerteilwagen         : baustein [nr] = new typVerteilwagen (nr, typ);
            	                          break;
         	case tMaschine             : baustein [nr] = new typMaschine (nr, typ);
            	                          break;
         	case tDrehpuffer           : baustein [nr] = new typDrehpuffer (nr, typ);
            	                          break;
//         case  tSammler             : baustein [nr] = new typSammler (nr, typ);
//                                      break;
				case tMehrfachLader        : baustein [nr] = new typMehrfachLader (nr, typ);
   	                                   break;
      	   case tLaufkran             : baustein [nr] = new typLaufkran (nr, typ);
         	                             break;
         	case tAbstrakteRegaleinheit: baustein [nr] = new typAbstrakteRegaleinheit (nr, typ);
            	                          break;
         	case tRegaleinheit         : baustein [nr] = new typRegaleinheit (nr, typ);
            	                          break;
         	case tRegalverwalter       : baustein [nr] = new typRegalverwalter (nr, typ);
            	                          break;
         	case tNcPoolverwalter      : baustein [nr] = new typNcPoolverwalter (nr, typ);
            	                          break;
         	case tKettenfoerderer      : baustein [nr] = new typKettenfoerderer (nr, typ);
            	                          break;
         	case tQuerfoerderer        : baustein [nr] = new typQuerfoerderer (nr, typ);
            	                          break;
         	case tKommissionierer      : baustein [nr] = new typKommissionierer (nr, typ);
            	                          break;
         	case tKomVerwalter         : baustein [nr] = new typKomVerwalter (nr, typ);
            	                          break;
         	case tFtsLadepool          : baustein [nr] = new typFtsLadePool (nr, typ);
            	                          break;
         	case tFtsLadeplatz         : baustein [nr] = new typFtsLadePlatz (nr, typ);
            	                          break;
         	case tFtsVerwalter         : baustein [nr] = new typFtsVerwalter (nr, typ);
																			FtsVerwalter = (typFtsVerwalter*)baustein [nr];
            	                          break;
         	case tFtsWagen             : baustein [nr] = new typFtsWagen (nr, typ);
            	                          break;
         	case tFtsEinbahnstrecke    : baustein [nr] = new typNetzEBStrecke (nr, typ);
            	                          break;
         	case tFtsZweibahnstrecke   : baustein [nr] = new typNetzZBStrecke (nr, typ);
            	                          break;
         	case tFtsKurve             : baustein [nr] = new typNetzKurve (nr, typ);
            	                          break;
         	case tFtsAbzweigung        : baustein [nr] = new typNetzAbzweigung (nr, typ);
            	                          break;
//         case tFtsKreuzung          : baustein [nr] = new typFtsKreuzung (nr, typ);
//                                      break;
//         case tFtsEinbahnMitInhalt  : baustein [nr] = new typFtsEinbahnMitInhalt (nr, typ);
//                                      break;
//         case tFtsZweibahnMitInhalt : baustein [nr] = new typFtsZweibahnMitInhalt (nr, typ);
//                                      break;
//         case tFtsEndstrecke        : baustein [nr] = new typFtsEndstrecke (nr, typ);
//                                      break;
         	default                    : Msg.Error ("SFXModel::readTGS ()", "Baustein %d: unbekannter Typ %d!", nr, typ);
            	                          break;
			}  // switch (typ)
			baustein [nr]->typTGSlesen (*file);
    		if (ObjInitDebug)
      		baustein [nr]->typTGSschreiben (cout);
  		}
		for (unsigned z = 1; z <= nr; z++) {
   		if (baustein[z] != NULL) {
      		if (((baustein [z]->Basistyp () >= tFtsEinbahnstrecke) &&
	  					(baustein [z]->Basistyp () <= tFtsEndstrecke))) {
        			FtsVerwalter->Netzbau((typNetzBaustein*) baustein [z]);
   	   	}
    		}
  		}
  		file->close();
  		delete file;
	}
}

void SFXModel::readTTP () {
  unsigned nr;

  InputFile *file = new InputFile (Ustring (ObjModelPath + ObjModelName + ".ttp").str ());
  if (!file)
    Msg.Error ("SFXModel::readTTP (...)", "Can't find file \"%s\"!!!",
               Ustring(ObjModelPath + ObjModelName + ".ttp").str ());
  SFXToken tok;
  tok.findSentence (2, *file);
  file->jump (200); // EOL

  while (tok.findNextSentence (*file)) {
    tok.nextToken (*file);
    nr = atoi (tok ());
    tok.nextToken (*file); // typ

    baustein [nr]->typTTPlesen (*file);
    if (ObjInitDebug)
      baustein [nr]->typTTPschreiben (cout);
  }
  file->close ();
  delete file;
}

void SFXModel::readTST () {
  unsigned nr;

  InputFile *file = new InputFile (Ustring (ObjModelPath + ObjModelName + ".tst").str ());
  if (!file)
    Msg.Error ("SFXModel::readTST (...)", "Can't find file \"%s\"!!!",
               Ustring(ObjModelPath + ObjModelName + ".tst").str ());
  SFXToken tok;
  tok.findSentence (2, *file);
  file->jump (200); // EOL

  while (tok.findNextSentence (*file)) {
    tok.nextToken (*file);
    nr = atoi (tok ());
    baustein [nr]->typTSTlesen(*file);
    if (ObjInitDebug)
      baustein [nr]->typTSTschreiben (cout);
  }
  file->close ();
  delete file;
}

void SFXModel::readTBV () {
  unsigned start;

  InputFile *file = new InputFile (Ustring (ObjModelPath + ObjModelName + ".tbv").str ());
  if (!file)
    Msg.Error ("SFXModel::readTBV (...)", "Can't find file \"%s\"!!!",
               Ustring(ObjModelPath + ObjModelName + ".tbv").str ());
  SFXToken tok;
  tok.findSentence (2, *file);
  file->jump (200); // EOL

  while (tok.findNextSentence (*file)) {
    tok.nextToken (*file);
    start = atoi (tok ());
    baustein [start]->typTBVlesen (*file);
    if (ObjInitDebug) {
      cout << "TBV: ";
      baustein [start]->typTBVschreiben (cout);
    }
  }
  file->close ();
  delete file;
}

void SFXModel::readTAS () {
  unsigned nr;
  typArbeitsplan *myArb;

  InputFile *file = new InputFile (Ustring (ObjModelPath + ObjModelName + ".tas").str ());
  if (!file)
    Msg.Error ("SFXModel::readTAS (...)", "Can't find file \"%s\"!!!",
               Ustring(ObjModelPath + ObjModelName + ".tas").str ());
  SFXToken tok;
  tok.findSentence (2, *file);
  file->jump (200); // EOL

  while (tok.findNextSentence (*file)) {
    tok.nextToken (*file);
    nr = atoi (tok ());
    myArb = new typArbeitsplan (nr);
    myArb->lesen (*file);
    ObjWorkSchedules.append (*myArb);
    if (ObjInitDebug) {
      cout << endl;
      myArb->schreiben (cout);
    }
  }
  file->close ();
  delete file;
}

void SFXModel::readTFK () {
  unsigned nr, firstBst;
  typTransportRoute *myFhk;

  InputFile *file = new InputFile (Ustring (ObjModelPath + ObjModelName + ".tfk").str ());
  if (!file)
    Msg.Error ("SFXModel::readTFK (...)", "Can't find file \"%s\"!!!",
               Ustring(ObjModelPath + ObjModelName + ".tfk").str ());
  SFXToken tok;
  tok.findSentence (2, *file);
  file->jump (200); // EOL

  while (tok.findNextSentence (*file)) {
    tok.nextToken (*file);
    nr = atoi (tok ());
    myFhk = new typTransportRoute (nr);
    myFhk->lesen(*file);
    firstBst = myFhk->Stationen ().First ()->Nummer ();
    if (!ObjRoutes[firstBst])
      ObjRoutes[firstBst] = new DynArray <typTransportRoute> (2);
    ObjRoutes[firstBst]->append (*myFhk);
    if (ObjInitDebug)
      myFhk->schreiben (cout);
  }
  file->close ();
  delete file;
}

void SFXModel::readTLM () {
  unsigned nr, typ;
  typProzess *proz;

  InputFile *file = new InputFile (Ustring (ObjModelPath + ObjModelName + ".tlm").str ());
  if (!file)
    Msg.Error ("SFXModel::readTLM (...)", "Can't find file \"%s\"!!!",
               Ustring(ObjModelPath + ObjModelName + ".tlm").str ());
  SFXToken tok;
  tok.findSentence (2, *file);
  file->jump (200); // EOL

  while (tok.findNextSentence (*file)) {
    tok.nextToken (*file);
    nr = atoi (tok ());
    tok.nextToken (*file);
    typ = atoi (tok ());
    switch (typ) {
      case typProzess::ANKUNFT  : proz = new typAnkunftsProzess (nr); break;
      case typProzess::STOERUNG : proz = new typStoerProzess    (nr); break;
      case typProzess::PRG      : proz = new typPRGProzess      (nr); break;
      default       : Msg.Error ("SFXModel::readTLM (...)", "Wrong Prozesstyp %d", typ); break;
    }
    proz->lesen (*file);
    ObjProcesses.append (*proz);
    if (ObjInitDebug) {
      cout << "TLM: ";
      proz->schreiben (cout);
    }
  }
  file->close ();
  delete file;
}

void SFXModel::readTPV () {
  unsigned nr;

  InputFile *file = new InputFile (Ustring (ObjModelPath + ObjModelName + ".tpv").str ());
  if (!file)
    Msg.Error ("SFXModel::readTPV (...)", "Can't find file \"%s\"!!!",
               Ustring(ObjModelPath + ObjModelName + ".tpv").str ());
  SFXToken tok;
  tok.findSentence (2, *file);
  file->jump (200); // EOL

  while (tok.findNextSentence (*file)) {
    tok.nextToken (*file);
    nr = atoi (tok ());
    tok.nextToken (*file); // typ
    baustein[nr]->typTPVlesen (*file);
    if (ObjInitDebug) {
      cout << "TPV: ";
      baustein [nr]->typTPVschreiben (cout);
    }
  }
  file->close ();
  delete file;
}

void SFXModel::readTZT () {
  unsigned code, info1, info2, info3;
  SimTime time;

  InputFile *file = new InputFile (Ustring (ObjModelPath + ObjModelName + ".tzt").str ());
  if (!file)
    Msg.Error ("SFXModel::readTZT (...)", "Can't find file \"%s\"!!!",
               Ustring(ObjModelPath + ObjModelName + ".tzt").str ());

  SFXToken tok;
  tok.findSentence (3, *file);
  tok.nextToken (*file);
  if (atoi (tok ()) != 3)
    Msg.Error ("SFXModel::readTZT (...)", "Wrong type at sentence 3");
  setModellende (readTime (*file));
  file->jump (200); // EOL

  while (tok.findNextSentence (*file)) {
    tok.nextToken (*file); // typ!!
    time = readTime (*file);
    tok.nextToken (*file);
    code = atoi (tok ());
    tok.nextToken (*file);
    info1 = atoi (tok ());
    tok.nextToken (*file);
    info2 = atoi (tok ());
    tok.nextToken (*file);
    info3 = atoi (tok ());

    if (code == ETprogramm) PrgModul->installProg (info2);
    if (ok_ereignis (code))
      notiz::planedelta (time, code, info1, info2, info3);
    else
      Msg.Error ("SFXModel::readTZT (...)", "Wrong Eventcode %d", code);
    file->jump (100); //EOL
  }
  file->close();
  delete file;
  if (ObjInitDebug) {
    cout << "TZT:" << endl;
    notiz::druckkalender (cout);
  }
}

void SFXModel::readTMW () {
  unsigned anzahl;
  unsigned code, betrifft, typ;
  int lastRoute;

  typTransportRoute*   fahrkurs;
  typArbeitsplan* arbplan;

  InputFile *file = new InputFile (Ustring (ObjModelPath + ObjModelName + ".tmw").str ());
  if (!file)
    Msg.Error ("SFXModel::readTMW (...)", "Can't find file \"%s\"!!!",
               Ustring(ObjModelPath + ObjModelName + ".tmw").str ());
  SFXToken tok;
  tok.findSentence (2, *file);
  file->jump (200); // EOL

  while (tok.findNextSentence (*file)) {
    tok.nextToken (*file);
    code = atoi (tok ());

    switch (code) {
      case 10: tok.nextToken (*file);
               betrifft = atoi (tok ());
               tok.nextToken (*file); // BausteinTyp
               tok.nextToken (*file); // Anzahl der Messungen
               anzahl = atoi (tok ());

               if (!baustein [betrifft]) {
                 Msg.Warning ("SFXModel::readTMW (...)", "Baustein %d existiert nicht!!!",
                              betrifft);
                 for (; anzahl; anzahl--) {
                   tok.nextToken (*file);
                   file->jump (200);
                 }
                 break;
               }

               for (; anzahl; anzahl--) {
                 tok.nextToken (*file); // Typ der Messung (Auslastung, Belegung)
                 typ = atoi (tok ());
                 tok.nextToken (*file); // Darstellungsart
                 tok.nextToken (*file); // Darstellungsbereich
                 switch (typ) {
                   case 1:  baustein [betrifft]->setAuslGeschichte (new Geschichte ());
                            break;
                   case 2:  baustein [betrifft]->setBelGeschichte (new Geschichte ());
                            break;
                   case 5:  baustein [betrifft]->setStoerGeschichte (new Geschichte ());
                            break;
                   default: break;
                 }
               }
               break;

      case 20: tok.nextToken (*file);
               fahrkurs = NULL;
               betrifft = atoi (tok ());
               lastRoute = ObjRoutes.Last ();
               for (int i = 0; i <= lastRoute; ) {
                 DynArray <typTransportRoute>* r = ObjRoutes[i++];
                 if (r) {
                   for (r->First (); (*r) (); (*r)++)
                     if ((*r) ()->Nummer () == betrifft) {
                       r->append (*fahrkurs);
                       break;
                     }
                 }
               }
               tok.nextToken (*file); // Anzahl der Messungen
               anzahl = atoi (tok ());
               if (!fahrkurs) {
                 Msg.Warning ("SFXModel::readTMW (...)", "Transportroute %d existiert nicht!!!",
                              betrifft);
                 for (; anzahl; anzahl--) {
                   tok.nextToken (*file);
                   file->jump (200);
                 }
                 break;
               }

               for (; anzahl; anzahl--) {
                 tok.nextToken (*file); // Typ der Messung (Auslastung, Belegung)
                 typ = atoi (tok ());
                 tok.nextToken (*file); // Darstellungsart
                 tok.nextToken (*file); // Darstellungsbereich
                 switch (typ) {
                   case 4:  fahrkurs->setDlzRegister (new Register ());
                            break;
                   default: break;
                 }
               }
               break;

      case 30: tok.nextToken (*file);
               arbplan = findWorkSchedule (atoi (tok ()));
               tok.nextToken (*file); // Anzahl der Messungen
               anzahl = atoi (tok ());
               if (!arbplan) {
                 Msg.Warning ("SFXModel::readTMW (...)", "Arbeitsplan %d existiert nicht!!!",
                              betrifft);
                 for (; anzahl; anzahl--) {
                   tok.nextToken (*file);
                   file->jump (200);
                 }
                 break;
               }

               for (; anzahl; anzahl--) {
                 tok.nextToken (*file); // Typ der Messung (Auslastung, Belegung)
                 typ = atoi (tok ());
                 tok.nextToken (*file); // Darstellungsart
                 tok.nextToken (*file); // Darstellungsbereich
                 switch (typ) {
                   case 4:  arbplan->setDlzRegister (new Register ());
                            break;
                   default: break;
                 }
               }
               break;

      case 40: file->jump (200); //EOL
               break;

      default: file->jump (200); //EOL
               break;
    }
  }
  file->close();
  delete file;
}

SimTime SFXModel::readTime (InputFile& file) const {
  SFXToken tok;
  int tag, std, min, sec, hsec;

  tok.nextToken (file);
  tag = atoi (tok());

  tok.nextToken (file);
  std = atoi (tok());

  tok.nextToken (file);
  min = atoi (tok());

  tok.nextToken (file);
  sec = atoi (tok());

  tok.nextToken (file);
  hsec = atoi (tok());

  return SimTime (tag * SimTime::SecondsPerDay ()
                  + std * SimTime::SecondsPerHour ()
                  + min * SimTime::SecondsPerMinute ()
                  + sec
                  + hsec * SimTime::FracsPerSecond ());
}

void SFXModel::init () {
  Ustring fileName (ObjModelPath + ObjModelName);
  fileName += Ustring (".ini");
  if (!FileSystem::FileExists (fileName.str ())) {
    Ustring sourceFileName (FileSystem::ExePath ());
    sourceFileName += "../template/Modell.ini";
    FileSystem::switchPathForOS (sourceFileName.str ());
    ifstream i (sourceFileName.str ());
    ofstream o (fileName.str ());
    o << i.rdbuf ();
    o.close ();
    i.close ();
  }
  IniFile::setup (fileName.str ());
   
  /**< Release einlesen und zuweisen, wenn nicht vorhanden auf 0 setzen */
  ObjRelease = IniFile::DefIniFile.readDouble ("ALLGEMEIN", "Release", 0);
  typBaustein::setClassNehmSchritt(IniFile::DefIniFile.readDouble ("ALLGEMEIN", "ClassNehmSchritt", 0.1));       
  typBaustein::setClassDrehSchritt(IniFile::DefIniFile.readDouble ("ALLGEMEIN", "ClassDrehSchritt", 15.0));
  typBaustein::setClassFahrSchritt(IniFile::DefIniFile.readDouble ("ALLGEMEIN", "ClassFahrSchritt", 0.1));

  ObjDebug     = IniFile::DefIniFile.readInt ("FFS", "Testprog", 0);
  ObjPrgDebug  = IniFile::DefIniFile.readInt ("FFS", "Prgtest",  0);
  ObjInitDebug = IniFile::DefIniFile.readInt ("FFS", "Initprog", 0);

  fileName  = Ustring (ObjModelPath) + Ustring ("logfile.out");
  FILE* tmp = fopen (fileName.str (), "w");
  if (tmp) {
    fclose (tmp);
    clogController.setToFile (fileName.str ());
  }
  else {
    fileName = getenv ("TEMP");
    fileName += FileSystem::PathSeparator ();
    fileName += "logfile.out";
    clogController.setToFile (fileName.str ());
  }
}

//==================================================================
//		output streaming
//==================================================================

void dprintf (char* format, ...) {
  static char str [1024];
  va_list args;
  va_start (args, format);
  vsprintf (str, format, args);
  va_end (args);
  cout << str << flush;
}

int  MessagerToCout (int, const char* txt) {
  cout << txt << flush;
  return 0;
}

//==================================================================
//		warning and error handling
//==================================================================

int sim_error (char *Modul, char *Methode, char *Text, int betr, bool fatal) {
  char buffer[255];
  Modellzeit().strftime(buffer, 255, SimTime::OutputFormat ());
  if (fatal)
    Msg.Error ((Ustring (Modul) += (Ustring ("::") + Ustring (Methode) + Ustring (" ") + Ustring (buffer))).str (), "%s %d", Text, betr);
  else
    Msg.Warning ((Ustring (Modul) += (Ustring ("::") + Ustring (Methode))).str (), "%s %d", Text, betr);
  return 0;
}

int sim_error (char *Modul, char *Methode, char *Text, char *betr, bool fatal) {
  if (fatal)
    Msg.Error ((Ustring (Modul) += (Ustring ("::") + Ustring (Methode))).str (), "%s %s", Text, betr);
  else
    Msg.Warning ((Ustring (Modul) += (Ustring ("::") + Ustring (Methode))).str (), "%s %s", Text, betr);
  return 0;
}

//==================================================================
//		Implementation
//		for class SFXToken
//==================================================================

SFXToken::SFXToken() : Token () {




}

// destructor
/*virtual*/ SFXToken::~SFXToken ()
 { }

bool SFXToken::findSentence (int sNumber, InputFile& file) {
  int sentence;

  do {
    nextToken (file);
  } while (!isInt());
  sentence = atoi (ObjData);

  if (sentence == sNumber) return true;
  if (sentence > sNumber)  file.seekg (0);

  while ((file) && (sentence != -999) && (sentence != -3)) {
    file.jump (200);   // EOL
    nextToken (file);
    sentence = atoi (ObjData);
    if (sentence == sNumber) return true;
  }

  return false;
}

bool SFXToken::findNextSentence (InputFile& file) {
  int sentence;

  do {
    nextToken (file);
    if (isInt ()) {
      sentence = atoi (ObjData);
      if (sentence != -1) {
        if ((sentence == -999) || (sentence == -3)) return false;
        else return true;
      }
    }
    file.jump (200);   // EOL
  } while (file);
  return false;
}
