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

#define _KETTFOER_CPP

#include "Kalender.h"
#include "Vec3D.h"
#include "MathDefs.h"
#include "modell.h"
#include "sfx.h"
#include "transp.h"
#include "baustein.h"
#include "ereignis.h"
#include "route.h"
#include "realzeit.h"
#include "arbplan.h"
#include "kettfoer.h"
#include "querfoer.h"

//---------------------------------------------------------
// class typKettenglied
//---------------------------------------------------------

typKettenglied::typKettenglied (typTransportEinheit *zWs, unsigned PlatzNr)
 : ObjAktPlatz   (PlatzNr),
   ObjTransportEinheit (zWs),
   hatAbgemeldet (false),
   hatAngemeldet (false),
   quellPlatz(NULL)
   {}

typKettenglied::~typKettenglied ()
 { }

typTransportEinheit* typKettenglied::Transp () const {
  return ObjTransportEinheit;
}

unsigned typKettenglied::IstPlatz () const {
  return ObjAktPlatz;
}

void typKettenglied::incAktPlatz () {
  ObjAktPlatz++;
}

typBaustein* typKettenglied::getvonBaustein() const{
   return quellPlatz;
}

//---------------------------------------------------------
// class typKettenfoerderer
//---------------------------------------------------------


// Konstruktor
typKettenfoerderer::typKettenfoerderer (unsigned n, unsigned b)
 : typBaustein (n, b),
   ichBelege             (false),
   ichFoerderebereits    (false),
   ObjLaenge             (0.0),
   ObjFoerderGeschw      (0.0),
   ObjNormalGeschw       (0.0),
   ObjKettGlAbst         (0.0),
   ObjFoerderzeitGlAbst	 (0.0),
   // Sicherheitsabstand in Kettengliedern
   ObjSicherheitsAbst    (0),
   // Sicherheitsabszand in Metern
   ObjSicherheitInMetern  (0.0),
   ObjAnzKettenglieder   (0),
   ObjRichtung       (),
   // Liste der Kettenglieder
   ObjMeineQuerfoerderer (2),
   ObjKettengliederListe (),
   platzDesLetztenQuerfoerderers(0),
   meinLetzterQuerfoerderer(NULL),
   querfoerdererVorhanden   (false),
   anfangsSicherheit    (0),
   merkerLetzterQuerfoerderer (0)
 { }
// Ende Konstuktor

// Destuktor
typKettenfoerderer::~typKettenfoerderer ()
 { }
// Ende Destruktor

// Einlesen der technischen Parameter
/*virtual*/ void typKettenfoerderer::typTTPlesen (InputFile& file) {
  SFXToken tok;
  tok.nextToken (file);
  ObjFoerderGeschw      = atof (tok ());
  if (!ObjFoerderGeschw)
    sim_error ("FFSKett", "typKettenfoerderer::typTTPlesen",
               "Es wurde keine Foerdergeschwindigkeit gesetzt!", ObjNummer, FATAL);
  tok.nextToken (file);
  ObjLaenge             = atof (tok ());
  tok.nextToken (file);
  //Sicherheitsabstand wird in Kettengliedern angegeben
  ObjAnzKettenglieder   = atof (tok ());
  tok.nextToken(file);
  ObjSicherheitsAbst    = atoi (tok ());
  file.jump (100); //EOL
  ObjNormalGeschw          = ObjFoerderGeschw;
  ObjKettGlAbst         = ObjLaenge / ObjAnzKettenglieder;
  ObjFoerderzeitGlAbst  = SimTime((ObjKettGlAbst / ObjFoerderGeschw) * SimTime::SecondsPerMinute ());
  ObjSicherheitInMetern  = ObjSicherheitsAbst * ObjKettGlAbst;
  ObjRichtung = ObjPalPlaetze [1]->Position () - ObjPalPlaetze [0]->Position ();
  ObjRichtung = ObjRichtung.unit ();
}
// Ende Einlesen der technischen Parameter

