// $Source: /usr/local/SimSoft/Sfx3D/src/gsl/ftsver.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: ftsver.cpp,v $
// Revision 1.2  2001/11/29 15:18:09  baum
// -Realzeitsteuerung eingebaut
// -Handsteuerung eingebaut
//

#include <limits.h>
#include <float.h>

#include "Token.h"

#define _FTSVER_CPP
#include "modell.h"
#include "ftsver.h"


#include "sfx.h"
#include "transp.h"
#include "baustein.h"
#include "fts.h"
#include "realzeit.h"
//---------------------------------------------------------
// Klasse typFtsVerwalter
//---------------------------------------------------------

typFtsVerwalter::typFtsVerwalter (unsigned n, unsigned b)
  : typBaustein          (n, b),
    ObjFtsWagen          (),     // Liste der untaetigen FtsWagen
		GKnotenliste				 (30) 	 //lar
{
  ObjAvis = new typAvis ();
}

typFtsVerwalter::~typFtsVerwalter ()
{ }

void typFtsVerwalter::typTPVlesen (InputFile& file) {
  SFXToken tok;
  int anzahl;
  int nr;

  tok.nextToken (file);
  anzahl = atoi (tok ());
  for (int z = 1; z <= anzahl; z++) {
  	tok.nextToken (file);
    nr = atoi (tok ());
   	ObjFtsWagen.append (*((typFtsWagen*) baustein [nr]));
   	baustein [nr]->setVerwalter (this);
	}	
		

	Netzbesetzung ();

//	for (GKnotenliste.First (); GKnotenliste (); GKnotenliste++) {
  	//cout << " Knoten " << GKnotenliste ()->Position () << " seine Nachbarn ";
		//GKnotenliste ()->drucknachbar();
		//cout << endl;
//	}

}

/*ostream& typTPVschreiben (ostream& ostrm) {
  //io_fw_int(fout, i_Nr(), "FtsVerwalter %3i\n");
}
//
void typFtsVerwalter::typTSTlesen (InputFile& file) {
  //hier noch auffuellen
  }*/

bool typFtsVerwalter::hasKapazitaet (typTransportEinheit* zTE) const {
  for (ObjFtsWagen.First (); ObjFtsWagen (); ObjFtsWagen++)
    if (ObjFtsWagen ()->hasKapazitaet (zTE))  return true;
  return false;
}

unsigned typFtsVerwalter::Kapazitaet () const {
  return ObjFtsWagen.Count ();
}

void typFtsVerwalter::aktivieren (unsigned vonWem) {
  individuellAktivieren ((typBaustein*) vonWem);
  setZustand (AKTIVIERT);
}

// eingefügt lar 07.09.00





