// Modelldatei fuer s1819r37 (AUDI) Juli 1999
// J. Bernhard
// Projekt Pressenstrasse

#include <stdio.h>
#include <iostream.h>
#include <fstream.h>

#ifdef WIN32
#include <strstrea.h>
#else
#include <strstream.h>
#endif

#include "sfxprg.h"
#include "Array.h"
#include "DynArray.h"
#include "MathDefs.h"

#include "Messung.h"


#ifdef WIN32
  #undef _impexp
  #define _impexp __declspec(dllexport)
#else
  #undef _impexp
  #define _impexp
#endif

//-----------------------------------------------------
//   globale Konstanten 
//   zur Manipulation des Modellverhaltens
//-----------------------------------------------------

// zur Manipulation der Losgroesse
const double LosMul = 1.0;

// zur Manipulation des WkzBestellzeitpunktes
bool MitBestellgrenze = true;

const SimTime BDEStartZeit (0.0);
const SimTime BDEIntervall (28800); // 8h !!

//-----------------------------------------------------
//   globale Konstanten
//-----------------------------------------------------

ofstream MyLog;
ofstream MyDlz;
ofstream MyBde;

// Werkzeugwechselzeit vor Stoessel!!!
// zum Bock fahren, abgeben,
// zum naechsten Bock fahren, aufnehmen,
// zum Stoessel fahren, abgeben!!
const SimTime  WkzAusEinfahrtZeit = 447; // 7.45 Minuten!!!

const unsigned WerkzeugVariante = 20;
const unsigned BlechVariante    = 21;

const SimTime  SonderAnfahrtDauer = 74;  // 1.23 Minuten!!!
const unsigned SonderfahrtKurz = 100; // steht in der Artikelnr
const unsigned SonderfahrtLang = 101;

//-----------------------------------------------------
//   Klassen fuer Baustein Attribute
//-----------------------------------------------------

class Steuerer : public UserData {
  public:
    Steuerer (unsigned steuerBst)
     : SteuerBst (steuerBst), HasToWait (false) { };
    virtual ~Steuerer     () { };

    unsigned SteuerBst;
    bool HasToWait;
};

class SonderSenkenData : public UserData {
  public:
    SonderSenkenData (unsigned kran)
      : MeinKran (kran) { };
    virtual ~SonderSenkenData     () { };

    unsigned MeinKran;
};

class KranData : public UserData {
  public:
    KranData () : Sonderfahrt (), HasToReset (false) { };
    virtual ~KranData () { };

    Geschichte Sonderfahrt;
    bool HasToReset;
};

class PressenData : public Steuerer {
  public:
    PressenData (unsigned steuerBst, unsigned stoesselBst)
     : Steuerer (steuerBst), StoesselBst (stoesselBst) {HasToWait = true;};
    ~PressenData () { };

    unsigned StoesselBst;
};

class StoesselData : public Steuerer {
  public:
    StoesselData (unsigned steuerBst)
     : Steuerer (steuerBst) { };
    ~StoesselData () { };
};

class AblageData : public Steuerer {
  public:
    AblageData (unsigned steuerBst) 
     : Steuerer (steuerBst), AnzahlBestellungen (0), ErstesBlechpaket (true) { };
    ~AblageData () { };
    
    unsigned AnzahlBestellungen;
    bool ErstesBlechpaket;
};

class LinienSteuerData : public UserData {
  public:
    LinienSteuerData (unsigned linienNr, unsigned linienPartner, unsigned wkzQuelle,
                      unsigned wkzLager, unsigned blechQuelle,   unsigned ablage,
                      unsigned vereinzeler);

    ~LinienSteuerData ();

    unsigned LinienNummer;
    unsigned AktAuftrag;
    unsigned LosZaehler;
    unsigned LosGroesse;
    unsigned WerkzeugReinZaehler;
    unsigned WerkzeugRausZaehler;
    unsigned WerkzeugBestellgrenze;

    unsigned LinienPartner;
    unsigned WerkzeugQuelle;
    unsigned WerkzeugLager;
    unsigned BlechQuelle;
    unsigned Ablage;
    unsigned Vereinzeler;

    bool WerkzeugWechsel;

    Array<unsigned>    Paketanzahl;
    DynArray<unsigned> Pressen;
    DynArray<unsigned> Stoessel; // Werkzeughalter!!!

    SimTime WechselZeitMerker;
    SimTime StartZeit;

    Register   Wartezeit;

    Geschichte Stillstand;
    Geschichte WkzWechsel;
    Geschichte Betrieb;
};