//addEingang
/**
Die Funktion addEingang wird von Querfoerderern aufgerufen,
deren Eingang an diesem Kettenfoerderer liegen.
Der aufrufende Querfoerderer wird an die Funktion addToMap weitergereicht.
*/
/*virtual*/ void typKettenfoerderer::addEingang (typBaustein* eingang) {
  ObjEingaenge.append (*eingang);
  if (eingang->Basistyp() == tQuerfoerderer){
        addToMap((typQuerfoerderer*) eingang);
  }
}
//Ende addEingang

//addAusgang
/**
Die Funktion addAusgang wird von Querfoerderern aufgerufen,
deren Ausgang an diesem Querfoerderer liegt.
Der aufrufende Querfoerderer wird an die Funktion addToMap weitergereicht.
*/
/*virtual*/ void typKettenfoerderer::addAusgang (typBaustein* ausgang) {
  ObjAusgaenge++;
  if (ausgang->Basistyp() == tQuerfoerderer){
        addToMap((typQuerfoerderer*) ausgang);
  }//if
}//Ende addAusgang

//addToMap
/**
Diese Funktion wird von den Funktionen addAusgang und addEingang aufgerufen und es wird ein
Querfoerderer uebergeben.
Diese Querfoerderer werden in der Funktion getPosition auf ihre Positionen im Kettenfoerderer
ueberpueft. Die Funktion getPosition liefert den Platz in Bezug auf ein Kettenglied des
Kettenfoerderer's zurueck.
Die Pruefung ob der Querfoerderer wirklich im Kettenfoerderer steht geschieht in der
if (this->Winkel() != querfoerderer->Winkel()) Anweisung.
Gehoert ein Querfoerderer zu diesem Kettenfoerderer, muss seine Transportrichtung nicht
gleich der Transportrichtung dieses Kettenfoerderers sein.
War die if Pruefung erfolgreich, wird dem uebergebenen Querfoerderer die Uebergabe Position
dieses Kettenfoerderers uebergeben. Weiterhin wird der Kettenfoerderer dem aufrufenden
Querfoerderer mitgeteilt. Das dieser Kettenfoerderer seinem Querfoerderer bekannt ist,
ist zur Regelung des Verkehrs der Transporteinheiten ausschlaggebend.
*/
void typKettenfoerderer::addToMap(typQuerfoerderer* querfoerderer){
	querfoerdererVorhanden = true;
     anfangsSicherheit = ((unsigned)querfoerderer ->Laenge(ObjRichtung).len ()/ObjKettGlAbst);
     if (!ObjMeineQuerfoerderer.find(*querfoerderer)){
        unsigned position = getPosition(querfoerderer);

        if (merkerLetzterQuerfoerderer < position){
           merkerLetzterQuerfoerderer = position;
           platzDesLetztenQuerfoerderers = position; 	
           meinLetzterQuerfoerderer = querfoerderer;
        }
        if (this->Winkel() != querfoerderer->Winkel()){
           querfoerderer->setzeMeinenKettenfoerderer(this);
           querfoerderer->setzeSpezUebergabePosition(ObjPalPlaetze [0]->Position () + (ObjRichtung*position*ObjKettGlAbst));
           querfoerderer->setzeObjFoerderRichtungKett (ObjPalPlaetze [1]->Position () - ObjPalPlaetze [0]->Position ());
           ObjMeineQuerfoerderer.insert(*querfoerderer,*(new unsigned(position)));
        }

    }//if
}//Ende addToMap

// getPosition
/**
   Siehe Erklaerung addToMap.
*/
unsigned typKettenfoerderer::getPosition(typQuerfoerderer* querfoerderer){
    
    return (unsigned) Round((querfoerderer->Position() + (querfoerderer->Laenge(ObjRichtung))*0.5
                -(ObjPalPlaetze [0]->Position ())).projOn(ObjRichtung).len()
                 / ObjKettGlAbst);
}// Ende getPosition

