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

#define _QUERFOER_CPP

/*** Windows headers ***/
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
//#include <winnt.h>
#endif /*WIN32*/


#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"
//--------------------------------------------------------
// Permanente Einheiten *** Quellcode:Querfoerderer ***
//---------------------------------------------------------

typQuerfoerderer::typQuerfoerderer(int n, int b)
: typBaustein(n,b),
  belegt                  (false),
  abgabevonMeinKett       (false),
  ObjFoerderRichtungKett  (0,0,0),
  ObjHubzeit              (0.0),
  MeinNaechsterBaustein   (NULL),
  ObjMeinKettenfoerderer  (NULL),
  KettenfoerdererBelegt   (false),
  UebergabePosAnKett      (0,0,0),
  abgesenkt               (true)
{};

typQuerfoerderer::~typQuerfoerderer(){
}

/*virtual*/void typQuerfoerderer::typTTPlesen (InputFile& file){
  SFXToken tok;
  tok.nextToken (file);
  ObjAufnahmezeit = SimTime (atof (tok ()) * SimTime::SecondsPerMinute ());
  tok.nextToken (file);
  ObjHubzeit      = SimTime (atof (tok ()) * SimTime::SecondsPerMinute ());
  file.jump (100); //EOL
}
//hasKapazitaet
/**
Liefert die Kapazitaet.
Diese Variante des Querfoerderers kann nur eine Transporteinheit aufnehmen
*/
/*virtual*/ bool typQuerfoerderer::hasKapazitaet (typTransportEinheit* ) const {
  if (ObjTransportEinheit != NULL || ObjPalPlaetze [0]->Buchung ())  return false;
  return true;
}//hasKapazitaet


//a_heben

void typQuerfoerderer::a_heben() {
     planeein (Modellzeit() + ObjHubzeit, ETeheben, ObjNummer, 0);
}//Ende a_heben
//e_heben
/**
Wenn die vorhandene Tranporteinheit von einem anderen Baustein als
von dem Kettenfoerderer der dieser Querfoerderer angehoert(ObjMeinKettenfoerderer) kommt,
und nicht auf ObjMeinKettenfoerderer soll wird diese hier aufgenommen.
Oder die Transp... kommt von ObjMeinKett... wird sie bei dem
NachfolgeBaustein angemeldet.
*/
void typQuerfoerderer::e_heben() {
     abgesenkt = false;
     if (ObjZielBaustein != ObjMeinKettenfoerderer){
         planesofort (ETaaufnehmen, ObjNummer, ObjNummer);
     }//if
     else{
          Vec3D* w = new Vec3D(0.0,0.0,0.0);
          ObjTransportEinheit->bewegen(*w);
          ObjTransportEinheit->Anmelden ();
          setZustand(WARTEN);
     }//else
}//e_heben