void typFtsVerwalter::Netzbau (typNetzBaustein* Bst) {


/*	Ablauf der Methode
	  1 	Durchgehen der Knotenliste des Übergebenen Bausteins
		2 	Wenn in der GListe ein Knoten mit den "selben" Koordinaten vorhanden ist, dann
		2.1	Anhängen der Nachfolgerliste des Knoten an die NListe des Knoten in der GListe
		2.2 Für die Knoten in der Nachfolgerliste des Bst. den Knoten aus der GListe anhängen und den Knoten des Bst. aus allen Nachfolgerlisten löschen
		2.3 Löschen des nicht eingehängten Knotens
		3		sonst : Anhängen des Knoten in die GListe
*/
  Vec3D laeuferKoord;
	Vec3D glaeuferKoord;
	typNetzKnoten* killer = NULL;
	bool gefunden=false;
//  cout << "Aufruf für " <<Bst->Nummer()<<endl;
	if (GKnotenliste.isEmpty ()){				// Nur für den ersten Baustein damit ein Bst in der GKnotenliste steht
		GKnotenliste.append ((Bst->NetzKnotenliste));
    }
	else {
		for (Bst->NetzKnotenliste.First (); Bst->NetzKnotenliste (); Bst->NetzKnotenliste++) {
      //cout << "Bst nr "<< Bst->Nummer()<< " Knoten "<<Bst->NetzKnotenliste ()->Position ()<<endl;
			laeuferKoord = (Bst->NetzKnotenliste ())->Position ();
		  gefunden = false;
			for (GKnotenliste.First ();GKnotenliste (); GKnotenliste++) {
				glaeuferKoord = GKnotenliste ()->Position ();			
			/** Wenn der Abstand 2er Knoten < 0,3 m ist, wird der neue Knoten nicht eingehängt sondern es wird die Nachfolgerliste
					 dieses Knoten an die Liste des schon vorhandenen Knotens angehängt **/
				if (fabs ((glaeuferKoord - laeuferKoord).len ()) < 0.1) {
					// An Knoten in G. werden die Nachbarn des Bst angehängt
					GKnotenliste ()->nachfolger.append(Bst->NetzKnotenliste ()->nachfolger);
	        /** Besondere Verknüpfung für Einbahnstrecken da diese keinen Verweis auf den Vorgänger in der nachbarliste haben **/
					if ((Bst->Basistyp () == tFtsEinbahnstrecke) || ((Bst->Basistyp () == tFtsKurve) && (Bst->Variante () != 1 ))|| ((Bst->Basistyp () == tFtsAbzweigung) && (Bst->Variante () != 1 ))) {
	  				for ( Bst->NetzKnotenliste ()->vorgaenger.First (); Bst->NetzKnotenliste ()->vorgaenger (); Bst->NetzKnotenliste ()->vorgaenger++) {
							Bst->NetzKnotenliste ()->vorgaenger ()->machnachbar (GKnotenliste ());
							Bst->NetzKnotenliste ()->vorgaenger ()->loeschnachbar (Bst->NetzKnotenliste ());
						}	
					}
					else {
					/** Durch die Nachbarliste des übergebenden Bausteins gehen und dort für jeden Knoten einen neuen Nachbarn anlegen **/
  					for ( Bst->NetzKnotenliste ()->nachfolger.First (); Bst->NetzKnotenliste ()->nachfolger (); Bst->NetzKnotenliste ()->nachfolger++) {

							Bst->NetzKnotenliste ()->nachfolger ()->machnachbar (GKnotenliste ());
							Bst->NetzKnotenliste ()->nachfolger ()->loeschnachbar (Bst->NetzKnotenliste ());
					  }
					}
					killer = Bst->NetzKnotenliste ();
					/** Der Knoten aus der GListe wird in die Knotenliste des Bausteins eingehängt. Grund: Sperren eines Bausteins und deren Knoten **/
					Bst->NetzKnotenliste.prepend(*GKnotenliste (),*killer);
					/** Der nicht eingefügte Knoten wird gelöscht (Speicherfreigabe) **/
					delete Bst->NetzKnotenliste.remove(*killer);
					Bst->NetzKnotenliste.find(*GKnotenliste ());

					gefunden = true;
				}
			}	
			/** Wird kein Knoten in der GListe gefunden-> Anhängen des Knotens **/			
			if (!gefunden) GKnotenliste.append(*(Bst->NetzKnotenliste ()));

			
		}
	}
}
				