// individuellAktivieren
/**
Die Funktion individuellAktivieren ist fuer die Aufnahmen einer Transport von einem
Nachbarbaustein im Zusammenspiel mit den Funktionen findeAusfuehrbareMeldung (),
waehlePlatz (typTransportEinheit* zW), passtDrauf (typTransportEinheit *zTE),
wartenaufnehmen (typTransportEinheit* zW, typBaustein* vonWem) und hasKapazitaet (typTransportEinheit* )
verantwortlich.
Die Nachbarbausteine rufen diese Funktion auf, wenn sie eine Transporteinheit
abgeben wollen. Das Zusammenspiele der oben genannten Funktionen prueft ob
die Transporteinheit aufgenommen werden darf.
Darf die Transporteinheit aufgenommen werden, werden alle notwendigen Variablen dafuer
gesetzt und das Aufnehmen wird eingeleitet.
*/
/*virtual*/ void typKettenfoerderer::individuellAktivieren(typBaustein*){
    typMeldung* zM ;
    if ((!ObjTransportEinheit && ObjZustand != FOERDERN && ObjZustand != WARTEN)){
        zM = findeAusfuehrbareMeldung ();
        if (zM){
            ObjTransportEinheit = zM->TransportEinheit ();
            ObjZielBaustein = zM->VonBaustein ();
            wartenaufnehmen (ObjTransportEinheit, ObjZielBaustein);
        }//if
    }//if
}// Ende individuell Aktivieren

// findeAusfuehrbareMeldung()
/**
Sucht die vorhanden Meldung durch.
*/
typMeldung* typKettenfoerderer::findeAusfuehrbareMeldung () {
   typTransportEinheit* zBuch = ObjPalPlaetze [0]->Buchung ();
   for (LCursor<typMeldung> c (ObjMeldungen); c; c++) {
       typTransportEinheit* zW = c ()->TransportEinheit ();
       if ((!zBuch) || (zW == zBuch)) {
          if (waehlePlatz (zW) != NULL){
             if (!zBuch && zW != ObjTransportEinheit)  zW->setZielPlatz (waehlePlatz (zW));
                        return &(ObjMeldungen.prepend (*(ObjMeldungen.remove (c))));
          }//if
       }//if
  }//for
  return NULL;
}//Ende findeAusfuehrbareMeldung()

// waehlePlatz()
/*virtual*/ typPlatz* typKettenfoerderer::waehlePlatz (typTransportEinheit* zW) {
    typPlatz* p (ObjPalPlaetze[0]);
    if (zW->Baustein()->Basistyp() == tQuerfoerderer && passtDrauf(zW)){
        return p;
    }//if
    else{
        if (p->Buchung ())  return (p->Buchung () == zW) ? p : NULL;
            if (passtDrauf (zW)) {
                p->setBuchung(zW);
                ObjBuchung++;
                return p;
            }//if
            else return NULL;
    }//else
}//Ende WaehlePlatz()

// passtDrauf
/**
   Prueft ob die Transporteinheit aufgenommen werden darf.
   Die Transporteinheit darf nicht aufgenommen werden wenn:
       Auf dem letzten Kettenglied eine Transporteinheit vorhanden ist.
       Eine Transporteinheit sich Angemeldet hat(Ausgang, Querfoerderer).

*/
/*virtual*/bool typKettenfoerderer::passtDrauf (typTransportEinheit *zTE) const {
   bool g = true;
   LCursor<typKettenglied> c (ObjKettengliederListe);
   for (typKettenglied *k ; (k = c ()) != NULL; c++){
       if (k->ObjAktPlatz == ObjAnzKettenglieder){
          g = false;
          for(ObjMeineQuerfoerderer.First(); ObjMeineQuerfoerderer() != NULL; ObjMeineQuerfoerderer++){
              typQuerfoerderer* qf= ObjMeineQuerfoerderer.findKey(*ObjMeineQuerfoerderer());
              if(zTE->Baustein() == qf){
                  g = true;
              }//if
          }//for
       }//if
       if (c()->hatAngemeldet == true){
          g = false;
       }//if
   }//for
   return (g);
}// Ende passtDrauf

//hasKapazitaet
/**
   Diese Funktion wird nicht benutzt.
   Die Kapazitaet regelt sich ueber den Sicherheitesabstand und
   die Anzahl der Kettenglieder selbst.
*/
/*virtual*/ bool typKettenfoerderer::hasKapazitaet (typTransportEinheit* ) const {
  if (ObjPalPlaetze [0]->Buchung ())
    return false;
  else
    return passtDrauf (NULL);
}// Ende hasKapazitaet

