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

#include <limits.h>
#include <float.h>

#include "Token.h"

#define _POOLVER_CPP
#include "modell.h"
#include "poolver.h"

#include "sfx.h"
#include "transp.h"
#include "baustein.h"
#include "maschine.h"
#include "regalver.h"

//---------------------------------------------------------
// Klasse typNcPoolverwalter
//---------------------------------------------------------

typNcPoolverwalter::typNcPoolverwalter (unsigned n, unsigned b)
 : typBaustein          (n, b),
   ObjBetreuer          (NULL),
   ObjVerwalter         (NULL),
   ObjLetzterLeuchtturm (NULL),
   ObjMaschinen         (1),
   ObjZuweisungen       () {
  ObjAvis = new typAvis ();
}

typNcPoolverwalter::~typNcPoolverwalter ()
 { }

/*virtual*/ void typNcPoolverwalter::typTPVlesen (InputFile& file) {
  SFXToken tok;
  int anzahl;
  int nr;

  tok.nextToken (file);

  anzahl = atoi (tok ());

  for (int z = 1; z <= anzahl; z++) {
    tok.nextToken (file);
    nr = atoi (tok ());
    ObjMaschinen.append (*((typMaschine*) baustein [nr]));
    baustein [nr]->setVerwalter (this);
  }
  ObjLetzterLeuchtturm = ObjMaschinen.First ();
}

/*virtual*/ void typNcPoolverwalter::a_meldewarten () {
  sim_error ("REGAL", "typNcPoolverwalter::a_meldewarten",
             "a_meldewarten unzulaessig fuer NcPoolverwalter", ObjNummer, FATAL);
}

/*virtual*/ bool typNcPoolverwalter::hasKapazitaet (typTransportEinheit* zTE) const {
  for (ObjMaschinen.First (); ObjMaschinen (); ObjMaschinen++)
    if (ObjMaschinen ()->hasKapazitaet (zTE))  return true;
  return false;
}

/*virtual*/ unsigned typNcPoolverwalter::Kapazitaet () const {
  unsigned kap = 0;
  for (ObjMaschinen.First (); ObjMaschinen (); ObjMaschinen++)
    kap += ObjMaschinen ()->Kapazitaet ();
  return kap;
}

/*virtual*/ unsigned typNcPoolverwalter::setKapazitaet (unsigned) {
  return sim_error ("POOLVER", "typNcPoolverwalter::setKapazitaet",
                    "setKapazitaet unzulaessig fuer NcPoolverwalter", ObjNummer, FATAL);
}

typBaustein* typNcPoolverwalter::setZielBaustein (typTransportEinheit *zTE) {
  typBaustein* ziel;

  if (ObjBetreuer && !(ObjAvis->isDirAvisOk ()))
    ziel = ObjBetreuer->setZielBaustein (zTE);
  else {
    ziel = Ziel_zuweisen (zTE);
    ObjAvis->decIndIstAnzahl ();
    ObjAvis->incDirIstAnzahl ();
    ziel->Avis ()->incDirIstAnzahl ();
    (zTE->Baustein ())->Avis ()->decDirIstAnzahl ();
  }
  return ziel;
}

void typNcPoolverwalter::Meldung_Arbeitsende () {
  if (ObjBetreuer)
    ObjBetreuer->Anforderung_naechste_TE (this);
}

/*virtual*/ typBaustein* typNcPoolverwalter::setVerwalter (typBaustein* newVerwalter) {
  if (newVerwalter->Basistyp () != tNcPoolverwalter)
    sim_error ("BAUSTEIN", "typNcPoolverwalter::setVerwalter",
               "NcPoolverwalter kann nur von NcPoolverwalter verwaltet werden", ObjNummer, FATAL);
  return (ObjVerwalter = (typNcPoolverwalter*) newVerwalter);
}

/*virtual*/ typRegalverwalter* typNcPoolverwalter::setBetreuer (typRegalverwalter* newBetreuer) {
  return (ObjBetreuer = newBetreuer);
}

typBaustein* typNcPoolverwalter::PoolBaustein (unsigned bstNr) const {
  for (ObjMaschinen.First (); ObjMaschinen (); ObjMaschinen++)
    if (ObjMaschinen ()->Nummer () == bstNr)  return ObjMaschinen ();
  return NULL;
}

/*virtual*/ void typNcPoolverwalter::ArbZuweisen (unsigned was,
              unsigned wohin, unsigned istVorg, unsigned sollVorg,
              unsigned wieoft) {
  if (PoolBaustein (wohin)) {
    Zuweisung *zw = new ArbeitsplanZuweisung (was, wohin, istVorg, sollVorg, wieoft);
    ObjZuweisungen.append (*zw);
  }
  else
    sim_error ("BAUSTEIN", "typNcPoolverwalter::ArbZuweisen",
               "Baustein nicht im Pool vorhanden", wohin, FATAL);
}

/*virtual*/ void typNcPoolverwalter::ArtZuweisen (unsigned was,
              unsigned wohin, unsigned istVorg, unsigned sollVorg,
              unsigned wieoft) {
  if (PoolBaustein (wohin)) {
    Zuweisung *zw = new ArtikelZuweisung (was, wohin, istVorg, sollVorg, wieoft);
    ObjZuweisungen.append (*zw);
  }
  else
    sim_error ("BAUSTEIN", "typNcPoolverwalter::ArtZuweisen",
               "Baustein nicht im Pool vorhanden", wohin, FATAL);
}

