//Vereinzeler
//author: Basti
//ObjTransportEinheit->Vorgang ()->Param2 () ist die Menge an Teilen, welche die vereinzelte TE enthalten soll
//ObjTransportEinheit->Vorgang ()->Param1 () ist die Bearbeitungszeit für das Aufreissen der ankommenden TE
// Die Zeit zum Vereinzeln einer TE ist die normale Bearbeitungszeit auf dem Vorgang, 
// werden mehrere Teile gleichzeitig entnommen ist es weiterhin die Zeit für ein Teil. 
// Es wird e_vereinzeln mit ObjNeuTemp->Vorgang ()->Dauer () * ObjTransportEinheit->Vorgang ()->Param2 () eingeplant !!!

#include "Kalender.h"
#include "DynArray.h"
#include "Queue.h"

#define _VEREIN_CPP
#include "modell.h"
#include "verein.h"

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

//-----------------------------------------------------
//   Klasse typVereinzeler
//-----------------------------------------------------

typVereinzeler::typVereinzeler (unsigned n, unsigned b)
 : typBaustein       (n, b),
   ObjNeuTempAbgeben (false),
   ObjTransportEinheitWartet (false),
   ObjNeuTemp        (NULL),
   ObjNeuZielBst     (NULL),
   ObjFindeMeldungFunktion (typVereinzeler::findeFifoMeldung) {
  ObjAvis = new typAvis();
}

typVereinzeler::~typVereinzeler () {

}





/*virtual*/ void typVereinzeler::typTGSlesen (InputFile& file) {
  typBaustein::typTGSlesen (file);
  if (ObjPalPlaetze.Count () != 2)
    sim_error ("VEREIN", "typVereinzeler::typTGSlesen",
               "Vereinzeler mit != 2 Palettenplaetzen", ObjVariante, FATAL);
}





/*virtual*/ void typVereinzeler::typTTPlesen (InputFile& file) {
  SFXToken tok;
  tok.nextToken (file);
  ObjAufnahmezeit = SimTime (atof (tok ()) * SimTime::SecondsPerMinute ());
  tok.nextToken (file);
  ObjPhysKapazitaet = ObjKapazitaet = atoi (tok ()); // EingangsKap
  tok.nextToken (file); // AusgangsKap ueberlesen!!!!
  file.jump (100); //EOL
}





/*virtual*/ ostream& typVereinzeler::typTTPschreiben (ostream& ostrm) const {
  ostrm.precision (2);
  ostrm << "TTP> ";
  Id_Schreiben (ostrm);
  ostrm << " ";
  ostrm.width (6);
  ostrm << ObjAufnahmezeit.inMinutes () << " ";
  ostrm.width (3);
  ostrm << ObjKapazitaet << "   1" << endl;
  return ostrm;
}





/*virtual*/ void typVereinzeler::typTSTlesen (InputFile& file) {
  typBaustein::typTSTlesen (file);
  if (ObjStrategie != 0)
    sim_error ("VEREIN", "typVereinzeler::typTSTlesen",
               "Strategie nicht implementiert", ObjNummer, FATAL);
}






// fuer RZS: e_ausschl hat den Sinn, dass die Senke keine weitere Palette
// aufnehmen kann, solange sie nicht tatsaechlich frei gemacht wurde.
void typVereinzeler::e_ausschl () {
   cout<<endl<<"/n-----ypVereinzeler::e_ausschl ()"<<endl;
  decBelegung ();
  ObjTransportEinheit->AktPlatz ()->setTransportEinheit (NULL);
  delete ObjTransportEinheit;
  ObjTransportEinheit = NULL;
  setZustand (RUHE);
  planesofort (ETaktivieren, ObjNummer, ObjNummer);
  aktiviereEingaenge ();
}