//wartenAufnehmen
/**
 Leitet das Aufnehmen ein.
*/
/*virtual*/ void typKettenfoerderer::wartenaufnehmen (typTransportEinheit* zW, typBaustein* vonWem) {
  if (vonWem->isUebergabeBereit (zW, this)) {
      setZustand (AKTIVIERT);
      planesofort (ETaaufnehmen, ObjNummer, vonWem->Nummer ());
  }//if
  else {
      vonWem->UebergabeVorbereiten (zW);
  }//else
}//Ende wartenAufnehmen

// a_aufnehmen
/**
   Diese Funktion stellt der aufzunehmenden Transporteinheit ein Kettenglied zur Verfuegung, welches fuer
   die Transporteinheit neu erzeugt wird.
   Es werden Zwei Faelle unterschieden!!!

   Fall 1: Die Transporteinheit kommt von einem Querfoererer.
           In diesem Fall wird ein Kettenglied erfeugt und genau an der
           Stelle wo sich das Kettenglied in der Kettengliederliste stehen wuerde eingegliedert.
           Die Transporteinheit wird sofort bei dem Vorgaengerbaustein abgemeldet um in diesem
           Takt die Aufnahme von anderen Transporteinheiten zu ermoeglichen.

   Fall 2: Die Transporteinheit kommt vom Eingang.
           Es wird ebenfalls ein Kettenglied erzeugt.
           Dieses Kettenglied wird in der Kettengliederliste welche die Kettenglieder
           verwaltet an das Ende gegliedert. Sollt kein Kettenglied vorhanden sein wird
           natuerlich an den Anfang gegliedert. Deises Verhalten gilt selbstverstaendlich auch
           fuer Fall 1.
           In diesem Fall wird die Transporteinheit jedoch noch nicht abgemeldet, da die
           Transporteinheit sich noch auf dem Vorgaengerbaustein befindet.
           Die Transporteinheit wird in e_foerdern abgemeldet wenn sich die Transporteinheit
           vollstaendig auf diesem KettenKettenfoerderer befindet.
           zu diesem Zweck wurde dem Kettenglied der Merker quellPlatz mitgegeben, um in einem
           Foerdertakt das Aufnehmen von einem bzw. mehreren Querfoerdern zu ermoeglichen.
           Die Merker ObjZielPlatz und ObjTransportEinheit werden nach dem Aufnehmen, das Aufnehmen
           ist beendet wenn e_aufnehmen vollstaendig abgearbeitet wurde, auf NULL gesetzt somit ist
           ein erneutes Aufnehmen moeglich.

*/
/*virtual*/ void typKettenfoerderer::a_aufnehmen () {
    LCursor<typKettenglied> c (ObjKettengliederListe);
    unsigned platzNummer = 0;
    Vec3D v (ObjPalPlaetze [0]->Position ());
    setZustand (AKTIVIERT);
    typKettenglied *zK;
    typMeldung *zM = holeMeldung ();
    if (zM->TransportEinheit()->Baustein()->Basistyp() == tQuerfoerderer){
         bool vorGliedern = false;
         for(ObjMeineQuerfoerderer.First(); ObjMeineQuerfoerderer() != NULL; ObjMeineQuerfoerderer++){
            typQuerfoerderer* qf = ObjMeineQuerfoerderer.findKey(*ObjMeineQuerfoerderer());
            if (zM->TransportEinheit()->Baustein() == qf){
                platzNummer = *ObjMeineQuerfoerderer();
            }//if
         }//for
         for (typKettenglied *k ; (k = c ()) != NULL; c++){
              if (k->IstPlatz() < platzNummer){
                vorGliedern = true;
                break;
              }//if
         }//for
         zK = new typKettenglied(zM->TransportEinheit (), platzNummer);
         zK->quellPlatz = ObjZielBaustein;
         if(vorGliedern == true){
            ObjKettengliederListe.prepend(*zK,c);
         }
         else
           ObjKettengliederListe.append(*zK);
           ObjZielBaustein->gibTransportEinheit (zM);
           Vec3D w (zM->TransportEinheit()->Position());
           aufnehmenEinleiten (v + ((ObjRichtung*zK->IstPlatz()*ObjKettGlAbst)-(ObjTransportEinheit->Laenge(ObjRichtung)*0.5)), ObjAufnahmezeit);
           zK->hatAbgemeldet = true;
           planesofort (ETeabgeben, ObjZielBaustein->Nummer(), ObjNummer);

     }//if
     else{
        zK = new typKettenglied(zM->TransportEinheit (), 0);
        zK->quellPlatz = ObjZielBaustein;
        ObjKettengliederListe.append( *zK);
        ObjZielBaustein->gibTransportEinheit (zM);
        aufnehmenEinleiten (v -(ObjTransportEinheit->Laenge(ObjRichtung)*0.5), ObjAufnahmezeit);
     }//else
}//Ende a_aufnehmen