//a_abgeben
/*virtual*/void typQuerfoerderer::a_abgeben() {
   setZustand(ABGEBEN);
}//Ende a_abgeben
//e_abgeben
/**
Wird von Nachfolgebaustein aufgerufen.
Setzt Merker auf NULL.
Plant falls der Querf.. angehoben ist senken.
Damit die Transpo.. auf ObjMeinKett... nicht in diesen Querf.. knallen.
*/
/*virtual*/void typQuerfoerderer::e_abgeben() {
  if (!abgesenkt && MeinNaechsterBaustein != ObjMeinKettenfoerderer){
      ObjTransportEinheit = NULL;
      ObjZielBaustein = NULL;
      belegt = false;
      abgabevonMeinKett = false;
      a_senken();
  }//if
  else{
       setZustand(RUHE);
       ObjTransportEinheit = NULL;
       ObjZielBaustein = NULL;
       belegt = false;
       abgabevonMeinKett = false;
       planeein( Modellzeit(), ETafoerdern, ObjMeinKettenfoerderer->Nummer(), this->Nummer());
  }//else
  setZustand(RUHE);
}//e_abgeben
/**
   Strategie 1 zieht die Transp... auf den Mittelpunkt des Querf.
   Der Mittelpunkt muss aber nicht zwangslaeufig auf einem Kettenglied liegen.
   Dadurch kann es in der graphischen Darstellung zu Ueberschneidungen der Transp....
   kommen. Logisch ist dann zwar alles richtig sieht aber manchmal komisch aus.
   Darum habe ich die Moeglichkeit der Variation der Darstellung implementiert.
   Ausprobieren wie es am besten aussieht!!!!!!!!
   Strat.. 1 zieht auf den Mittelpunkt des Querf...
   Strat.. 0 zieht die vordere Kante (Transportrichtung) auf das zugehoerige Kettenglied
   Die Strat.. wird in PROJEKTNAME.tst gesetzt.
*/
/*virtual*/void typQuerfoerderer::a_aufnehmen() {
  belegt = true;
  abgabevonMeinKett = false;
  typMeldung *zM = holeMeldung ();
  ObjZielBaustein->gibTransportEinheit (zM);
  typPlatz *p (ObjPalPlaetze[0]);
  if (p->Buchung () != ObjTransportEinheit)
        sim_error ("FFSKett", "typQuerfoerderer::a_aufnehmen",
               "Transpueck ist nicht auf Platz gebucht", ObjNummer, FATAL);
  p->setBuchung (NULL);
  ObjBuchung--;
  if (abgesenkt){
     if (Strategie() == 1)
           aufnehmenEinleiten (ObjPalPlaetze[0]->Position(), ObjAufnahmezeit);
         else if (Strategie() == 0)
             aufnehmenEinleiten (SpezUebergabePosition ()-(ObjTransportEinheit->Laenge(FoerderRichtungKett().unit())*0.5), ObjAufnahmezeit);

  }//if
  else{
       Vec3D* w = new Vec3D(0.0,0.0,0.0);
       if (Strategie() == 1)
           aufnehmenEinleiten ((ObjPalPlaetze[0]->Position())+ *w, ObjAufnahmezeit);
        else
            aufnehmenEinleiten (SpezUebergabePosition ()-(ObjTransportEinheit->Laenge(FoerderRichtungKett().unit())*0.5), ObjAufnahmezeit);
  }//else
}//a_aufnehmen
//e_aufnehmen
/**
Wird von Nachfolgebaustein aufgrufen.
Kam die vorhandene Transp... von ObjMeinK... wird die Transp... angehoben damit sie
an den Nachfolgebaustein abgegeben werden kann.
Wenn die Transp auf ObjMeinK... abgegeben werden soll wird senken geplant, da der
Vorgaengerbaustein auf einem anderen Hoehenniveau liegt wie ObjMeinK... .
Ansonsten ist der Querf bereits abgesenkt und die Transp.. wird angemeldet.
*/
/*virtual*/void typQuerfoerderer::e_aufnehmen() {
    planesofort (ETeabgeben, ObjZielBaustein->Nummer(), ObjNummer);
    if (ObjZielBaustein == ObjMeinKettenfoerderer){
       planesofort(ETaheben,ObjNummer,ObjNummer);
    }//if
    else if (MeinNaechsterBaustein == ObjMeinKettenfoerderer){
            planesofort(ETasenken,ObjNummer,ObjNummer);
    }// else if
    else if ((MeinNaechsterBaustein != ObjMeinKettenfoerderer) && (ObjZielBaustein != ObjMeinKettenfoerderer)){
            ObjTransportEinheit->Anmelden ();
            setZustand(WARTEN);
    }//else if
}//e_aufnehmen

void typQuerfoerderer::a_senken() {
     planeein (Modellzeit() + ObjHubzeit, ETesenken, ObjNummer, ObjNummer);

}
//e_senken
/**
Meldet an wenn ObjMeinKett der naechste Baustein der Transp... ist.
Sonst wird ObjMeinK... zum foerdern veranlasst da sein Foerdervorgang ja
in DarfIchAuf... unterbrochen wurde.
*/
void typQuerfoerderer::e_senken() {
     abgesenkt = true;
     if (MeinNaechsterBaustein == ObjMeinKettenfoerderer){
        ObjTransportEinheit->Anmelden ();
        setZustand(WARTEN);
    }
    else{
         setZustand(RUHE);
         planeein( Modellzeit(), ETafoerdern, ObjMeinKettenfoerderer->Nummer(), this->Nummer());

    }
} // Ende e_senken



/*virtual*/void typQuerfoerderer::individuellAktivieren(typBaustein* vonWem){
   if((!ObjTransportEinheit && belegt == false && ObjMeinKettenfoerderer->Zustand() != FOERDERN && !ObjMeinKettenfoerderer->TransportEinheit()&& abgesenkt) ||
     (!ObjTransportEinheit && abgabevonMeinKett == true && ObjMeinKettenfoerderer->Zustand() != FOERDERN && vonWem == ObjMeinKettenfoerderer && abgesenkt)){
         typMeldung* zM = findeAusfuehrbareMeldung ();
         if (zM){
            KettenGliedIstBelegt();
            setZustand(AKTIVIERT);
            ObjTransportEinheit = zM->TransportEinheit ();
            this->ObjZielBaustein = zM->VonBaustein();
            MeinNaechsterBaustein = ObjTransportEinheit->nextBaustein();
            wartenaufnehmen (ObjTransportEinheit, ObjZielBaustein);
        }//if
    }//if
} // Ende Querf aktivieren

