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

#include <limits.h>
#include <stdio.h>
//#include <unistd.h>

#include "MathDefs.h"

#include "Vec3D.h"
#include "HMatrx3D.h"
#include "Token.h"
#include "List.h"
#include "SimTime.h"

#define _FTSNETZ_CPP
#include "modell.h"
#include "ftsnetz.h"

#include "sfx.h"
#include "transp.h"
#include "baustein.h"
#include "ereignis.h"
#include "realzeit.h"
#include "arbplan.h"



//---------------------------------------------------------
// Klasse typNetzKnoten
//---------------------------------------------------------

typNetzKnoten::typNetzKnoten (typNetzBaustein* MBaustein, Vec3D pos )
:
	nachfolger (2),
	vorgaenger (1),
	MNetzBaustein (1)
{
	belegt  = NULL;														// Nicht von einem FTS belegt
	besucht = false;													// Noch nicht von einem FTS besucht (für die Wegfindung)
	gesperrt = false;							
	reserviert = false;
	MNetzBaustein.append (MBaustein);
	ObjPosition = Vec3D ( pos.X (),pos.Y (),0);		// Koordinaten des Knoten in absoluten Angaben
																								// ACHTUNG hierbei wird immer die Z-Koordinate
																								// auf 1 gesetzt somit kann man keine Strecke
																								// übereinander anordnen
}


typNetzKnoten::~typNetzKnoten () {
	
	}


void typNetzKnoten::machnachbar (typNetzKnoten* nach) {
	nachfolger.append(*nach);
}

void typNetzKnoten::machvorgaenger (typNetzKnoten* vor) {
	vorgaenger.append(*vor);
}


void typNetzKnoten::loeschnachbar (typNetzKnoten* knoten) {
	nachfolger.remove(*knoten);
}


Vec3D typNetzKnoten::Position () {
	return ObjPosition;
}


void typNetzKnoten::setBelegt (typFtsWagen* fts) {
	belegt = fts;
}

typFtsWagen* typNetzKnoten::Belegt () {
	return belegt;
}

void typNetzKnoten::setBesucht (const bool status) {
	besucht = status;
	}


bool typNetzKnoten::Besucht () {
	return besucht;
}

void typNetzKnoten::setGesperrt (const bool status) {
	gesperrt = status;
}

bool typNetzKnoten::Gesperrt () {
	return gesperrt;
}

void typNetzKnoten::setReserviert (const bool status) {
	reserviert = status;
}

bool typNetzKnoten::Reserviert () {
	return reserviert;
}

	

// TESTFUNKTION

void typNetzKnoten::drucknachbar() const{
	for (nachfolger.First (); nachfolger (); nachfolger++) {	
		cout << nachfolger ()->ObjPosition << "\t";
	}
	nachfolger.First ();
}



void typNetzKnoten::druck() {
	cout << ObjPosition;
	cout << " \n Nächster K : ";
}
// TESTFUNKTION








	

//---------------------------------------------------------
// Klasse typNetzBaustein
//---------------------------------------------------------


typNetzBaustein::typNetzBaustein (unsigned n, unsigned b) :
	typBaustein (n,b),
	delta (1,1),
	schrittweite (1.5)													// Abstand der Knoten in Meter

	{

	}


//DynArray* typNetzBaustein::gibKnotenliste() {
//	return NetzKnotenliste;
//}



unsigned typNetzBaustein::Variante () const {
  return ObjVariante;
}