//e_aufnehmen
/**
Siehe a_aufnehmen.
Weiterhin wird a_foerdern eingeplant.
*/
/*virtual*/ void typKettenfoerderer::e_aufnehmen() {
    LCursor<typKettenglied> c (ObjKettengliederListe);
    setZustand (AKTIVIERT);
    if(ObjZielBaustein->Basistyp()==tQuerfoerderer){}
    else if (ObjTransportEinheit->AktPlatz ()==ObjPalPlaetze[0]){
         typPlatz *p (ObjTransportEinheit->AktPlatz ());
         if (p->Buchung () != ObjTransportEinheit)
            sim_error ("FFSKett", "typKettenfoerderer::e_aufnehmen",
            "Transpueck ist nicht auf Platz gebucht", ObjNummer, FATAL);
            p->setBuchung (NULL);
            ObjBuchung--;
    }//else if
    for(ObjMeineQuerfoerderer.First(); ObjMeineQuerfoerderer() != NULL; ObjMeineQuerfoerderer++){
   	typQuerfoerderer* qf= ObjMeineQuerfoerderer.findKey(*ObjMeineQuerfoerderer());
   	if( qf == ObjZielBaustein)
   	    qf->KettenGliedIstBelegt();
    }//for
    ObjTransportEinheit = NULL;
    ObjZielBaustein = NULL;
    planeein (Modellzeit(),ETafoerdern, ObjNummer, 0);
}//Ende e_aufnehmen

// a_foerdern
/**
Liefert die Funktion DarfIchAufDenQuerfoerderer() true und ist der vorhergehende
Foerdertakt abgeschlossen, es darf gefoerdert werden.
Hierbei wird das Kettenglied und die zugehoerige Transporteinheit
um einen Kettengliedabstand weiter in Foerderrichtung geschoben.
*/
/*virtual*/ void typKettenfoerderer::a_foerdern () {
    if (ichFoerderebereits==false){
        LCursor<typKettenglied> c (ObjKettengliederListe);
        if (DarfIchAufDenQuerfoerderer() ){
           ichFoerderebereits = true;
           setZustand (FOERDERN);
            for(c.First(); c () != NULL; c++) {
                //das Kettenglied wird um einen Platz weiter nach vorn geschoben
                c() -> incAktPlatz ();
                //das Transpueck wird ebenfalls weiter geschoben damit es auf dem
                //Kettenglied bleibt
                c() -> Transp()->bewegen(ObjRichtung * ObjKettGlAbst);
            }//for
            planeein (Modellzeit ()+ ObjFoerderzeitGlAbst, ETefoerdern, ObjNummer, 0);
        }//if
    }//if
}//ENDE a_foerdern