LinienSteuerData::LinienSteuerData (unsigned linienNr,    unsigned linienPartner, 
                                    unsigned wkzQuelle,   unsigned wkzLager,
                                    unsigned blechQuelle, unsigned ablage,
                                    unsigned vereinzeler)
 : LinienNummer          (linienNr),
   AktAuftrag            (0),
   LosGroesse            (0),
   LosZaehler            (0),
   WerkzeugReinZaehler   (0),
   WerkzeugRausZaehler   (0),
   WerkzeugBestellgrenze (0),

   LinienPartner    (linienPartner),
   WerkzeugQuelle   (wkzQuelle),
   WerkzeugLager    (wkzLager),
   BlechQuelle      (blechQuelle),
   Ablage           (ablage),
   Vereinzeler      (vereinzeler),

   WerkzeugWechsel  (false),

   Paketanzahl      (6),
   Pressen          (6),
   Stoessel         (6),

   WechselZeitMerker(),
   StartZeit        (),
   Wartezeit        (),
   Stillstand       (),
   WkzWechsel       (),
   Betrieb          () {
  Stillstand.erfassen (100.0);
}

LinienSteuerData::~LinienSteuerData () {
  for (unsigned i = Paketanzahl.Count (); i > 0; i--)
    delete Paketanzahl.remove (i);
  while (Pressen.Last ())  delete Pressen.removeLast ();
  while (Stoessel.Last ()) delete Stoessel.removeLast ();
}

//-----------------------------------------------------
//   Initialisierung
//-----------------------------------------------------

