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

#include "Messung.h"

#include "List.h"
#include "Queue.h"

#define _QUELLE_CPP
#include "modell.h"
#include "quelle.h"

#include "sfx.h"
#include "transp.h"
#include "baustein.h"
#include "ereignis.h"
#include "programm.h"
#include "arbplan.h"
#include "realzeit.h"

//-----------------------------------------------------
//   Klasse QuellenBestellzettel
//-----------------------------------------------------

class QuellenBestellzettel : public ArbeitsplanBestellzettel {
  public:
    QuellenBestellzettel (typArbeitsplan* arb, unsigned istv, unsigned sollv, unsigned wieoft);
    virtual ~QuellenBestellzettel ();

    bool           isMeinTeil (typTransportEinheit*) const;
    bool           isAbgearbeitet () const;
    typTransportEinheit* stornieren ();
    typTransportEinheit* erzeugeTeil ();
    void           vergissTeil ();

  private:
    Queue<typTransportEinheit> ObjTeile;
    typArbeitsplan* ObjArbeitsplan;
};

QuellenBestellzettel::QuellenBestellzettel (typArbeitsplan* arb, unsigned istv, unsigned sollv,
                                            unsigned wieoft)
 : ArbeitsplanBestellzettel (arb->Nummer (), istv, sollv, wieoft),
   ObjTeile      (),
   ObjArbeitsplan (arb)
  { }

/*virtual*/ QuellenBestellzettel::~QuellenBestellzettel ()
  { }

bool QuellenBestellzettel::isMeinTeil (typTransportEinheit* zTE) const {
  return (zTE == ObjTeile.First ());
}

bool QuellenBestellzettel::isAbgearbeitet () const {
  return (!Wieoft () && ObjTeile.isEmpty ());
}

typTransportEinheit* QuellenBestellzettel::stornieren () {
  unsigned anz (Wieoft ());
  if (anz)  while (decWieoft ());
  typTransportEinheit *zTE1 (ObjTeile.remove ()), *zTE2 (ObjTeile.remove ());
  if (zTE2)  {
    ObjTeile.append (*zTE1);
    return zTE2;
  }
  return anz ? zTE1 : (typTransportEinheit*) NULL;
}

typTransportEinheit* QuellenBestellzettel::erzeugeTeil () {
  decWieoft ();
      return &(ObjTeile.append (* (new typTransportEinheit (ObjArbeitsplan))));
}

void QuellenBestellzettel::vergissTeil () {
  ObjTeile.remove ();
}

//-----------------------------------------------------
//   Klasse typQuelle
//-----------------------------------------------------

typQuelle::typQuelle (unsigned n, unsigned b)
 : typPrgBaustein  (n, b),
   ObjArbeitsliste () {
  ObjAvis = new typAvis ();
}

typQuelle::~typQuelle () {
  while (ObjArbeitsliste.Last ())
    delete ObjArbeitsliste.removeLast ();
}

/*virtual*/ void typQuelle::a_aufnehmen () {
  holeMeldung ();
  for (LCursor<typVorgang> c (ObjTransportEinheit->Arbeitsplan()->Vorgaenge ()); c; c++)
    c ()->ZielBaustein ()->Avis ()->incIndIstAnzahl ();
  ObjAvis->decIndIstAnzahl ();
  ObjAvis->incDirIstAnzahl ();
  ObjTransportEinheit->schaltePlatz ();
  incBelegung ();
  setZustand (AUFNEHMEN);
  planedelta (ObjAufnahmezeit, ETeaufnehmen, ObjNummer, 0);
  ObjTransportEinheit->SystemEintritt (ObjPalPlaetze [0]->Position (), ObjWinkel);
  if (MySFXModel->RealTime ())
    RzsSenden (ObjNummer, ETaeinschl, 1);
}

/*virtual*/ void typQuelle::e_aufnehmen () {
  setZustand (PRGWARTEN);
  if (ObjStoerDauer > SimTime (0.0))
    planesofort (ETastoerung, ObjNummer);
  else
    planesofort (ETaktivieren, ObjNummer, ObjNummer);
}

/*virtual*/ void typQuelle::e_arbeiten () {
  ObjPrgArbZeit = SimTime (-1.0);
  ObjTransportEinheit->schalteVorgang (findeSollVorgang (ObjTransportEinheit));
  setZustand (PRGWARTEN);
  if (ObjStoerDauer > SimTime (0.0))
    planesofort (ETastoerung, ObjNummer);
  else
    planesofort (ETaktivieren, ObjNummer, ObjNummer);
}

/*virtual*/ unsigned typQuelle::AnzahlArbeitsliste () const {
  return ObjArbeitsliste.Count ();
}

/*virtual*/ bool typQuelle::hasKapazitaet (typTransportEinheit*) const {
  return true;
}

/*virtual*/ typPlatz* typQuelle::waehlePlatz (typTransportEinheit* zTE) {
  return zTE->setZielPlatz (ObjPalPlaetze[0]);
}

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

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