void typNetzBaustein::typTGSlesen (InputFile& file) {
	typBaustein::typTGSlesen (file);
  text =  TGBPattern::buildText (Ustring ("gesperrt"),  0.2, 1.0, ObjGeometry.Center ());

	Vec3D pos = Vec3D(ObjGeometry.Pos ().X (),ObjGeometry.Pos ().Y (),ObjGeometry.Pos ().Z ()-1);
	 positionieren (pos);



  if (ObjPalPlaetze.Count () < 2)
  sim_error ("NetzBaustein", "typNetzBaustein::typTGSlesen",
             "NetzBaustein mit nur einem Knoten", ObjVariante, FATAL);

 	NetzKnotenliste();
	typNetzKnoten* Knoten;
	// Die Knoten werden aus den Palettenplaetzen erzeugt und in die NetzKnotenliste eingehängt
	for (unsigned i=0; i<ObjPalPlaetze.Count ();i++) {
	 	Knoten = new typNetzKnoten (this,ObjPalPlaetze[i]->Position());
		NetzKnotenliste.append (*Knoten);
  }
		interneVerknuepfung();
//    druckNetz();


//  for (LCursor<typNetzKnoten> c (test); c; c++) {
//  	cout << "LISTE  \n";
//		cout << c ()->Position (); 	
//	}

// cout << "Ende";
}


/*virtual*/ ostream& typNetzBaustein::typTGSschreiben (ostream& ostrm) const {
  ostrm.precision (2);
  ostrm << "TGS: ";
  Id_Schreiben (ostrm);
  ostrm << " ";
  ostrm.width (6);
  ostrm << ObjGeometry.Pos () << " ";
  ostrm.width (6);
  ostrm << ObjWinkel.deg () << " ";
  ostrm.width (2);
  ostrm << ObjZaehler << endl;
	druckNetz();

  return ostrm;
}



void typNetzBaustein::typTBVlesen (InputFile& file) {
	typBaustein::typTBVlesen(file);
}



void typNetzBaustein::aSperren () {
	typBaustein::aSperren ();

	for (NetzKnotenliste.First (); NetzKnotenliste (); NetzKnotenliste++) NetzKnotenliste ()->setGesperrt(true);
  ObjGeometry.insert (*text);
}
	

void typNetzBaustein::eSperren () {
	typBaustein::eSperren ();
	for (NetzKnotenliste.First (); NetzKnotenliste (); NetzKnotenliste++) NetzKnotenliste ()->setGesperrt(false);
	ObjGeometry.remove (*text);

}





/**********************TESTFUNKTION**************************/

void typNetzBaustein::druckNetz () const{
	for (NetzKnotenliste.First (); NetzKnotenliste (); NetzKnotenliste++) {
		cout << NetzKnotenliste ()->Position () << "seine Nachbarn ";
		NetzKnotenliste ()->drucknachbar();
		cout <<endl;
	}

}






bool typNetzBaustein::hasKapazitaet(typTransportEinheit*) const {return true;} //noch ein witz???
void typNetzBaustein::individuellAktivieren(typBaustein*) {}
/* virtual */ void typNetzBaustein::interneVerknuepfung() {}	
/*	virtual*/ void typNetzBaustein::typTTPlesen (InputFile&) {}


//---------------------------------------------------------
// Klasse typNetzZweiBahnStrecke
//---------------------------------------------------------


typNetzZBStrecke::typNetzZBStrecke (unsigned n, unsigned b) : typNetzBaustein(n, b) {
}			


void typNetzZBStrecke::interneVerknuepfung() {

// Knoten innerhalb des Bausteins erzeugen
	Vec3D anfang = NetzKnotenliste.First ()->Position (); 	// Anfang der Strecke
	Vec3D ende = NetzKnotenliste.Next ()->Position ();			// Ende der Strecke
	Vec3D koord (0,0,0);
	Vec3D	laenge = ende - anfang;                       //
	
	typNetzKnoten* Knoten;                              // Neuer Knoten der erzeugt wird
	Vec3D schritt = laenge.unit ()*schrittweite;        // Schrittweitenvektor Einheitsvektor für die Richtung multipliziert mit der Schrittweite
	koord += schritt;

	
/* Solange Knoten zwischen Anfang und Ende erzeugen und in die Knotenliste einhängen 	*/
/* bis das Ende erreicht ist 																													*/
	while (koord.len () < laenge.len ()) {
		Knoten = new typNetzKnoten (this,anfang+koord);
		NetzKnotenliste.prepend(*Knoten,*NetzKnotenliste.Last ());
		koord += schritt;	
	}

/*** Verknuepfungen zwischen den Knoten erzeugen ***/
  typNetzKnoten* laeufer;
	typNetzKnoten* naechster;
	NetzKnotenliste.First();
	while (NetzKnotenliste.Next ()) {
 		NetzKnotenliste.Prev ();
		laeufer = NetzKnotenliste ();
		naechster = NetzKnotenliste.Next ();  	
		laeufer->machnachbar (naechster);
		naechster->machnachbar (laeufer);
	}

} 				