void _impexp init_prog () {
  unsigned i;

//  MyLog.open ("/Sfx3D/Modelle/audi/strasse2/audi.log", ios::out | ios::trunc);
//  MyDlz.open ("/Sfx3D/Modelle/audi/strasse2/audi.dlz", ios::out | ios::trunc);
//  MyBde.open ("/Sfx3D/Modelle/audi/strasse2/audi.bde", ios::out | ios::trunc);

// Linie 19
  LinienSteuerData* lsd = new LinienSteuerData (19, 112, 88, 22, 87, 35, 57);
  for (i = 55; i >= 40; i -= 3)  // richtige logische Reihenfolge!!!
    lsd->Pressen.append (*(new unsigned int (i)));
  for (i = 56; i >= 41; i -= 3)
    lsd->Stoessel.append (*(new unsigned int (i)));
  setBstUserData (2, lsd);

  if (MitBestellgrenze)
    lsd->WerkzeugBestellgrenze = 101;
  else
    lsd->WerkzeugBestellgrenze = 0;

  // Einschleuszeit + ideale Anfahrtzeit in Sekunden!!
  lsd->WechselZeitMerker = 1462.45;

  for (unsigned i = 1; i <= 5; i++)
    lsd->Paketanzahl[i] = new unsigned ((Round(7 * LosMul) >= 1) ? Round(7 * LosMul) : 1);
  lsd->Paketanzahl[6] = new unsigned ((Round(14 * LosMul) >= 1) ? Round(14 * LosMul) : 1);
  lsd->Paketanzahl[7] = new unsigned ((Round(5 * LosMul) >= 1) ? Round(5 * LosMul) : 1);
  lsd->Paketanzahl[8] = new unsigned ((Round(6 * LosMul) >= 1) ? Round(6 * LosMul) : 1);
  lsd->Paketanzahl[9] = new unsigned ((Round(6 * LosMul) >= 1) ? Round(6 * LosMul) : 1);
  lsd->Paketanzahl[10] = new unsigned (1);
  for (lsd->Stoessel.First (); lsd->Stoessel (); lsd->Stoessel++)
    setBstUserData (*(lsd->Stoessel ()), new StoesselData (2));
  for (lsd->Pressen.First (), lsd->Stoessel.First (); lsd->Pressen (); lsd->Pressen++, lsd->Stoessel++)
    setBstUserData (*(lsd->Pressen ()), new PressenData (2, *(lsd->Stoessel ())));

  //for (unsigned i = 0; i < 6; i++)
  //  bestelleArbeitsplan ((lsd->LinienNummer * 10000) + 1102 + i, lsd->WerkzeugQuelle, 1);

  setBstUserData (lsd->Ablage, new AblageData (2));
  setBstUserData (1, new Steuerer (2)); // AuftragsQuelle


// Linie 18
  lsd = new LinienSteuerData (18, 2, 88, 22, 87, 86, 108);
  for (i = 106; i >= 91; i -= 3)  // richtige logische Reihenfolge!!!
    lsd->Pressen.append (*(new unsigned int (i)));
  for (i = 107; i >= 92; i -= 3)
    lsd->Stoessel.append (*(new unsigned int (i)));
  setBstUserData (112, lsd);


  if (MitBestellgrenze)
    lsd->WerkzeugBestellgrenze = 90;
  else
    lsd->WerkzeugBestellgrenze = 0;
  // Einschleuszeit + ideale Anfahrtzeit in Sekunden!!
  lsd->WechselZeitMerker = 3242.95;

  lsd->Paketanzahl[1] = new unsigned ((Round(10 * LosMul) >= 1) ? Round(10 * LosMul) : 1);
  lsd->Paketanzahl[2] = new unsigned ((Round(30 * LosMul) >= 1) ? Round(30 * LosMul) : 1);
  lsd->Paketanzahl[3] = new unsigned ((Round(22 * LosMul) >= 1) ? Round(22 * LosMul) : 1);
  lsd->Paketanzahl[4] = new unsigned ((Round(9 * LosMul) >= 1) ? Round(9 * LosMul) : 1);
  lsd->Paketanzahl[5] = new unsigned ((Round(8 * LosMul) >= 1) ? Round(8 * LosMul) : 1);

  for (lsd->Stoessel.First (); lsd->Stoessel (); lsd->Stoessel++)
    setBstUserData (*(lsd->Stoessel ()), new StoesselData (112));
  for (lsd->Pressen.First (), lsd->Stoessel.First (); lsd->Pressen (); lsd->Pressen++, lsd->Stoessel++)
    setBstUserData (*(lsd->Pressen ()), new PressenData (112, *(lsd->Stoessel ())));

  //for (unsigned i = 0; i < 6; i++)
  //  bestelleArbeitsplan ((lsd->LinienNummer * 10000) + 1102 + i, lsd->WerkzeugQuelle, 1);
  
  setBstUserData (lsd->Ablage, new AblageData (112));
  setBstUserData (111, new Steuerer (112)); // AuftragsQuelle

// Linie 17
  lsd = new LinienSteuerData (17, 187, 163, 32, 162, 33, 134);
  for (i = 132; i >= 120; i -= 3)  // richtige logische Reihenfolge!!!
    lsd->Pressen.append (*(new unsigned int (i)));
  lsd->Pressen.append (*(new unsigned int (37)));
  for (i = 133; i >= 121; i -= 3)
    lsd->Stoessel.append (*(new unsigned int (i)));
  lsd->Stoessel.append (*(new unsigned int (58)));
  setBstUserData (16, lsd);

  if (MitBestellgrenze)
    lsd->WerkzeugBestellgrenze = 152;
  else
    lsd->WerkzeugBestellgrenze = 0;
  // Einschleuszeit + ideale Anfahrtzeit in Sekunden!!
  lsd->WechselZeitMerker = 3562.45;

  lsd->Paketanzahl[1] = new unsigned ((Round(6 * LosMul) >= 1) ? Round(6 * LosMul) : 1);
  lsd->Paketanzahl[2] = new unsigned ((Round(5 * LosMul) >= 1) ? Round(5 * LosMul) : 1);
  lsd->Paketanzahl[3] = new unsigned ((Round(3 * LosMul) >= 1) ? Round(3 * LosMul) : 1);
  lsd->Paketanzahl[4] = new unsigned ((Round(2 * LosMul) >= 1) ? Round(2 * LosMul) : 1);
  lsd->Paketanzahl[5] = new unsigned ((Round(8 * LosMul) >= 1) ? Round(8 * LosMul) : 1);
  lsd->Paketanzahl[6] = new unsigned ((Round(7 * LosMul) >= 1) ? Round(7 * LosMul) : 1);
  lsd->Paketanzahl[7] = new unsigned ((Round(7 * LosMul) >= 1) ? Round(7 * LosMul) : 1);
  lsd->Paketanzahl[8] = new unsigned ((Round(10 * LosMul) >= 1) ? Round(10 * LosMul) : 1);
  lsd->Paketanzahl[9] = new unsigned ((Round(11 * LosMul) >= 1) ? Round(11 * LosMul) : 1);

  for (lsd->Stoessel.First (); lsd->Stoessel (); lsd->Stoessel++)
    setBstUserData (*(lsd->Stoessel ()), new StoesselData (16));
  for (lsd->Pressen.First (), lsd->Stoessel.First (); lsd->Pressen (); lsd->Pressen++, lsd->Stoessel++)
    setBstUserData (*(lsd->Pressen ()), new PressenData (16, *(lsd->Stoessel ())));

  //for (unsigned i = 0; i < 6; i++)
  //  bestelleArbeitsplan ((lsd->LinienNummer * 10000) + 1102 + i, lsd->WerkzeugQuelle, 1);
  
  setBstUserData (lsd->Ablage, new AblageData (16));
  setBstUserData ( 15, new Steuerer (16)); // AuftragsQuelle

// Linie 16
  lsd = new LinienSteuerData (16, 16, 163, 32, 162, 161, 183);
  for (i = 181; i >= 166; i -= 3)  // richtige logische Reihenfolge!!!
    lsd->Pressen.append (*(new unsigned int (i)));
  for (i = 182; i >= 167; i -= 3)
    lsd->Stoessel.append (*(new unsigned int (i)));
  setBstUserData (187, lsd);

  if (MitBestellgrenze)
    lsd->WerkzeugBestellgrenze = 107;
  else
    lsd->WerkzeugBestellgrenze = 0;
  // Einschleuszeit + ideale Anfahrtzeit in Sekunden!!
  lsd->WechselZeitMerker = 1742.95;

  lsd->Paketanzahl[1] = new unsigned ((Round(4 * LosMul) >= 1) ? Round(4 * LosMul) : 1);
  lsd->Paketanzahl[2] = new unsigned ((Round(23 * LosMul) >= 1) ? Round(23 * LosMul) : 1);
  lsd->Paketanzahl[3] = new unsigned ((Round(2 * LosMul) >= 1) ? Round(2 * LosMul) : 1);
  lsd->Paketanzahl[4] = new unsigned ((Round(2 * LosMul) >= 1) ? Round(2 * LosMul) : 1);
  lsd->Paketanzahl[5] = new unsigned ((Round(21 * LosMul) >= 1) ? Round(21 * LosMul) : 1);
  lsd->Paketanzahl[6] = new unsigned ((Round(8 * LosMul) >= 1) ? Round(8 * LosMul) : 1);

  for (lsd->Stoessel.First (); lsd->Stoessel (); lsd->Stoessel++)
    setBstUserData (*(lsd->Stoessel ()), new StoesselData (187));
  for (lsd->Pressen.First (), lsd->Stoessel.First (); lsd->Pressen (); lsd->Pressen++, lsd->Stoessel++)
    setBstUserData (*(lsd->Pressen ()), new PressenData (187, *(lsd->Stoessel ())));

  //for (unsigned i = 0; i < 6; i++)
  //  bestelleArbeitsplan ((lsd->LinienNummer * 10000) + 1102 + i, lsd->WerkzeugQuelle, 1);
  
  setBstUserData (lsd->Ablage, new AblageData (187));
  setBstUserData (186, new Steuerer (187)); // AuftragsQuelle

// anderes
  setBstUserData (196, new SonderSenkenData ( 60)); //Linie 18/19
  setBstUserData (198, new SonderSenkenData (136)); //Linie 16/17

  installEvent (ETaaufnehmen, 196, "ETaaufnehmen_SonderSenke");
  installEvent (ETaaufnehmen, 198, "ETaaufnehmen_SonderSenke");

  setBstUserData ( 60, new KranData ());
  setBstUserData (136, new KranData ());

  installEvent (ETeaufnehmen,  60, "ETeaufnehmen_Kran");
  installEvent (ETeaufnehmen, 136, "ETeaufnehmen_Kran");
  installEvent (ETeabgeben,    60, "ETeabgeben_Kran");
  installEvent (ETeabgeben,   136, "ETeabgeben_Kran");

  installEvent (ETearbeiten,   1, "ETearbeiten_AuftragsQuelle");
  installEvent (ETearbeiten, 111, "ETearbeiten_AuftragsQuelle");
  installEvent (ETearbeiten,  15, "ETearbeiten_AuftragsQuelle");
  installEvent (ETearbeiten, 186, "ETearbeiten_AuftragsQuelle");

  planeEin (BDEStartZeit, ETprogramm, 0, 1001);

//  planeEin (3959, ETatrace, 0, 0, 0);
//  planeEin (278, ETatrace, 0, 0, 0);

}