void typQuelle::ArbBestellung (unsigned idnr, unsigned istvorg, unsigned sollvorg,
                               unsigned wieoft) {
  if (!wieoft)  return;
  typArbeitsplan* zA = MySFXModel->findWorkSchedule (idnr);
  QuellenBestellzettel *zBZ = new QuellenBestellzettel (zA, istvorg, sollvorg, wieoft);
  ObjArbeitsliste.append (*zBZ);
  typTransportEinheit* zTE = zBZ->erzeugeTeil ();
  empfangeMeldung (zTE->Meldung ());
}

void typQuelle::ArtBestellung (unsigned idnr, unsigned istvorg, unsigned sollvorg,
                               unsigned wieoft) {
  if (!wieoft)  return;
  typArbeitsplan* zA = MySFXModel->findWorkScheduleByArticle (idnr, this);
  QuellenBestellzettel *zBZ = new QuellenBestellzettel (zA, istvorg, sollvorg, wieoft);
  ObjArbeitsliste.append (*zBZ);
  typTransportEinheit* zTE = zBZ->erzeugeTeil ();
  empfangeMeldung (zTE->Meldung ());
}

/*virtual*/ bool typQuelle::loescheArbBestellung (unsigned idnr, unsigned istv){
  for (LCursor<QuellenBestellzettel> c (ObjArbeitsliste); c; c++) {
    if (c ()->hatArbeitsplan (idnr, istv)) {
      typTransportEinheit* zTE = c ()->stornieren ();
      if (zTE)                       delete zTE;
      if (c ()->isAbgearbeitet ())  delete ObjArbeitsliste.remove (c);
      return true;
    }
  }
  return false;
}

/*virtual*/ bool typQuelle::loescheArtBestellung (unsigned idnr, unsigned istv){
  typArbeitsplan* zA = MySFXModel->findWorkScheduleByArticle (idnr, this);
  for (LCursor<QuellenBestellzettel> c (ObjArbeitsliste); c; c++) {
    if (c ()->hatArbeitsplan (zA->Nummer (), istv)) {
      typTransportEinheit* zTE = c ()->stornieren ();
      if (zTE)                       delete zTE;
      if (c ()->isAbgearbeitet ())  delete ObjArbeitsliste.remove (c);
      return true;
    }
  }
  return false;
}

/*virtual*/ void typQuelle::individuellAktivieren (typBaustein* vonWem) {
  if (((ObjZustand == RUHE) && (!ObjMeldungen.isEmpty ()))
       || ((ObjZustand == POLLING) && (vonWem == this))
       || (ObjZustand == PRGWARTEN)) {
    if (ObjProgramm)
      if (!PrgModul->continueUserProg (ObjProgramm)) {
        ObjProgramm = NULL;
        if (MySFXModel->PrgDebug ()) dprintf ("Programm geloescht auf Bst = %d\n", ObjNummer);
      }
      else return;

    if (ObjBelegung || ObjMeldungen.isEmpty ())  return;
    typMeldung* zM = findeAusfuehrbareMeldung ();
    if (zM) {
      ObjTransportEinheit = zM->TransportEinheit ();
      setZustand (AKTIVIERT);
      planesofort (ETprogramm, ObjNummer, ObjTransportEinheit->Vorgang ()->ProgNr ());
    }
    else
      if (!ObjMeldungen.isEmpty ()) {
        setZustand (POLLING);
        planedelta (0.1, ETaktivieren, ObjNummer, ObjNummer);
      }
  }
}

typMeldung* typQuelle::findeAusfuehrbareMeldung () {
  LCursor<typMeldung> c (ObjMeldungen);
  if (ObjStrategie != 0)
    for (; c; c++)
      if (isAvisOk (c ()->TransportEinheit ()))  break;

  if (!c)  return NULL;
  erzeugeBestellTeil (c ());
  return &(ObjMeldungen.prepend (*(ObjMeldungen.remove (c))));
}

bool typQuelle::isAvisOk (typTransportEinheit* zTE) const {
  LCursor<typVorgang> c (zTE->Arbeitsplan ()->Vorgaenge ());
  c++;
  bool AvisOK = (ObjStrategie == 3) ? true : c ()->ZielBaustein ()->Avis ()->isDirAvisOk ();

  if ((ObjStrategie >= 2) && AvisOK)
    for (; c; c++)
      AvisOK = (c ()->ZielBaustein ()->Avis ()->isIndAvisOk ());
  return AvisOK;
}

void typQuelle::erzeugeBestellTeil (typMeldung* zM) {
  for (LCursor<QuellenBestellzettel> c (ObjArbeitsliste); c; c++)
    if (c ()->Wieoft () && c ()->isMeinTeil (zM->TransportEinheit ()))  {
      ObjMeldungen.append (*(c ()->erzeugeTeil ()->Meldung ()), *zM);
      return;
    }
}

unsigned typQuelle::findeSollVorgang (typTransportEinheit *zTE) {
  for (LCursor<QuellenBestellzettel> c (ObjArbeitsliste); c; c++)
    if (c ()->isMeinTeil (zTE))  {
      unsigned sollvorgang = c ()->SollVorgang ();
      c ()->vergissTeil ();
      if (c ()->isAbgearbeitet ())  delete ObjArbeitsliste.remove (c);
      return sollvorgang;
    }
  sim_error ("QUELLE", "typQuelle::findeSollVorgang",
             "Palette ohne Bestellzettel auf Quelle", ObjNummer, FATAL);
  return 0;
}

// typQuelle