//e_foerdern
/**
Am Ende eines jeden Foerdertaktes wird diese Funktion aufgerufen.
Besonderheiten:
               Ist eine Transporteinheit vom Eingang aufgenommen worden
               wird diese in dieser Funktion abgemeldet, wenn sie vollstaendig
               auf diesem Kettenfoerderer steht.

               Ist eine Meldung vorhanden wird dieser Kettenfoerderer
               sich selbst aktivieren um die Transporteinheit aufzunehmen.Ansonsten
               wird a_foerdern eingeplant.
*/
/*virtual*/ void typKettenfoerderer::e_foerdern () {
    bool kettenGliedVorhanden = false;
    setZustand(RUHE);
    bool mussFoerdern = true;
    bool planeFoerdern = false;
    LCursor<typKettenglied> c (ObjKettengliederListe);
    for (typKettenglied *k ; (k = c ()) != NULL; c++){
       unsigned i = (unsigned) (k->Transp ()->Laenge (ObjRichtung).len() / ObjKettGlAbst);
        kettenGliedVorhanden = true;
        unsigned V; 
        if ( querfoerdererVorhanden){
        	 V = anfangsSicherheit + ObjSicherheitsAbst;
        }
        else 
        	V = ObjSicherheitsAbst + i;
        if(V < k->IstPlatz() && k-> hatAbgemeldet ==false){
             planesofort (ETeabgeben, k->getvonBaustein()->Nummer(), ObjNummer);
             k-> hatAbgemeldet =true;
        }//if
        if (k->IstPlatz() >= ObjAnzKettenglieder && k->hatAngemeldet == false){
           if (k->ObjTransportEinheit->nextBaustein() != meinLetzterQuerfoerderer){
                          k->ObjTransportEinheit->Anmelden();
                          k->hatAngemeldet = true;
             }
             setZustand(WARTEN);
             mussFoerdern = false;

       }//if
    }//for
    if (mussFoerdern == true ){
        if(passtDrauf(NULL) && !ObjMeldungen.isEmpty() && !ObjTransportEinheit){
            if (DarfIchAufDenQuerfoerderer()){
               planesofort(ETaktivieren, ObjNummer, ObjNummer);
            }//if
        }//if
        else{
            if (Strategie() != 1 ){
                if (kettenGliedVorhanden){
                   planeein( Modellzeit(), ETafoerdern, ObjNummer, 0);
                   planeFoerdern = true;
                }//if
            }//if
            else if (ObjTransportEinheit){
                planeein( Modellzeit(), ETafoerdern, ObjNummer, 0);
                planeFoerdern = true;
            }//else if
        }//else
    }//if
    if (!planeFoerdern)
        DarfIchAufDenQuerfoerderer();
    ichFoerderebereits = false;
}//Ende e_foerdern
//DarfIchAufDenQuerfoerderer()
/**
Auf den ersten Blick ist diese Funktion recht krausig.
Auf den zweiten aber auch. Ich glaube das wird bei weiteren Blicken
auch so bleiben.
Diese Funktion vergleicht die vorhandenen Querfoerderer mit den vorhandenen Kettengliedern,
und regelt das Zusammenspiel der Querfoerderer und dem Kettenfoerderer.
Die kleinste Aenderung an dieser Funktion fuehrt zu einem phantastischem Chaos.
Die Funktion regelt folgendes:

Befindet sich ein Kettenglied hinter (Transportrichtung) einem Querfoerderer und die Transporteinheit
ueberdeckt den Querfoerderer nicht mehr (auch Sicherhietsabstand) wird dieser freigeben.

Befindet sich ein Kettenglied auf einem Querfoerderer wird dieser belegt.
(Braucht man damit nicht mehrere Transporteinheiten auf diesen Platz gefahren werden)
Soll diese Transporteinheit auf dem Kettenglied auf diesen Querfoerderer, wird sie angemeldet
und das weiterfoerdern wird verhindert.

Befindet sich ein Kettenglied vor (Transportrichtung) einem Querfoerderer,
wird geprüft ob dieser Querfoerderer eine Meldung hat (Querfoerderer->sucheMeldung(this)),
ist eine Meldung vorhanden wird der Querfoerderer aktiviert und foerdern wird verhindert.
Befindet sich keine Meldung in der Liste wird der Platz fuer die Transporteinheit die
sich vor dem Querfoerderer auf einem Kettengliad befindet reserviert. Dies geschieht
damit eine Transporteinheit die von einem Nachbarbaustein des Querfoerderers aufgenómmen
werden soll, nicht in die auf dem Kettenfoerderer befindlichen Transporteinheiten knallt.

Am Ende der Funktion werden die Querfoerderer die zuvor nicht behandelt wurden, da in ihrer
Umgebung keine Kettenglieder vorhanden sind aktiviert.


*/
bool typKettenfoerderer::DarfIchAufDenQuerfoerderer(){
  setZustand(WARTEDP);
  bool ichDarf = true;
  
  LCursor<typKettenglied> c (ObjKettengliederListe);
  for (typKettenglied *k ; (k = c ()) != NULL; c++){
      bool habeMeldung = false;
      
      for(ObjMeineQuerfoerderer.First(); ObjMeineQuerfoerderer() != NULL; ObjMeineQuerfoerderer++){
          typQuerfoerderer* qf= ObjMeineQuerfoerderer.findKey(*ObjMeineQuerfoerderer());
          if(k->IstPlatz()== (unsigned)*ObjMeineQuerfoerderer() + anfangsSicherheit + ObjSicherheitsAbst){
             qf->KettenGliedIstFrei();
          }//if
          if((k->IstPlatz()==0 && k->IstPlatz()==(unsigned)*ObjMeineQuerfoerderer() - anfangsSicherheit)||
               k->IstPlatz()==(unsigned)*ObjMeineQuerfoerderer()- (anfangsSicherheit + ObjSicherheitsAbst) ||
               k->IstPlatz()==(unsigned)*ObjMeineQuerfoerderer()- (anfangsSicherheit)){
               	qf->KettenGliedIstBelegt();	 
               	//bool einenSchrittzuvorSchonAngemeldet = false;
               	if (!qf->rabgesenkt()){
                  ichDarf = false;
               }
               if (qf->sucheMeldung(this) && k->ObjTransportEinheit == NULL){
                   ichDarf = false;
                   habeMeldung = true;
               }//if
               else if (qf->TransportEinheit() == NULL && qf->abgabevonMeinKett == false){
                        if (k->hatAngemeldet == false){
                            qf->KettenGliedIstBelegt();
                        }//if
                }//else if
                else {
                     ichDarf = false;
                     if(!ObjMeldungen.isEmpty()){
                        planesofort(ETaktivieren, ObjNummer, ObjNummer);
                     }//if
                }//else
                
          }//if
          if((((unsigned)*ObjMeineQuerfoerderer()-(anfangsSicherheit+ObjSicherheitsAbst)) < k->IstPlatz())
	      &&(k->IstPlatz() <(unsigned)*ObjMeineQuerfoerderer() + anfangsSicherheit+ObjSicherheitsAbst)){
                if (!habeMeldung){
                   qf->KettenGliedIstBelegt();
                }//if
          }//if
          if (k->hatAngemeldet){
          	ichDarf/*nicht*/= false;		
          }
          if(k->IstPlatz()==(unsigned)*ObjMeineQuerfoerderer()){
             qf->KettenGliedIstBelegt();
             if (k->ObjTransportEinheit->nextBaustein()!=NULL){
                if(k->ObjTransportEinheit->nextBaustein()->Nummer()== qf->Nummer()&& qf->TransportEinheit()==NULL){
                      if (k->hatAngemeldet == false){
                          qf->abgabevonMeinKett = true;
                          if (k->IstPlatz() <=  anfangsSicherheit + ObjSicherheitsAbst)
                             	planesofort (ETeabgeben, k->getvonBaustein()->Nummer(), ObjNummer);
                          k->ObjTransportEinheit->Anmelden();
                          k->hatAngemeldet = true;
                      }//if
                      ichDarf/*nicht*/= false;
                }//if
             }//if
          }//if
          
        }//for
  }//for
  for(ObjMeineQuerfoerderer.First(); ObjMeineQuerfoerderer() != NULL; ObjMeineQuerfoerderer++){
    typQuerfoerderer* qf= ObjMeineQuerfoerderer.findKey(*ObjMeineQuerfoerderer());
    if(qf->sucheMeldung(this) && !ObjTransportEinheit && !qf->TransportEinheit()){
       ichDarf = false;
       
    }//if
    
  }//for

    return ichDarf;
}//Ende DarfIchAufDenQuerfoerderer()