/*virtual*/ void typVereinzeler::e_aufnehmen () {
   cout<<endl<<"/n-----typVereinzeler::e_aufnehmen ()"<<endl;
  typPlatz *p (ObjTransportEinheit->AktPlatz ());
  if (p->Buchung () != ObjTransportEinheit)
    sim_error ("VEREIN", "typVereinzeler::e_aufnehmen",
               "TransportEinheit ist nicht auf Platz gebucht", ObjNummer, FATAL);
  p->setBuchung (NULL);
  ObjBuchung--;
  ObjTransportEinheit->positionieren (ObjPalPlaetze [0]->Position ());
//  ObjTransportEinheit->fearbeGestalt (default);

  if (ObjStoerDauer > SimTime (0.0))
    planesofort (ETastoerung, ObjNummer);
  else {
    setZustand (AKTIVIERT);
    cout<<"ObjTransportEinheit->Menge ()=: "<<ObjTransportEinheit->Menge ()<<endl;
      planesofort (ETaarbeiten, ObjNummer, p->Nummer ());

  }
  planesofort (ETeabgeben, ObjZielBaustein->Nummer (), ObjNummer);
  int VereinzelMenge = ObjTransportEinheit->Vorgang ()->Param2 ();
  int Kisteninhalt = ObjTransportEinheit->Menge ();
  if (Kisteninhalt % VereinzelMenge!= 0){
      sim_error ("VEREIN", "typVereinzeler::e_aufnehmen",
               "Kopfrechnen ist nicht deine grosse Stärke Du Held", ObjNummer, FATAL);
   }
}





/*virtual*/ void typVereinzeler::a_arbeiten () {
   cout<<endl<<"/n-----typVereinzeler::a_arbeiten ()"<<endl;
  if (notiz::AktInfo2 () == 0)  {
    setZustand (ARBEITEN);
    planedelta (ObjTransportEinheit->Vorgang ()->Param1 (), ETearbeiten, ObjNummer, notiz::AktInfo2 ());
  }
  else{
      planesofort (ETearbeiten, ObjNummer, notiz::AktInfo2 ());
      //planedelta (ObjNeuTemp->Vorgang ()->Dauer (), ETearbeiten, ObjNummer, notiz::AktInfo2 ());
//  if (rzs) RzsSenden (ObjNummer, ETaarbeiten, 0);
   }
}





/*virtual*/ void typVereinzeler::e_arbeiten () {
cout <<endl<<"/n-----typVereinzeler::e_arbeiten ()"<<endl<<"notiz::AktInfo2="<<notiz::AktInfo2 ()<<endl;
  if (notiz::AktInfo2 () == 0){
    if (ObjNeuTempAbgeben)  ObjTransportEinheitWartet = true;
    else planesofort (ETavereinzeln, ObjNummer, notiz::AktInfo2 ());
  }
  else  {
   cout<<"ObjNeuTemp->schalteVorgang (ObjNummer)"<<ObjNummer<<endl;
    ObjNeuTemp->schalteVorgang ();
    ObjNeuZielBst = ObjNeuTemp->Meldung ()->NachBaustein ();
    ObjNeuTemp->Anmelden ();
  }
}





/*virtual*/ void typVereinzeler::a_vereinzeln () {
   cout<<endl<<"/n-----typVereinzeler::a_vereinzeln ()"<<endl;
   double vorhandeneMenge;
   setZustand (ARBEITEN);
   ObjTransportEinheitWartet = false;
   if (ObjTransportEinheit && (ObjTransportEinheit->Menge () > 0)){
      vorhandeneMenge = ObjTransportEinheit->Menge ();
      cout<<"a_vereinzeln vorhandeneMenge = "<<ObjTransportEinheit->Menge ()<<endl;
   }
   
   if (vorhandeneMenge == ObjTransportEinheit->Vorgang ()->Param2 ()) {
      ObjTransportEinheit->decMenge (ObjTransportEinheit->Vorgang ()->Param2 ());
      erzeugeNeuTemp ();
      ObjNeuTemp->setMenge (ObjTransportEinheit->Vorgang ()->Param2 ());
      ObjNeuTempAbgeben = true;
      planedelta (ObjNeuTemp->Vorgang ()->Dauer () * ObjTransportEinheit->Vorgang ()->Param2 (),
                ETevereinzeln, ObjNummer, notiz::AktInfo2 ());
   }
   else {
      ObjTransportEinheit->decMenge (ObjTransportEinheit->Vorgang ()->Param2 ());
      cout<<"a_vereinzeln nach else ObjTransportEinheit->decMenge (1)"<<endl;
      erzeugeNeuTemp ();
      ObjNeuTemp->setMenge (ObjTransportEinheit->Vorgang ()->Param2 ());
      ObjNeuTempAbgeben = true;
      planedelta (ObjNeuTemp->Vorgang ()->Dauer () * ObjTransportEinheit->Vorgang ()->Param2 (),
                ETevereinzeln, ObjNummer, notiz::AktInfo2 ());
   }
}