//-----------------------------------------------------
//   Exit
//-----------------------------------------------------

void _impexp exit_prog () {
/*
  LinienSteuerData* steuererData = (LinienSteuerData*) BstUserData (187);
  MyBde << "### Wartezeit: ";
  MyBde << " Linie16 ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Min () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Max () << endl;

  steuererData = (LinienSteuerData*) BstUserData (16);
  MyBde << "### Wartezeit: ";
  MyBde << " Linie17 ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Min () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Max () << endl;

  steuererData = (LinienSteuerData*) BstUserData (112);
  MyBde << "### Wartezeit: ";
  MyBde << " Linie18 ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Min () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Max () << endl;

  steuererData = (LinienSteuerData*) BstUserData (2);
  MyBde << "### Wartezeit: ";
  MyBde << " Linie19 ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Min () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Wartezeit.Max () << endl;

  MyLog.close ();
  MyDlz.close ();
  MyBde.close ();
*/
}

//-----------------------------------------------------
//   Funktionen der Bausteine
//-----------------------------------------------------

//-----------------------------------------------------
//  Event auf AuftragsQuelle
//-----------------------------------------------------

void _impexp ETearbeiten_AuftragsQuelle () {
  Steuerer* myData = (Steuerer*) BstUserData (This);
  LinienSteuerData* steuererData = (LinienSteuerData*) BstUserData (myData->SteuerBst);
  unsigned aktArtikel = (steuererData->LinienNummer * 10000) + 1102;

  if (steuererData->LosZaehler > steuererData->WerkzeugBestellgrenze) {

/*    if (!AnzArtikelBelegung (steuererData->WerkzeugLager, aktArtikel)) {
      for (unsigned i = 0; i < 6; i++)
        bestelleArbeitsplan (aktArtikel + i, steuererData->WerkzeugQuelle);
    }*/
    while (steuererData->LosZaehler > steuererData->WerkzeugBestellgrenze) warten ();
    while (((LinienSteuerData*) BstUserData (steuererData->LinienPartner))->WerkzeugWechsel) warten ();
    steuererData->WerkzeugWechsel = true;
//    bestelleArtikel (aktArtikel, steuererData->WerkzeugLager, 6, 0, 3); 
    for (unsigned i = 0; i < 6; i++)
      bestelleArbeitsplan (aktArtikel + i, steuererData->WerkzeugQuelle, 1, 0, 3);
  }
  else {
    while (((LinienSteuerData*) BstUserData (steuererData->LinienPartner))->WerkzeugWechsel) warten ();
    steuererData->WerkzeugWechsel = true;
    if (AnzArtikelBelegung (steuererData->WerkzeugLager, aktArtikel)) {
      bestelleArtikel (aktArtikel, steuererData->WerkzeugLager, 6, 0, 3);
    }
    else {
      for (unsigned i = 0; i < 6; i++)
        bestelleArbeitsplan (aktArtikel + i, steuererData->WerkzeugQuelle, 1, 0, 3);
    }
  }
}

