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

#include "MathDefs.h"
#include "List.h"
#include <iostream.h>

#define _TRANSP_CPP
#include "modell.h"
#include "transp.h"

#include "baustein.h"
#include "sfxprg.h"
#include "arbplan.h"
#include "route.h"

//---------------------------------------------------------
// Klasse typMeldung
//---------------------------------------------------------

typMeldung::typMeldung (typTransportEinheit *zTE)
 : ObjPrio       (-10),
   ObjTransportEinheit (zTE),
   ObjVonBst     (zTE->Vorgang ()->ZielBaustein ()),
   ObjNachBst    (ObjVonBst)
 { }

typMeldung::~typMeldung ()
 { }

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

typBaustein *typMeldung::VonBaustein () const {
  return ObjVonBst;
}

typBaustein *typMeldung::NachBaustein () const {
  return ObjNachBst;
}

void typMeldung::setVonBaustein (typBaustein* vonBst) {
  ObjVonBst = vonBst;
}

void typMeldung::setNachBaustein (typBaustein* nachBst) {
  ObjNachBst = nachBst;
}

int typMeldung::Prioritaet () const {
  return ObjPrio;
}

void typMeldung::incPrioritaet (int wert) {
  ObjPrio += wert;
}

void typMeldung::decPrioritaet (int wert) {
  ObjPrio -= wert;
}

void typMeldung::setPrioritaet (int wert) {
  ObjPrio = wert;
}

void typMeldung::PrioEingliedern (List<typMeldung>& lst) {
  LCursor<typMeldung> c (lst);
  for ( ; c; c++)
    if (ObjPrio > c ()->Prioritaet ()) break;
  lst.prepend (*this, c);
}


//---------------------------------------------------------
// Klasse typTransportEinheit
//---------------------------------------------------------
/*static*/ unsigned typTransportEinheit::ClassID = 1;

typTransportEinheit::typTransportEinheit (typArbeitsplan *zA)
 : ObjID            (ClassID++),
   ObjVariante      (zA->Palettenvariante ()),
   ObjUnterVariante (1),
   ObjProjektID     (0),

   ObjPrio       (0),

   ObjAnkunft    (Modellzeit ()),
   ObjFkAnkunft  (Modellzeit ()),

   ObjMeldung    (NULL),
   ObjAktPlatz   (NULL),
   ObjZielPlatz  (NULL),
   ObjBuchPlatz  (NULL),

   ObjPlatzKorrektur (-EZ),

   ObjArbeitsplan (zA),
   ObjVorgang    (zA->Vorgaenge ()),
   ObjBestand    (new typStlElement (*(ObjArbeitsplan->BestandsListe ().First ()))),

   ObjTransportRoute   (NULL),
   ObjStation    (),

   ObjGeometry   (),
   ObjWinkel     (),
   ObjDestroyFunc (NULL),

   ObjUData      (NULL) {

  typBaustein* zBst (ObjVorgang ()->ZielBaustein ());
  zBst->waehlePlatz (this);
  ObjMeldung = new typMeldung (this);

  TGBTempPattern* myTGBPattern = MySFXModel->TGBLibrary ()->findTemp (ObjVariante, ObjUnterVariante);

  GeoObject* geo = new GeoObject ();  //Speicherleck im GeoObject behoben Mark (13.03.03)
  geo->copyContents (*(myTGBPattern->MyGeometry ()));
  geo->setParent (ObjGeometry);
  geo->setSelectionToMum ();
  //ObjGeometry.copyContents (*(myTGBPattern->MyGeometry ()));
/*  ObjGeometry.insert (*(TGBPattern::buildText (Ustring (ObjArbeitsplan->Nummer ()),
                                               myTGBPattern->NumberHeight (),
                                               3.0, myTGBPattern->NumberPos ())));
*/

  ObjPlatzKorrektur = ObjGeometry.Center () + Vec3D (0.0, 0.0, Laenge (EZ).len () * -0.5);
  MySFXModel->insertTemporary (*this, ObjGeometry);
}