void typFtsVerwalter::individuellAktivieren (typBaustein*) {

  //===============================================================
  typFtsWagen* zWagen;
 	typMeldung* zMeldung;
 //===============================================================
	if (ObjFtsWagen.isEmpty ()) {
    sim_error ("FTSVERWALTER", "typFtsVerwalter::individuellAktivieren",
               "Keine FtsWagen zu verwalten", ObjFtsWagen.Count (), FATAL);
	}

 //	typMeldung* d;
 //for (LCursor<typMeldung> c (ObjMeldungen); c (); c++) {
//			d = c ();
//      typTransportEinheit* zTE = d->TransportEinheit ();
   		// schaue auf den naechsten Baustein
//   		typBaustein* zNext = zTE->nextBaustein ();

//		cout << " Meldungen des FTSVer von Bst : " << (d->VonBaustein())->Nummer() << " nach "<< zNext->Nummer()<< endl;
//     }
//cout << "Leer"<<endl;
  if (ObjMeldungen.isEmpty ()) {
    setZustand (RUHE);
  }
  else {
    // Solange Liste gefuellt ist und es einen freien Wagen gibt,
    // werden die Meldungen weitergegeben
		for (LCursor<typMeldung> c (ObjMeldungen); c (); c++) {
			zMeldung = c ();

   		typTransportEinheit* zTE = zMeldung->TransportEinheit ();
   		// schaue auf den naechsten Baustein
   		typBaustein* zNext = zTE->nextBaustein ();

	    if (zNext->hasKapazitaet (zTE)) {
				zWagen = findeFreienWagen (zMeldung);
				if (zWagen) {
	 				// hier eine Frage: muss folgende Zeile sein???
	 				// FtsWagen wird ZielBaustein gegeben
	 				zMeldung->setNachBaustein (zWagen);
					if (!zWagen->hasMeldungen ())
	 					zWagen->empfangeMeldung (zMeldung);
			  	ObjMeldungen.remove (*zMeldung);
	 				// dem ObjZielBaustein muss Buchung gegeben werden! Deshalb folgende Zeile
	 				// ansonsten fuehrt es zu einem DeadLock
	 				// rudi*** 12.10.2000
			  	typTransportEinheit* zTE = zMeldung->TransportEinheit ();
          zTE->setZielPlatz (zTE->nextBaustein ()->waehlePlatz (zTE));

				}
	    }
	 	} // for

    if (!ObjMeldungen.isEmpty ()) {
      setZustand (POLLING);
      //planedelta(0.5, ETaktivieren, ObjNummer, ObjNummer);
    }
    else
      setZustand (RUHE);
  }
}




typFtsWagen* typFtsVerwalter::findeFreienWagen (typMeldung* zMeldung) {
  typBaustein* zBst = zMeldung->VonBaustein ();

	typFtsWagen* gewinner = NULL;
  double min_Abstand = DBL_MAX;
  //===============================================================
  for (ObjFtsWagen.First (); ObjFtsWagen (); ObjFtsWagen++) {
  	if (ObjFtsWagen ()->hasMeldungen ()) continue;
    if (/*(ObjFtsWagen ()->Zustand () == RUHE) && */(!(ObjFtsWagen ()->Belegung ())
    		&& (!ObjFtsWagen ()->isGesperrtOrGestoert ()) && (!(ObjFtsWagen ()->hasMeldungen ())))) {
    	typFtsWagen* Wagen = ObjFtsWagen ();
			// Abstand zwischen TE und FTS-Wagen wird berechnet
	    Vec3D abs_Abstand (zBst->Position () - Wagen->Position ());
	    double Abstand = abs_Abstand.len ();

	    if (Abstand < min_Abstand) {
  		    min_Abstand = Abstand;
  		    gewinner = Wagen;
  		 }
  	}
  }
  if (gewinner) return gewinner;
  else return NULL;
}



typNetzKnoten* typFtsVerwalter::suchKnoten(typBaustein* Bst){
	typNetzKnoten *suchknoten;
  double min_q_abstand = DBL_MAX;

  for (GKnotenliste.First (); GKnotenliste (); GKnotenliste++) {
		Vec3D q_Abstand (GKnotenliste ()->Position () - Bst->Position ());
	  double Abstand = q_Abstand.len ();

    if ( Abstand  <  min_q_abstand) {
    	suchknoten = GKnotenliste ();
      min_q_abstand = Abstand;
    }
  }
  return suchknoten;
}


/*** lar 14.09.00 ***/
void typFtsVerwalter::Netzbesetzung () {
  for (ObjFtsWagen.First (); ObjFtsWagen (); ObjFtsWagen++)
    ObjFtsWagen ()->initIstKnoten ();
}
		