/*virtual*/ void typVereinzeler::e_vereinzeln () {
   cout<<endl<<"/n-----typVereinzeler::e_vereinzeln ()"<<endl;
   planesofort (ETaarbeiten, ObjNummer, 1);
   ObjTransportEinheitWartet = true;
}





/*virtual*/ void typVereinzeler::eStoeren () {
  ObjStoerEnde = NULL;
  if (ObjStoerGeschichte) ObjStoerGeschichte->erfassen (0.0);
  switch (ObjAlterZustand) {
    case AUFNEHMEN :  setZustand (AKTIVIERT);
                        planesofort (ETaarbeiten, ObjNummer,0);
                      break;

    default        :  setZustand (ObjAlterZustand); // RUHE or POLLING!!!
                      planesofort (ETaktivieren, ObjNummer, ObjNummer);
                      aktiviereEingaenge ();
                      aktiviereAusgaenge ();
                      break;
  }
}






/*virtual*/ typTransportEinheit* typVereinzeler::gibTransportEinheit (typMeldung* zM) {
   cout<<endl<<"/n-----typVereinzeler::gibTransportEinheit (typMeldung* zM)"<<endl;
   typTransportEinheit *zTE = zM->TransportEinheit ();
   zTE->AktPlatz ()->setTransportEinheit (NULL);
   if (zTE == ObjTransportEinheit)  {
      setZustand (AKTIVIERT);
      decBelegung ();
      if (ObjBelGeschichte) ObjBelGeschichte->erfassen (ObjBelegung);
      planesofort (ETaabgeben, ObjNummer, ObjZielBaustein->Nummer ());
      ObjTransportEinheit = NULL;
   }
   else  {
      planesofort (ETaabgeben, ObjNummer, ObjNeuZielBst->Nummer ());
      ObjNeuTemp = NULL;
   }
  return zTE;
}





/*virtual*/ void typVereinzeler::a_abgeben () {
   cout<<endl<<"/n-----typVereinzeler::a_abgeben ()"<<endl;
   if (baustein [notiz::AktInfo2 ()] == ObjZielBaustein)  setZustand (ABGEBEN);
}





/*virtual*/ void typVereinzeler::e_abgeben () {
   cout<<endl<<"/n-----typVereinzeler::e_abgeben ()"<<endl;
  if (baustein [notiz::AktInfo2 ()] == ObjZielBaustein)  {
    setZustand (RUHE);
    ObjZielBaustein = NULL;
  }
  else  {
    ObjNeuZielBst = NULL;
    ObjNeuTempAbgeben = false;
  }
  planesofort (ETaktivieren, ObjNummer, ObjNummer);
  if (ObjTransportEinheit->Menge()==0) {
      planesofort (ETeausschl, ObjNummer, 0);
   }

  aktiviereEingaenge ();
}






/*virtual*/ bool typVereinzeler::hasKapazitaet (typTransportEinheit* ) const {
   cout<<endl<<"/n-----typVereinzeler::hasKapazitaet (typTransportEinheit* zTE)"<<endl;
  return (ObjBelegung + ObjBuchung) < ObjKapazitaet;
}