typTransportEinheit::typTransportEinheit (typArbeitsplan *zA, unsigned sollVorgang)
 : ObjID            (ClassID++),
   ObjVariante      (zA->Palettenvariante ()),
   ObjUnterVariante (1),

   ObjPrio       (0),

   ObjAnkunft    (Modellzeit ()),
   ObjFkAnkunft  (Modellzeit ()),

   ObjMeldung    (NULL),
   ObjAktPlatz   (NULL),
   ObjZielPlatz  (NULL),
   ObjBuchPlatz  (NULL),

   ObjPlatzKorrektur (-EZ),

   ObjArbeitsplan (zA),
   ObjVorgang    (zA->Vorgaenge ()),
   ObjBestand    (new typStlElement (*(ObjArbeitsplan->BestandsListe ().First ()))),

   ObjTransportRoute   (NULL),
   ObjStation    (),

   ObjGeometry   (),
   ObjWinkel     (),
   ObjDestroyFunc (NULL),

   ObjUData      (NULL) {
   
   //cout << " typTransportEinheit sollVorgang : " << sollVorgang << endl;
   schalteVorgang (sollVorgang);
   

  typBaustein* zBst (ObjVorgang ()->ZielBaustein ());
  zBst->waehlePlatz (this);
  ObjMeldung = new typMeldung (this);

  TGBTempPattern* myTGBPattern = MySFXModel->TGBLibrary ()->findTemp (ObjVariante, ObjUnterVariante);

  GeoObject* geo = new GeoObject ();  //Speicherleck im GeoObject behoben Mark (13.03.03)
  geo->copyContents (*(myTGBPattern->MyGeometry ()));
  geo->setParent (ObjGeometry);
  geo->setSelectionToMum ();
  //ObjGeometry.copyContents (*(myTGBPattern->MyGeometry ()));
/*  ObjGeometry.insert (*(TGBPattern::buildText (Ustring (ObjArbeitsplan->Nummer ()),
                                               myTGBPattern->NumberHeight (),
                                               3.0, myTGBPattern->NumberPos ())));
*/

  ObjPlatzKorrektur = ObjGeometry.Center () + Vec3D (0.0, 0.0, Laenge (EZ).len () * -0.5);
  MySFXModel->insertTemporary (*this, ObjGeometry);
}

typTransportEinheit::~typTransportEinheit () {
  stopBDE ();

  if (ObjMeldung)      delete ObjMeldung;
  if (ObjUData)        delete ObjUData;
  if (ObjDestroyFunc)  ObjDestroyFunc (&ObjGeometry);
  MySFXModel->removeTemporary (*this);
  delete ObjBestand;
}

void typTransportEinheit::setDestroyFunction (TransportEinheitDestroyFunction* destroyFunc) {
  ObjDestroyFunc = destroyFunc;
}

unsigned typTransportEinheit::ID () const {
  return ObjID;
}

void typTransportEinheit::SystemEintritt (const Vec3D& pos, const Angle& globWinkel) {
  drehen (globWinkel);
  positionieren (pos);
  ObjGeometry.setParent (*(MySFXModel->ModelSpace ()));

  startBDE ();
}

void typTransportEinheit::bewegen (const Vec3D& move) {
  Vec3D v (move);
  ObjGeometry.move (ObjGeometry.DirToLocal (v), 0);
}

void typTransportEinheit::positionieren  (const Vec3D& pos) {
  ObjGeometry.setPos (pos - ObjPlatzKorrektur, 0);
}

void typTransportEinheit::drehen (const Angle& ang) {
  ObjGeometry.DirToLocal (ObjPlatzKorrektur);
  ObjGeometry.rotate (EZ, ang, 0);
  ObjWinkel += ang;
  if (ObjWinkel < 0.0)  ObjWinkel += 360;
  else if (ObjWinkel == 360.0) ObjWinkel = Angle (0.0);
  ObjGeometry.DirToSpace (ObjPlatzKorrektur);
}

void typTransportEinheit::einblenden () {
  ObjGeometry.setParent (*(MySFXModel->ModelSpace ()));
}

void typTransportEinheit::ausblenden () {
  ObjGeometry.clearParent ();
}

void typTransportEinheit::ausrichten (const Angle& angToX) {
  ObjGeometry.DirToLocal (ObjPlatzKorrektur);
  ObjWinkel = angToX;
  if (ObjWinkel < 0.0)  ObjWinkel += 360;
  else if (ObjWinkel == 360.0) ObjWinkel = Angle (0.0);
  ObjGeometry.setXTo (Vec3D (ObjWinkel.cos (), ObjWinkel.sin (), 0.0), 0);
  ObjGeometry.DirToSpace (ObjPlatzKorrektur);
}