//---------------------------------------------------------
// Klasse typNetzEinBahnStrecke
//---------------------------------------------------------


typNetzEBStrecke::typNetzEBStrecke (unsigned n, unsigned b) : typNetzBaustein(n, b) {
}			


void typNetzEBStrecke::interneVerknuepfung() {

// Knoten innerhalb des Bausteins erzeugen
	Vec3D anfang = NetzKnotenliste.First ()->Position (); 	// Anfang der Strecke
	Vec3D ende = NetzKnotenliste.Next ()->Position ();			// Ende der Strecke
	Vec3D koord (0,0,0);
	Vec3D	laenge = ende - anfang;                       //
	
	typNetzKnoten* Knoten;                              // Neuer Knoten der erzeugt wird
	schrittweite = 1;													// Abstand der Knoten in Meter
	Vec3D schritt = laenge.unit ()*schrittweite;        // Schrittweitenvektor Einheitsvektor für die Richtung multipliziert mit der Schrittweite
	koord += schritt;

	
/* Solange Knoten zwischen Anfang und Ende erzeugen und in die Knotenliste einhängen 	*/
/* bis das Ende erreicht ist 																													*/
	while (koord.len () < laenge.len ()) {
		Knoten = new typNetzKnoten (this,anfang+koord);
		NetzKnotenliste.prepend(*Knoten,*NetzKnotenliste.Last ());
		koord += schritt;	
		
	}

/*** Verknuepfungen zwischen den Knoten erzeugen ***/

  typNetzKnoten* laeufer;
	typNetzKnoten* naechster;
	NetzKnotenliste.First();
	while (NetzKnotenliste.Next ()) {
 		NetzKnotenliste.Prev ();
		laeufer = NetzKnotenliste ();
		naechster = NetzKnotenliste.Next ();  	
		laeufer->machnachbar (naechster);
		naechster->machvorgaenger (laeufer);
	}

} 				






//---------------------------------------------------------
// Klasse typNetzKurve
//---------------------------------------------------------

typNetzKurve::typNetzKurve (unsigned n, unsigned b) : typNetzBaustein(n, b) {
}			

void typNetzKurve::interneVerknuepfung() {
	Vec3D vr;
	if (ObjVariante != 3) vr = ObjPalPlaetze[1]->Position () - Position ();
	else vr = ObjPalPlaetze[0]->Position () - Position ();
	typNetzKnoten* Knoten;
        delta = Angle(schrittweite/vr.len(),1);
		/*** Es werden im Winkel von DELTA jeweils neue Knoten erzeugt ***/
		for (Angle drehw(delta); drehw.deg () <90; drehw += delta) {
      Knoten = new typNetzKnoten (this,Position () + vr * ZrotHMatrx3D(drehw));
			if (ObjVariante !=3) NetzKnotenliste.append(*Knoten,*NetzKnotenliste.First ());
	  	else NetzKnotenliste.prepend(*Knoten,*NetzKnotenliste.Last ());
 		}


/*** Verknuepfungen zwischen den Knoten erzeugen ***/
	typNetzKnoten* laeufer;
	typNetzKnoten* naechster;
	NetzKnotenliste.First();
	while (NetzKnotenliste.Next ()) {
 		NetzKnotenliste.Prev ();
		laeufer = NetzKnotenliste ();
		naechster = NetzKnotenliste.Next ();  	
		laeufer->machnachbar (naechster);
		if (ObjVariante == 1) naechster->machnachbar (laeufer); // Rückverknüpfung nur machen
		else naechster->machvorgaenger (laeufer);								// wenn es sich um eine ZweiBahnKurve handelt

	}

} 				
	