// a_abgeben
/**
Wird von gibTransportEinheit (typMeldung* zM) aufgerufen.
Plant aktivieren von diesem Kettenfoerderer wenn Meldung vorhanden.
Sonst wird FOERDERN geplant.
*/
/*virtual*/ void typKettenfoerderer::a_abgeben () {
  setZustand (ABGEBEN);
  if (!ObjTransportEinheit && !ObjMeldungen.isEmpty()){
      planesofort (ETaktivieren, ObjNummer, ObjNummer);
  }//if
  else if (Strategie() != 1){
          planesofort (ETafoerdern, ObjNummer, 0);
  }//else if
}//Ende a_abgeben


//e_abgeben
/**
Wird vom Nachfolgebaustein aufgerufen, wenn dieser die Transporteinheit die er
von diesem Kettenfoerderer erhalten hat, vollstaendig aufgenommen hat.
Weiterin werden die Querfoerderer aktiviert(falls vorhanden), und
ganz wichtig, sollte ein Querfoerderer sích so weit hinten (Foerderrichtung) befinden
das kein Kettenglied ihn nach dem Ueberfahren in DarfIchAuf... freigeben kann, so
wird dieser hier freigegeben damit der Querf... wieder TransportE... aufnehmen kann.

*/
/*virtual*/ void typKettenfoerderer::e_abgeben () {
  bool letztenFreigeben = true;
  ObjFoerderGeschw = ObjNormalGeschw;
  LCursor<typKettenglied> c (ObjKettengliederListe);
  if (!ObjTransportEinheit && ObjKettengliederListe.isEmpty ()){
        setZustand (RUHE);
  }//if
  for(ObjMeineQuerfoerderer.First(); ObjMeineQuerfoerderer() != NULL; ObjMeineQuerfoerderer++){
    typQuerfoerderer* qf= ObjMeineQuerfoerderer.findKey(*ObjMeineQuerfoerderer());
    if (!qf->belegt &&(!ObjTransportEinheit && ObjKettengliederListe.isEmpty ())){
        DarfIchAufDenQuerfoerderer();
    }//if
  }//for
  /*for (typKettenglied *k ; (k = c ()) != NULL; c++){
      cout <<"Platz des Letzten = "<<platzDesLetztenQuerfoerderers<<" IstPlatz = "<<k->IstPlatz()<<endl;
      cout <<"ANzahl der Kettenglieder = "<<ObjAnzKettenglieder<<endl;
      if (k->IstPlatz() >= platzDesLetztenQuerfoerderers && k->IstPlatz() >= ObjAnzKettenglieder-(anfangsSicherheit+ObjSicherheitsAbst)){
            cout<<"Gebe frei "<<endl;
            letztenFreigeben = false;
        }
  }//for*/
  if (meinLetzterQuerfoerderer != NULL && letztenFreigeben == true)
      meinLetzterQuerfoerderer->KettenGliedIstFrei();
}//Ende e_abgeben