//-----------------------------------------------------
//  LinienSteuerBaustein
//-----------------------------------------------------

void _impexp prog_100 () {
  LinienSteuerData* myData = (LinienSteuerData*) BstUserData (This);
  AblageData* ablageData = (AblageData*) BstUserData (myData->Ablage);

  aufnehmen ();
  myData->Stillstand.erfassen (0.0);
  myData->WkzWechsel.erfassen (100.0);

  myData->AktAuftrag = ArtikelNr (This);

  while (myData->WerkzeugReinZaehler < 5) warten ();

  unsigned what = (myData->LinienNummer * 10000);
  if (myData->AktAuftrag < 10)
    what += myData->AktAuftrag * 1000;

  bestelleArbeitsplan (what, myData->BlechQuelle, 1);
  ablageData->AnzahlBestellungen = *(myData->Paketanzahl [myData->AktAuftrag]);
  ablageData->ErstesBlechpaket = true;
  myData->LosZaehler = 1; // Dummy, um spaeter in der while-Schleife zu bleiben!!!

  while (myData->WerkzeugReinZaehler < 6) warten ();
  myData->WerkzeugReinZaehler = 0;
  myData->WerkzeugWechsel = false;
  aktivieren (This - 1); // Meine Quelle oder Neckermann?;-)
  aktivieren (myData->LinienPartner - 1); // Auftragsquelle!!!
  aktivieren (myData->LinienPartner);

  arbeiten ();
  while (myData->LosZaehler > 0) warten ();
  myData->Betrieb.erfassen (0.0);
  myData->WkzWechsel.erfassen (100.0);
/*
  MyDlz << "### DLZ Linie";
  MyDlz.width (2);
  MyDlz << myData->LinienNummer << ": " <<  ArbeitsplanNr (This) << " ";
  MyDlz.width (12);
  MyDlz << TEStartzeit (This).inMinutes () << " ";
  MyDlz.width (12);
  MyDlz << (myData->StartZeit - TEStartzeit (This)).inMinutes () << " ";
  MyDlz.width (12);
  MyDlz << (Modellzeit () - myData->StartZeit).inMinutes () << " ";
  MyDlz.width (12);
  MyDlz << MinDurchlaufzeit (what + 100).inMinutes ();
  MyDlz.width (12);
  MyDlz << MitDurchlaufzeit (what + 100).inMinutes ();
  MyDlz.width (12);
  MyDlz << MaxDurchlaufzeit (what + 100).inMinutes ();
  MyDlz.width (6);
  MyDlz << myData->LosGroesse << endl;
*/
  while (((LinienSteuerData*) BstUserData (myData->LinienPartner))->WerkzeugWechsel) warten ();

  myData->WerkzeugWechsel = true;
  for (myData->Stoessel.First (); myData->Stoessel (); myData->Stoessel++) {
    ((StoesselData*) BstUserData (*(myData->Stoessel ())))->HasToWait = false;
    aktivieren (*(myData->Stoessel ()));
  }
  while (myData->WerkzeugRausZaehler < 6) warten ();
  myData->WerkzeugRausZaehler = 0;
  myData->WerkzeugWechsel = false;
  aktivieren (This - 1); // Meine Quelle oder Neckermann?;-))
  aktivieren (myData->LinienPartner - 1); // Auftragsquelle!!!
  aktivieren (myData->LinienPartner);

  myData->WkzWechsel.erfassen (0.0);
  myData->Stillstand.erfassen (100.0);
  abgeben ();
}