//---------------------------------------------------------
// Klasse typNetzAbzweigung
//---------------------------------------------------------


typNetzAbzweigung::typNetzAbzweigung (unsigned n, unsigned b) : typNetzBaustein(n, b) {
}			



void typNetzAbzweigung::interneVerknuepfung() {
//	cout << " Kreuzung. : ";
		
/*** Berechnung des Mittelpunkts der Krümmung **/
	Vec3D v1 = ObjPalPlaetze[0]->Position ();
	Vec3D v2 = ObjPalPlaetze[2]->Position ();
	Vec3D v3 = ObjPalPlaetze[1]->Position ();
	Vec3D v12 = v2 - v1;
	Vec3D v13 = v3 - v1;
	Vec3D vr = v13.projOn(v12);
	Vec3D vm1 = v3-vr;
	Vec3D vm2 = v3+vr;

		typNetzKnoten* Knoten;
		typNetzKnoten* laeufer;
		typNetzKnoten* naechster;
		Angle drehw(delta);
		
	if (ObjVariante == 1) {  // ZweiBahnAbzweigung
	/** Erzeugen der Knoten auf der Krümmung **/
		for ( ; drehw.deg () < 90; drehw += delta) {
			Vec3D vneu = vm1+(vr*ZrotHMatrx3D(drehw));
    	Knoten = new typNetzKnoten (this,vneu);
			NetzKnotenliste.append(*Knoten,*NetzKnotenliste.First ());			
			Vec3D vneu2 = vm2+(vr*ZrotHMatrx3D(-drehw+Angle(180)));
    	Knoten = new typNetzKnoten (this,vneu2);
			NetzKnotenliste.prepend(*Knoten,*NetzKnotenliste.Last ());			
		}

		NetzKnotenliste.First ();
		while (NetzKnotenliste.Next ()) {
 			laeufer = NetzKnotenliste.Prev ();
			naechster = NetzKnotenliste.Next ();  	
			laeufer->machnachbar (naechster);
			naechster->machnachbar (laeufer);
		}
		/*** Spezielle Verknüpfung der geraden Durchgangsstrecke ***/
		NetzKnotenliste.First ()->machnachbar (NetzKnotenliste.Last ());
		NetzKnotenliste.Last ()->machnachbar (NetzKnotenliste.First ());

	}
  else {	// EinBahnAbzweigung
	Vec3D vneu;
		for ( ; drehw.deg () < 90; drehw += delta) {
			if (ObjVariante == 2 ) vneu = vm1+(vr*ZrotHMatrx3D(drehw));
			else vneu = vm1+(vr*ZrotHMatrx3D(-drehw));
    	Knoten = new typNetzKnoten (this,vneu);
			NetzKnotenliste.append(*Knoten,*NetzKnotenliste.First ());
		}

		
		NetzKnotenliste.First ();

		for (unsigned i =1 ; i<= (NetzKnotenliste.Count ()-2); i++){
			laeufer = NetzKnotenliste();
			naechster = NetzKnotenliste.Next ();  	
			laeufer->machnachbar (naechster);
			naechster->machvorgaenger (laeufer);
		}		
		/*** Spezielle Verknüpfung der geraden Durchgangsstrecke ***/
		NetzKnotenliste.First ()->machnachbar (NetzKnotenliste.Last ());
		NetzKnotenliste.Last ()->machvorgaenger (NetzKnotenliste.First ());

  }



} 				