// findeAusfuehrbareMeldung()
/**
Holt die Meldungen aus der Meldungsliste.
Befindet sich eine Meldung von ObjMeinKett...
in der Liste wird diese herausgesucht, da die zugehoerige Transp sich ueber dem
Querf... befindet.
Wuerde in diesem Fall eine andere Meldung genommen, wuerde es zu einer Kollesion
der beiden Tranp... kommen.
*/
typMeldung* typQuerfoerderer::findeAusfuehrbareMeldung () {
  typTransportEinheit* zBuch = ObjPalPlaetze [0]->Buchung ();
  typTransportEinheit* zW = NULL;
  typTransportEinheit* transMerker = NULL;
  for (LCursor<typMeldung> c (ObjMeldungen); c; c++) {
        zW = c ()->TransportEinheit ();
        if(zW){
           if (c()->VonBaustein() == ObjMeinKettenfoerderer){
               transMerker =c()->TransportEinheit();
               break;
           }//if
           else if ((!zBuch) || (zW == zBuch)) {
                if (!zBuch && zW != ObjTransportEinheit){
                    transMerker =c()->TransportEinheit();
                }//if
           }//else if
        }//if
  }//for
  for (LCursor<typMeldung> h (ObjMeldungen); h; h++) {
      if(transMerker == h()->TransportEinheit()){
           transMerker->setZielPlatz (waehlePlatz (transMerker));
           return &(ObjMeldungen.prepend (*(ObjMeldungen.remove (h))));
      }
  }
  return NULL;
}//Ende findeAusfuehrbareMeldung()

/*virtual*/ typTransportEinheit *typQuerfoerderer::gibTransportEinheit (typMeldung* zM) {
    typBaustein* ausgang = zM->NachBaustein ();
    typTransportEinheit *zW = zM->TransportEinheit ();
    decBelegung ();
    planesofort (ETaabgeben, ObjNummer, ausgang->Nummer ());
    return zW;
}// Ende gibTransportEinheit

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


/*virtual*/ void typQuerfoerderer::wartenaufnehmen (typTransportEinheit* zW, typBaustein* vonWem) {
  if (vonWem->isUebergabeBereit (zW, this)) {
     setZustand (AKTIVIERT);
     if (vonWem == ObjMeinKettenfoerderer){
        a_aufnehmen();
     }
     else{
          planesofort (ETaheben, ObjNummer, ObjNummer);
     }//else
  }//if
  else {
       vonWem->UebergabeVorbereiten (zW);
  }
}//Ende wartenAufnehmen


void typQuerfoerderer::KettenGliedIstBelegt(){
     belegt = true;
}

void typQuerfoerderer::KettenGliedIstFrei(){
     belegt = false;
}

void typQuerfoerderer::setzeMeinenKettenfoerderer(typBaustein* mein){
    ObjMeinKettenfoerderer = (typKettenfoerderer* )mein;
}

bool typQuerfoerderer::sucheMeldung(const typBaustein* von){
     if (!ObjMeldungen.isEmpty() && !ObjTransportEinheit && belegt == false && ObjMeinKettenfoerderer->Zustand() != FOERDERN){
        planesofort(ETaktivieren, ObjNummer, von->Nummer());
        return true;
     }
     return false;
}

Vec3D typQuerfoerderer::Laenge (const Vec3D& globalDir) const {
  Vec3D v (globalDir);
  v = this->ObjGeometry.Len (ObjGeometry.DirToLocal (v));
  return ObjGeometry.DirToSpace (v);
}

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

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

void typQuerfoerderer::setzeSpezUebergabePosition (Vec3D vec){
     UebergabePosAnKett = vec;
}

Vec3D typQuerfoerderer::SpezUebergabePosition (){
      return UebergabePosAnKett;
}

void typQuerfoerderer::setzeObjFoerderRichtungKett(Vec3D vec){
     ObjFoerderRichtungKett = vec;
}

Vec3D typQuerfoerderer::FoerderRichtungKett(){
    return ObjFoerderRichtungKett;
}

bool typQuerfoerderer::rabgesenkt(){
     return abgesenkt;
}