// gibTransportEinheit
/**
Loescht die Kettenglieder
*/
/*virtual*/ typTransportEinheit *typKettenfoerderer::gibTransportEinheit (typMeldung* zM) {
  LCursor<typKettenglied> c (ObjKettengliederListe);
  typBaustein* ausgang = zM->NachBaustein ();
  typTransportEinheit *zW = zM->TransportEinheit ();
  if (ausgang->Aufnahmezeit () > 0)
    ObjFoerderGeschw = Min (ObjNormalGeschw,
              zW->Laenge (ObjRichtung).len () / ausgang->Aufnahmezeit ().inMinutes ());
    for(typKettenglied *k ; (k = c ()) != NULL; c++){
        if (zW == k->ObjTransportEinheit) {
           ObjKettengliederListe.remove(*k);
        }//if
    }//for
    decBelegung ();
    planesofort (ETaabgeben, ObjNummer, ausgang->Nummer ());
    return zW;
}// Ende gibTransportEinheit

/*virtual*/ Vec3D typKettenfoerderer::UebernahmePos (const typBaustein&) const {
  return (ObjPalPlaetze [0]->Position ());
}

/*virtual*/ Vec3D typKettenfoerderer::UebergabePos (const typBaustein&) const {
  return (ObjPalPlaetze [1]->Position ());
}


typTransportEinheit* typKettenfoerderer::TransportEinheit () const {
  return  ObjTransportEinheit;
}