/*virtual*/ void typNcPoolverwalter::individuellAktivieren (typBaustein*) {
// Diese Funktion ist absichtlich leer!!!!
}

typBaustein* typNcPoolverwalter::ZuweisungAusfuehren
                                   (typTransportEinheit* zTE) {
  if (ObjZuweisungen.isEmpty ()) return NULL;
  for (LCursor<Zuweisung> z (ObjZuweisungen); z; z++)
    if (z ()->TransportEinheitPasst (zTE)) {
      if (z ()->SollVorgang ())
        zTE->schalteVorgang (z ()->SollVorgang ());
        if (! (z ()->decWieoft ())) {
        typBaustein *ziel = PoolBaustein (z ()->FuerBaustein ());
        delete ObjZuweisungen.remove (*z ());
        return ziel;
      }
    }
  return NULL;
}

typBaustein* typNcPoolverwalter::Ziel_zuweisen (typTransportEinheit* zTE) {
  typBaustein* ziel = ZuweisungAusfuehren (zTE);
  if (ziel) return ziel;
  switch (ObjStrategie) {
    case 0:  ziel = zuweisen_FIFO ();
             break;
    case 1:  ziel = zuweisen_Leuchtturm ();
             break;
    case 2:  ziel = zuweisen_Auslastung ();
             break;
    case 3:  ziel = zuweisen_AvisVergleich ();
             break;
    default: ziel = zuweisen_Vorgabe ();  //alle anderen Strategien!
             break;
  }
  return ziel;
}

typBaustein* typNcPoolverwalter::zuweisen_FIFO () {
  for (ObjMaschinen.First (); ObjMaschinen (); ObjMaschinen++)
    if ((!ObjMaschinen ()->Belegung ())
        && (!ObjMaschinen ()->isGesperrtOrGestoert ())
        && (ObjMaschinen ()->Avis ()->isDirAvisOk ()))
      return ObjMaschinen (); //freie Maschine gefunden!
  for (ObjMaschinen.First (); ObjMaschinen (); ObjMaschinen++)
    if (!ObjMaschinen ()->isGesperrtOrGestoert ())  return ObjMaschinen ();
  return ObjMaschinen.First ();
}

typBaustein* typNcPoolverwalter::zuweisen_Leuchtturm () {
  ObjMaschinen.find (*ObjLetzterLeuchtturm);
  ObjMaschinen++;
  if (ObjMaschinen ())  return ObjLetzterLeuchtturm = ObjMaschinen ();
  else                  return ObjLetzterLeuchtturm = ObjMaschinen.First ();
}

typBaustein* typNcPoolverwalter::zuweisen_Auslastung () {
  double minAusl, AuslVergleich = DBL_MAX;
  typMaschine* zM = NULL;
  for (ObjMaschinen.First (); ObjMaschinen (); ObjMaschinen++) {
    if (!ObjMaschinen ()->AuslGeschichte ()) 
      sim_error ("POOLVER", "zuweisen_Auslastung",
        "Maschine ohne AuslastungsGeschichte", ObjMaschinen()->Nummer (),
        FATAL);
    minAusl = ObjMaschinen ()->AuslGeschichte ()->Mittel ();
    if ((!ObjMaschinen ()->isGesperrtOrGestoert ()) && 
        (minAusl < AuslVergleich) &&
        (ObjMaschinen ()->Avis ()->isDirAvisOk ())) {
      zM = ObjMaschinen ();
      AuslVergleich = minAusl;
    }
  }
  if (zM) return zM;

  for (ObjMaschinen.First (); ObjMaschinen (); ObjMaschinen++)
    if (!ObjMaschinen ()->isGesperrtOrGestoert ())  return ObjMaschinen ();
  return ObjMaschinen.First ();
}

typBaustein* typNcPoolverwalter::zuweisen_AvisVergleich () {
  unsigned minAvis, AvisVergleich = UINT_MAX;
  typMaschine* zM = NULL;
  for (ObjMaschinen.First (); ObjMaschinen (); ObjMaschinen++) {
    minAvis = ObjMaschinen ()->Avis ()->DirIstAnzahl ();
    if ((!ObjMaschinen ()->isGesperrtOrGestoert ()) && 
        (minAvis < AvisVergleich)) {
      zM = ObjMaschinen ();
      AvisVergleich = minAvis;
    }
  }
  if (zM) return zM;

  for (ObjMaschinen.First (); ObjMaschinen (); ObjMaschinen++)
    if (!ObjMaschinen ()->isGesperrtOrGestoert ())  return ObjMaschinen ();
  return ObjMaschinen.First ();
}

typBaustein* typNcPoolverwalter::zuweisen_Vorgabe () {
  dprintf("NC Poolverwalter: Strategie %3i nicht implementiert!\n", ObjStrategie);
  dprintf(" -> Zuweisung erfolgt nach Poolliste (Strategie 0) !!\n");
  return zuweisen_FIFO ();
}