/*virtual*/ typPlatz* typVereinzeler::waehlePlatz (typTransportEinheit* zTE) {
   cout<<endl<<"/n-----typVereinzeler::waehlePlatz (typTransportEinheit* zTE)"<<endl;
  if (zTE->AktPlatz ()) {
    typPlatz* p = ObjPalPlaetze [0];
    if (!p->isVerfuegbar ())  
      return (p->Buchung () == zTE) ? p : (typPlatz*) NULL;
    p->setBuchung (zTE);
    ObjBuchung++;
    return p;
  }
  else  return zTE->setZielPlatz (ObjPalPlaetze [1]);  // Ausgangsseite
}





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





/*virtual*/ Vec3D typVereinzeler::UebergabePos (const typBaustein& bst) const {
  return (ObjNeuZielBst == &bst) ? ObjPalPlaetze [1]->Position ()
                                 : ObjPalPlaetze [0]->Position ();
}






/*virtual*/ void typVereinzeler::individuellAktivieren (typBaustein* vonWem) {
   cout<<endl<<"/n-----typVereinzeler::individuellAktivieren (typBaustein* vonWem)"<<endl<<"     vonWem"<<vonWem->Nummer()<<endl;
  if (!(((ObjZustand == RUHE)  && (!ObjMeldungen.isEmpty ()))
        || ((ObjZustand == WARTEDP) && (ObjZielBaustein == vonWem))
        || (vonWem == this)))
    return;
  if (ObjTransportEinheit)  {
    if (ObjTransportEinheitWartet && !ObjNeuTemp)
      planesofort (ETavereinzeln, ObjNummer, ObjTransportEinheit->AktPlatz ()->Nummer ());
    return;
  }
  typMeldung* zM = findeAusfuehrbareMeldung ();
  if (zM) {
    ObjTransportEinheit = zM->TransportEinheit ();
    ObjZielBaustein = zM->VonBaustein ();    
    wartenaufnehmen (ObjTransportEinheit, ObjZielBaustein);
  }
}





typMeldung* typVereinzeler::findeAusfuehrbareMeldung () {
   cout<<endl<<"/n-----typVereinzeler::findeAusfuehrbareMeldung ()"<<endl;
   LCursor<typMeldung> c (ObjMeldungen);
   typTransportEinheit *zTE;
   for ( ; c; c++) {
      zTE = c ()->TransportEinheit ();
      break;
   }
   typTransportEinheit* zBuch = ObjPalPlaetze [0]->Buchung (); 
   if (c&&(!zBuch || (zTE == zBuch))) {
      if (!zBuch)  zTE->setZielPlatz (waehlePlatz (zTE));
      return &(ObjMeldungen.prepend (*(ObjMeldungen.remove (c))));
   }
   return NULL;
}





void typVereinzeler::erzeugeNeuTemp () {
   cout<<endl<<"/n-----typVereinzeler::erzeugeNeuTemp ()"<<endl;
  ObjNeuTemp = new typTransportEinheit (ObjTransportEinheit->Arbeitsplan(), ObjTransportEinheit->Vorgang()->Nummer());
  for (LCursor<typVorgang> c (ObjNeuTemp->Arbeitsplan ()->Vorgaenge ()); c; c++)
    c ()->ZielBaustein ()->Avis ()->incIndIstAnzahl ();
  ObjAvis->decIndIstAnzahl ();
  ObjAvis->incDirIstAnzahl ();
  ObjNeuTemp->schaltePlatz ();
  ObjNeuTemp->SystemEintritt (ObjPalPlaetze [1]->Position (), ObjWinkel);
//  ObjNeuTemp->fearbeGestalt (default);
}







typMeldung* typVereinzeler::findeFifoMeldung (typVereinzeler* who) { // Strategie 0
  typTransportEinheit* zBuch = who->ObjPalPlaetze [0]->Buchung ();
  for (LCursor<typMeldung> c (who->ObjMeldungen); c; c++) {
    typTransportEinheit* zTE = c ()->TransportEinheit ();
    if (!zBuch || (zTE == zBuch)) {
      if (!zBuch)  zTE->setZielPlatz (who->waehlePlatz (zTE));
      return &(who->ObjMeldungen.prepend (*(who->ObjMeldungen.remove (c))));
    }
  }
  return NULL;
}