unsigned typTransportEinheit::ProjektID () {
  return ObjProjektID;
}

void typTransportEinheit::setProjektID (unsigned projektID) {
  ObjProjektID = projektID;
}

unsigned typTransportEinheit::Variante () {
  return ObjVariante;
}

void typTransportEinheit::setVariante (unsigned variante, unsigned unterVariante /*= 0*/) {
  ObjVariante = variante;
  ObjUnterVariante = unterVariante;
  TGBTempPattern* myTGBPattern = MySFXModel->TGBLibrary ()->findTemp (ObjVariante, ObjUnterVariante);


  GeoObject* geo = ObjGeometry.GObjArray ().First ();    // Matthias 16.03.02  Speicherleck!!!! Speicherleck im GeoObject behoben Mark (13.03.03)
  geo->copyContents (*(myTGBPattern->MyGeometry ()));
  geo->setParent (ObjGeometry);
  geo->setSelectionToMum ();

  //ObjGeometry.copyContents (*(myTGBPattern->MyGeometry ()));
  ObjPlatzKorrektur = ObjGeometry.Center () + Vec3D (0.0, 0.0, Laenge (EZ).len () * -0.5);
}

Vec3D typTransportEinheit::Position () const {
  return (ObjGeometry.Pos () + ObjPlatzKorrektur);
}

const Angle& typTransportEinheit::Winkel () const {
  return ObjWinkel;
}

Vec3D typTransportEinheit::Laenge (const Vec3D& globalDir) const {
  Vec3D v (globalDir);
  v = ObjGeometry.Len (ObjGeometry.DirToLocal (v));
  return ObjGeometry.DirToSpace (v);
}

bool typTransportEinheit::hatArbeitsplan (unsigned was, unsigned istv) const {
  if (ObjArbeitsplan->Nummer () != was)  return false;
  return (!istv || ObjVorgang ()->Nummer () == istv) ? true : false;
}

bool typTransportEinheit::hatArtikel (unsigned was, unsigned istv) const {
  if (ObjBestand->Artikel () != was)  return false;
  return (!istv || ObjVorgang ()->Nummer () == istv) ? true : false;
}

unsigned typTransportEinheit::Artikel () const {
  return ObjBestand->Artikel ();
}

unsigned typTransportEinheit::setArtikel (unsigned artikel) {
  return ObjBestand->setArtikel (artikel);
}

const double& typTransportEinheit::Menge () const {
  return ObjBestand->Menge ();
}

const double& typTransportEinheit::incMenge (const double& menge) {
  return ObjBestand->incMenge (menge);
}

const double& typTransportEinheit::decMenge (const double& menge) {
  return ObjBestand->decMenge (menge);
}

const double& typTransportEinheit::setMenge (const double& neuMenge) {
  return ObjBestand->setMenge (neuMenge);
}

int typTransportEinheit::Prioritaet () const {
  return ObjPrio;
}

int typTransportEinheit::setPrioritaet (int wert) {
  return ObjPrio = wert;
}

typVorgang *typTransportEinheit::Vorgang () const {
  return ObjVorgang ();
}

void typTransportEinheit::schalteVorgang (int sollVorgang /*= 0*/) {
  if (sollVorgang) {
    int aktVNr   = ObjVorgang ()->Nummer ();
    int startVNr = aktVNr;
    typBaustein* altZiel  = ObjVorgang ()->ZielBaustein ();
    if (aktVNr <= sollVorgang)
      while (aktVNr != sollVorgang) {
        ObjVorgang++;
        aktVNr = ObjVorgang ()->Nummer ();
        if (aktVNr > startVNr)
          altZiel->Avis ()->decIndIstAnzahl ();     // das geht nur bei vorwaerts!!!!!!
        altZiel = ObjVorgang ()->ZielBaustein ();
      }
    else
      while (aktVNr != sollVorgang) {
        ObjVorgang--;
        aktVNr = ObjVorgang ()->Nummer ();
        ObjVorgang ()->ZielBaustein ()->Avis ()->incIndIstAnzahl ();
//        if (aktVNr > startVNr)
//          altZiel->Avis ()->decIndIstAnzahl ();     // das geht nur bei vorwaerts!!!!!!
//        altZiel = ObjVorgang ()->ZielBaustein ();
      }
  }
  else
    ObjVorgang++; ObjVorgang ();
}