//-----------------------------------------------------
//  PressenProgramm auf erster Presse fuer ProbeBlech
//-----------------------------------------------------

void _impexp prog_200 () {
  PressenData* firstPressData = (PressenData*) BstUserData (This);
  LinienSteuerData* steuererData   = (LinienSteuerData*) BstUserData (firstPressData->SteuerBst);

  while (firstPressData->HasToWait == true) warten ();
  firstPressData->HasToWait = true;
  //MyLog.precision (10);
  //MyLog << This << "will aufnehmen:  " << Modellzeit ().inMinutes () << endl;
  aufnehmen ();
  //MyLog << This << "hat aufgenommenn:" << Modellzeit ().inMinutes () << endl;

  steuererData->StartZeit = Modellzeit ();
  steuererData->WkzWechsel.erfassen (0.0);
  steuererData->Betrieb.erfassen (100.0);
  setTEVariante (firstPressData->StoesselBst, WerkzeugVariante, 2);
  arbeiten ();
  setTEVariante (This, BlechVariante, 2);
  setTEVariante (firstPressData->StoesselBst, WerkzeugVariante, 1);
  //MyLog << This << "will abgeben:    " << Modellzeit ().inMinutes () << endl;
  abgeben ();
  while (firstPressData->HasToWait == true) warten ();
  firstPressData->HasToWait = true;
}

//-----------------------------------------------------
//  PressenProgramm auf letzter Presse fuer ProbeBlech
//-----------------------------------------------------

void _impexp prog_201 () {
  PressenData*      lastPressData  = (PressenData*)      BstUserData (This);
  LinienSteuerData* steuererData   = (LinienSteuerData*) BstUserData (lastPressData->SteuerBst);
  PressenData*      firstPressData = (PressenData*)      BstUserData (*(steuererData->Pressen.First ()));
  //MyLog << This << "will aufnehmen:  " << Modellzeit ().inMinutes () << endl;
  aufnehmen ();
  //MyLog << This << "hat aufgenommenn:" << Modellzeit ().inMinutes () << endl;
  setTEVariante (lastPressData->StoesselBst, WerkzeugVariante, 2);
  arbeiten ();
  setTEVariante (lastPressData->StoesselBst, WerkzeugVariante, 1);
  setTEMenge (lastPressData->SteuerBst, --(steuererData->LosZaehler));
  firstPressData->HasToWait = false;
  aktivieren (*(steuererData->Pressen.First ()));
  //MyLog << This << "will abgeben:    " << Modellzeit ().inMinutes () << endl;
  abgeben ();
}

//-----------------------------------------------------
//  PressenProgramm auf erster Presse
//-----------------------------------------------------

void _impexp prog_212 () {
  PressenData* firstPressData = (PressenData*)      BstUserData (This);
  //MyLog << This << "will aufnehmen:  " << Modellzeit ().inMinutes () << endl;
  aufnehmen ();
  //MyLog << This << "hat aufgenommenn:" << Modellzeit ().inMinutes () << endl;
  setTEVariante (firstPressData->StoesselBst, WerkzeugVariante, 2);
  arbeiten ();
  setTEVariante (This, BlechVariante, 2);
  setTEVariante (firstPressData->StoesselBst, WerkzeugVariante, 1);
  //MyLog << This << "will abgeben:    " << Modellzeit ().inMinutes () << endl;
  abgeben ();
}

//-----------------------------------------------------
//  allgemeines PressenProgramm 
//-----------------------------------------------------

void _impexp prog_210 () {
  PressenData* myPressData = (PressenData*)      BstUserData (This);
  //MyLog << This << "will aufnehmen:  " << Modellzeit ().inMinutes () << endl;
  aufnehmen ();
  //MyLog << This << "hat aufgenommenn:" << Modellzeit ().inMinutes () << endl;
  setTEVariante (myPressData->StoesselBst, WerkzeugVariante, 2);
  arbeiten ();
  setTEVariante (myPressData->StoesselBst, WerkzeugVariante, 1);
  //MyLog << This << "will abgeben:    " << Modellzeit ().inMinutes () << endl;
  abgeben ();
}

//-----------------------------------------------------
//  PressenProgramm auf letzter Presse fuer NormalBlech
//-----------------------------------------------------

