<?php
/**
 * @copyright (c) Kufer Software GmbH, Oderstraße 7, D-84453 Mühldorf
 */

use Kufer\Web\Classes\Gebuehren\WarenkorbBerechnungsKontext;
use Kufer\Web\Classes\Gebuehren\WarenkorbBerechnungsState;


abstract class GebuehrenElementRechner
{
  
  protected $gebuehrenElement;

  
  abstract public function ladeGebuehren($knr);

  abstract protected function getKindGebuehrElement(
    $lfdNr,
    $zpid,
    ?WarenkorbBerechnungsKontext $wkKontext = null,
    ?WarenkorbBerechnungsState $wkState = null
  ): GebuehrenElement;

  abstract protected function getKindGebuehrElementErmaessigt(
    $lfdNr,
    KursgebuehrBerechnungsKontextTeilnehmer $kGebBerKontextTn,
    ?WarenkorbBerechnungsKontext $wkKontext = null,
    ?WarenkorbBerechnungsState $wkState = null
  ): GebuehrenElement;

  
  public static function createInstance(?bool $isKuferSql5): GebuehrenElementRechner
  {
    if ($isKuferSql5 ?? \System::isKuferSql5()) {
      return new GebuehrenElementRechnerFuenfNull();
    } else {
      return new GebuehrenElementRechnerVierZwanzig();
    }
  }

  public function setGebuehrenElement($gebuehrenElement)
  {
    $this->gebuehrenElement = $gebuehrenElement;
  }

  public function getGebuehrenSummeErmaessigt(
    int $currentTnIndex,
    KursgebuehrBerechnungsKontext $kGebBerKontext,
    ?WarenkorbBerechnungsKontext $wkKontext = null,
    ?WarenkorbBerechnungsState $wkState = null
  ): float {
    $gebElem = $this->applyGebuehrenElementVisitors(clone $this->gebuehrenElement, $currentTnIndex, $kGebBerKontext, $wkKontext, $wkState);

    return $gebElem->getSum();
  }

  
  public function getGebuehrenSaetzeErmaessigt(
    int $currentTnIndex,
    KursgebuehrBerechnungsKontext $kGebBerKontext,
    ?WarenkorbBerechnungsKontext $wkKontext = null,
    ?WarenkorbBerechnungsState $wkState = null
  ): array {
    $gebElem = $this->applyGebuehrenElementVisitors(clone $this->gebuehrenElement, $currentTnIndex, $kGebBerKontext, $wkKontext, $wkState);
    $gebElem->accept(new GebuehrenElementVisitorFloatToString());

    return $gebElem->getGebuehrensaetze();
  }

  public function getKindGebuehrSumme($lfdNr, $zpid, ?WarenkorbBerechnungsKontext $wkKontext = null, ?WarenkorbBerechnungsState $wkState = null): float
  {
    return $this->getKindGebuehrElement($lfdNr, $zpid, $wkKontext, $wkState)->getSum();
  }

  public function getKindGebuehrSaetze($lfdNr, $zpid, ?WarenkorbBerechnungsKontext $wkKontext = null, ?WarenkorbBerechnungsState $wkState = null): array
  {
    $gebElem = $this->getKindGebuehrElement($lfdNr, $zpid, $wkKontext, $wkState);
    $gebElem->accept(new GebuehrenElementVisitorFloatToString());

    return $gebElem->exportGebuehrensaetze();
  }

  
  public function getKindGebuehrErmaessigtSumme(
    $lfdNr,
    KursgebuehrBerechnungsKontextTeilnehmer $kGebBerKontextTn,
    ?WarenkorbBerechnungsKontext $wkKontext = null,
    ?WarenkorbBerechnungsState $wkState = null
  ): float {
    return $this->getKindGebuehrElementErmaessigt($lfdNr, $kGebBerKontextTn, $wkKontext, $wkState)->getSum();
  }

  
  public function getKindGebuehrErmaessigtSaetze(
    $lfdNr,
    KursgebuehrBerechnungsKontextTeilnehmer $kGebBerKontextTn,
    ?WarenkorbBerechnungsKontext $wkKontext = null,
    ?WarenkorbBerechnungsState $wkState = null
  ): array {
    $gebElem = $this->getKindGebuehrElementErmaessigt($lfdNr, $kGebBerKontextTn, $wkKontext, $wkState);
    $gebElem->accept(new GebuehrenElementVisitorFloatToString());

    return $gebElem->exportGebuehrensaetze();
  }

  
  protected function applyGebuehrenElementVisitors(
    GebuehrenElement $gebElem,
    int $currentTnIndex,
    KursgebuehrBerechnungsKontext $kGebBerKontext,
    ?WarenkorbBerechnungsKontext $wkKontext = null,
    ?WarenkorbBerechnungsState $wkState = null
  ): GebuehrenElement {
    $zahlplan = $kGebBerKontext->tns[$currentTnIndex]->zahlplan;
    $visitChooseZps = new GebuehrenElementVisitorFilterByZahlplan($zahlplan, $gebElem->getTeilMin());
    $gebElem->accept($visitChooseZps);

    if ($kGebBerKontext->isKollegenrabattApplicable($currentTnIndex)) {
      $visitKollegenRabatt = new GebuehrenElementVisitorApplyKollegenrabatt();
      $gebElem->accept($visitKollegenRabatt);
    }

    if ($kGebBerKontext->isVsbMitgliederRabattApplicable($currentTnIndex)) {
      $visitVsbRabatt = new GebuehrenElementVisitorApplyVsbMitgliederRabatt();
      $gebElem->accept($visitVsbRabatt);
    }

    
    
    
    
    if ($currentTnIndex > 0 && ($kGebBerKontext->hauptTnAuch || $kGebBerKontext->isFirmenAnmeldung)) {
      $visitPauschal = new GebuehrenElementVisitorRemovePauschalgebuehr();
      $gebElem->accept($visitPauschal);
    }

    
    if (!$kGebBerKontext->rabattierbar) {
      $kontextTn = $kGebBerKontext->tns[$currentTnIndex];
      $visitProz = new GebuehrenElementVisitorApplyErmaessigungProz(
        $kontextTn->ermProzent,
        $kontextTn->kursbezogeneErmaessigung,
        $kontextTn->ermGrund
      );
      $gebElem->accept($visitProz);
    }

    
    
    
    
    

    if ($wkKontext && $wkKontext->gutscheinBetrag) {
      $visitGutscheinBetrag = new GebuehrenElementVisitorGutscheinBetrag(
        $wkKontext,
        $wkState
      );
      $gebElem->accept($visitGutscheinBetrag);
    }

    if ($currentTnIndex == 0 && isset($kGebBerKontext->spendeninfos)) {
      $visitSpendenBetrag = new GebuehrenElementVisitorSpendenBetrag(
        $kGebBerKontext->spendeninfos,
        $kGebBerKontext->useKostenstellenAndererGebuehrenForSpenden
      );
      $gebElem->accept($visitSpendenBetrag);
    }

    if (!$kGebBerKontext->brutto) {
      $visitNetto = new GebuehrenElementVisitorNetto();
      $gebElem->accept($visitNetto);
    }

    return $gebElem;
  }
}