typBaustein* typTransportEinheit::Station () const {
  return ObjStation ();
}

typMeldung *typTransportEinheit::Meldung () const {
  return ObjMeldung;
}

typPlatz *typTransportEinheit::AktPlatz () const {
  return ObjAktPlatz;
}

typPlatz* typTransportEinheit::schaltePlatz () {
  ObjAktPlatz = ObjZielPlatz;
  ObjZielPlatz = ObjBuchPlatz;
  ObjBuchPlatz = NULL;
  return ObjAktPlatz;
}

typPlatz *typTransportEinheit::ZielPlatz () const {
  return ObjZielPlatz;
}

typPlatz* typTransportEinheit::setZielPlatz (typPlatz *zp) {
  return ObjZielPlatz = zp;
}

typPlatz *typTransportEinheit::BuchPlatz () const {
  return ObjBuchPlatz;
}

typPlatz* typTransportEinheit::setBuchPlatz (typPlatz *zb) {
  return ObjBuchPlatz = zb;
}

typBaustein* typTransportEinheit::Baustein () const {
  return ObjAktPlatz->Baustein ();
}

typBaustein* typTransportEinheit::nextBaustein () const {
  return ObjTransportRoute->nextBaustein (ObjStation ());
}

typTransportRoute *typTransportEinheit::TransportRoute () const {
  return ObjTransportRoute;
}

typArbeitsplan *typTransportEinheit::Arbeitsplan() const {
  return ObjArbeitsplan;
}

void typTransportEinheit::Anmelden () {
  schalteStation ();
  ObjMeldung->setPrioritaet (ObjAktPlatz->Baustein ()->Prioritaet ());
  typBaustein* zBst (ObjMeldung->NachBaustein ());
  zBst->empfangeMeldung (ObjMeldung);
}

void typTransportEinheit::startBDE () {
  ObjAnkunft = Modellzeit ();
  ObjArbeitsplan->startBDE ();
}

void typTransportEinheit::stopBDE () {
  ObjArbeitsplan->stopBDE (this);
}

const SimTime typTransportEinheit::Laufzeit () const {
  return (Modellzeit() - ObjAnkunft);
}

const SimTime typTransportEinheit::TransportRouteLaufzeit () const {
  return (Modellzeit() - ObjFkAnkunft);
}

UserData* typTransportEinheit::getUserData () const {
  return ObjUData;
}

void typTransportEinheit::setUserData (UserData* Data) {
  if (ObjUData)
    sim_error ("BAUSTEIN", "typTransportEinheit::setUserData",
             "TransportEinheit hat bereits UserData", ObjArbeitsplan->Nummer (),
	      FATAL);
  else ObjUData = Data;
}

UserData* typTransportEinheit::resetUserData () {
  UserData* tmp = ObjUData;
    ObjUData = NULL;
  return tmp;
}

void typTransportEinheit::schalteStation () {
  if (!ObjTransportRoute) {
    typBaustein* zielStation = (ObjVorgang ()->ZielBaustein ()->setZielBaustein (this));
    ObjTransportRoute = MySFXModel->findRoute (ObjAktPlatz->Baustein (), zielStation);
    ObjFkAnkunft = Modellzeit();
    ObjTransportRoute->startBDE ();
    ObjStation = ObjTransportRoute->Stationen ();
    ObjMeldung->setVonBaustein (ObjStation ());
    ObjStation++;
    ObjMeldung->setNachBaustein (ObjStation ());
  }
  else if (ObjStation () != ObjTransportRoute->Stationen ().Last ()) {
    ObjMeldung->setVonBaustein (ObjAktPlatz->Baustein ());
    ObjStation++;
    ObjMeldung->setNachBaustein (ObjStation ());
  }
  else {
    ObjTransportRoute->stopBDE (this);
    ObjTransportRoute = NULL;
    schalteStation ();
  }
}

GeoObject* typTransportEinheit::Geometry () {
	return &ObjGeometry;
}