void _impexp prog_211 () {
  PressenData*      lastPressData = (PressenData*)      BstUserData (This);
  LinienSteuerData* steuererData  = (LinienSteuerData*) BstUserData (lastPressData->SteuerBst);
  //MyLog << This << "will aufnehmen:  " << Modellzeit ().inMinutes () << endl;
  aufnehmen ();
  //MyLog << This << "hat aufgenommenn:" << Modellzeit ().inMinutes () << endl;
  setTEVariante (lastPressData->StoesselBst, WerkzeugVariante, 2);
  arbeiten ();
  setTEVariante (lastPressData->StoesselBst, WerkzeugVariante, 1);
  setTEMenge (lastPressData->SteuerBst, --(steuererData->LosZaehler));
  aktivieren (lastPressData->SteuerBst - 1); // Quelle!!!
  aktivieren (lastPressData->SteuerBst);
  //MyLog << This << "will abgeben:    " << Modellzeit ().inMinutes () << endl;
  abgeben ();
}

//-----------------------------------------------------
//  StoesselProgramm 
//-----------------------------------------------------

void _impexp prog_300 () {
  StoesselData*     myStoesselData = (StoesselData*)     BstUserData (This);
  LinienSteuerData* steuererData   = (LinienSteuerData*) BstUserData (myStoesselData->SteuerBst);
  PressenData* firstPressData = (PressenData*) BstUserData (*(steuererData->Pressen.First ()));
  bool tretePresse = false;

  aufnehmen ();
  if ((++(steuererData->WerkzeugReinZaehler)) == 6) {
    //MyLog << "Wechsel fertig: " << Modellzeit ().inSeconds () << endl;
    steuererData->Wartezeit.erfassen ((Modellzeit () - steuererData->WechselZeitMerker).inMinutes ());
    tretePresse = true;
  }
  aktivieren (myStoesselData->SteuerBst);

  arbeiten ();                            // Werkzeug einbauen

  if (tretePresse) {
    firstPressData->HasToWait = false;
    aktivieren (*(steuererData->Pressen.First ()));
  }

  myStoesselData->HasToWait = true;
  while (myStoesselData->HasToWait == true) warten ();

  schlafen (Vorgangszeit (This));        // Werkzeug ausbauen
  setTEPrioritaet (This, 0);
  
  abgeben ();

  while (Belegung (This)) warten ();
  if (++(steuererData->WerkzeugRausZaehler) == 6) {
    steuererData->WechselZeitMerker = Modellzeit () + WkzAusEinfahrtZeit;
    aktivieren (myStoesselData->SteuerBst);
  }
}

//-----------------------------------------------------
//  AblageProgramm
//-----------------------------------------------------

void _impexp prog_350 () {
  AblageData* myData = (AblageData*) BstUserData (This);
  LinienSteuerData* steuererData = (LinienSteuerData*) BstUserData (myData->SteuerBst);
  int arbPlan;

  aufnehmen ();

  arbPlan = ArbeitsplanNr (This);
  if (myData->ErstesBlechpaket) {
    myData->ErstesBlechpaket = false;
    steuererData->LosZaehler = myData->AnzahlBestellungen * TEMenge (This);
    steuererData->LosGroesse = steuererData->LosZaehler;
    setTEMenge (myData->SteuerBst, steuererData->LosZaehler);
    bestelleArbeitsplan (arbPlan + 101, steuererData->Vereinzeler, 1);                // Einrichtblech
    bestelleArbeitsplan (arbPlan + 100, steuererData->Vereinzeler, TEMenge (This) - 1); // Restbleche
    myData->AnzahlBestellungen--;
  }
  else {
    bestelleArbeitsplan (arbPlan + 100, steuererData->Vereinzeler, TEMenge (This));
  }

  arbeiten ();
  abgeben ();

  while (Belegung (This)) warten ();
  if (myData->AnzahlBestellungen) {
    bestelleArbeitsplan (arbPlan, steuererData->BlechQuelle, 1);
    myData->AnzahlBestellungen--;
  }
}

//-----------------------------------------------------
//  Event fuer Senke der Sonderfahrten
//-----------------------------------------------------

void _impexp ETaaufnehmen_SonderSenke () {
  SonderSenkenData* myData = (SonderSenkenData*) BstUserData (This);
  if (ArtikelNr (myData->MeinKran) == (int) SonderfahrtKurz)
    setAufnahmezeit (This, SimTime (zufallszahl (10, 1)) - SonderAnfahrtDauer);
  else
    setAufnahmezeit (This, SimTime (zufallszahl (10, 2)) - SonderAnfahrtDauer);

}

//-----------------------------------------------------
//  Event fuer Kran zur Sonderfahrtmessung
//-----------------------------------------------------

void _impexp ETeaufnehmen_Kran () {
  int artnr = ArtikelNr (This);
  if ((artnr == SonderfahrtLang) || (artnr == SonderfahrtKurz)) {
    KranData* myData = (KranData*) BstUserData (This);
    myData->Sonderfahrt.erfassen (100.0);
    myData->HasToReset = true;
  }
}

void _impexp ETeabgeben_Kran () {
  KranData* myData = (KranData*) BstUserData (This);
  if (myData->HasToReset == true) {
    myData->Sonderfahrt.erfassen (0.0);
    myData->HasToReset = false;
  }
}
//-----------------------------------------------------
//  BDE-Programme
//-----------------------------------------------------

void resetBDE () {
  LinienSteuerData* steuererData = (LinienSteuerData*) BstUserData (187);
  steuererData->Stillstand.compress ();
  steuererData->WkzWechsel.compress ();
  steuererData->Betrieb.compress ();

  steuererData = (LinienSteuerData*) BstUserData (16);
  steuererData->Stillstand.compress ();
  steuererData->WkzWechsel.compress ();
  steuererData->Betrieb.compress ();

  steuererData = (LinienSteuerData*) BstUserData (112);
  steuererData->Stillstand.compress ();
  steuererData->WkzWechsel.compress ();
  steuererData->Betrieb.compress ();

  steuererData = (LinienSteuerData*) BstUserData (2);
  steuererData->Stillstand.compress ();
  steuererData->WkzWechsel.compress ();
  steuererData->Betrieb.compress ();

  compressBelegung (22);
  compressBelegung (32);

  KranData* kd = (KranData*) BstUserData (136);
  kd->Sonderfahrt.compress ();
  compressAuslastung (136);
  kd = (KranData*) BstUserData (60);
  kd->Sonderfahrt.compress ();
  compressAuslastung (60);


}

void _impexp prog_1001 () { // Init-BDE

  resetBDE ();
  planeDelta (BDEIntervall, ETprogramm, 0, 1000);
}

void _impexp prog_1000 () { // schreibe BDE
/*
  MyBde << "*********** BDE um " << Modellzeit () << " ***********\n" << endl;

  LinienSteuerData* steuererData = (LinienSteuerData*) BstUserData (187);

  MyBde << "### BDE Linie16:     ";
  MyBde.width (8);
  MyBde << steuererData->Stillstand.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->WkzWechsel.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Betrieb.Mittel () << endl;

  steuererData = (LinienSteuerData*) BstUserData (16);

  MyBde << "### BDE Linie17:     ";
  MyBde.width (8);
  MyBde << steuererData->Stillstand.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->WkzWechsel.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Betrieb.Mittel () << endl;

  steuererData = (LinienSteuerData*) BstUserData (112);

  MyBde << "### BDE Linie18:     ";
  MyBde.width (8);
  MyBde << steuererData->Stillstand.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->WkzWechsel.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Betrieb.Mittel () << endl;

  steuererData = (LinienSteuerData*) BstUserData (2);

  MyBde << "### BDE Linie19:     ";
  MyBde.width (8);
  MyBde << steuererData->Stillstand.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->WkzWechsel.Mittel () << "  ";
  MyBde.width (8);
  MyBde << steuererData->Betrieb.Mittel () << endl;

  MyBde << "### Lager Linie1617: ";
  MyBde.width (8);
  MyBde << MinBelegung (22) << "  ";
  MyBde.width (8);
  MyBde << MitBelegung (22) << "  ";
  MyBde.width (8);
  MyBde << MaxBelegung (22) << endl;

  MyBde << "### Lager Linie1819: ";
  MyBde.width (8);
  MyBde << MinBelegung (32) << "  ";
  MyBde.width (8);
  MyBde << MitBelegung (32) << "  ";
  MyBde.width (8);
  MyBde << MaxBelegung (32) << endl;

  MyBde << "### BDE Kran1617:    ";
  KranData* kd = (KranData*) BstUserData (136);
  double sonderMittel = kd->Sonderfahrt.Mittel ();
  MyBde.width (8);
  MyBde << sonderMittel << "  ";
  MyBde.width (8);
  MyBde << (MitAuslastung (136) - sonderMittel) << endl;

  MyBde << "### BDE Kran1819:    ";
  kd = (KranData*) BstUserData (60);
  sonderMittel = kd->Sonderfahrt.Mittel ();
  MyBde.width (8);
  MyBde << sonderMittel << "  ";
  MyBde.width (8);
  MyBde << (MitAuslastung (60) - sonderMittel) << endl << endl;
*/
  resetBDE ();

  if (Modellzeit () < Modellende ())
    planeDelta (BDEIntervall, ETprogramm, 0, 1000);
}

//################ End S1819R37.cpp ###############
