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


class TeilnehmerAPI
{
  public const ALGORITHM_DUBLETTE_EINBUCHUNGSROUTINE = 1;
  
  public const ALGORITHM_DUBLETTE_SIMPEL = 2;
  public const ALGORITHM_DUBLETTE_SIMPEL_PERSNR = 3;
  public const ALGORITHM_DUBLETTE_SIMPEL_GEBDAT = 4;
  public const ALGORITHM_DUBLETTE_SIMPEL_TNR = 5;
  
  public const ALGORITHM_DUBLETTE_SIMPEL_OHNE_STAMMHOERER = 6;

  
  private function __construct()
  {
  }

  
  public static function getXMLNode($pTeilnehmer, $fields, $pBezeichnung = 'teilnehmer')
  {
    return AbgleichAPI::getXMLNode(new DBWorkTeilnehmer(), $pTeilnehmer, $fields, $pBezeichnung);
  }

  
  public static function correctTeilnehmer($pTnTuple, $pCorrectMode = 'insert', $pOperation = AbgleichAPI::ABGLEICH_TEILNEHMER, $pNoMapping = false)
  {
    return AbgleichAPI::correctDatamodul(
      new DBWorkTeilnehmer(),
      $pTnTuple,
      $pCorrectMode,
      'teilnehmer',
      'teilnehmer',
      'teilnehm',
      $pOperation,
      AbgleichAPI::ABGLEICH_TEILNEHMERDELETE,
      AbgleichAPI::ABGLEICH_TEILNEHMERKORREKTUR,
      $pNoMapping
    );
  }

  
  public static function deleteTeilnehmer($pTnId, $pNoMapping = false)
  {
    $abgleichAPI = new AbgleichAPI();
    $message = new XMLNode('teilnehmer');

    
    $dbwTeilnehmer = new DBWorkTeilnehmer();
    $datamodulNode = AbgleichAPI::getXMLNode($dbwTeilnehmer, $dbwTeilnehmer->getTeilnehm($pTnId), array('id'), 'teilnehmer', true);
    $message->addChild($datamodulNode);

    $nutzlast = new Nutzlast($message);
    if ($pNoMapping) {
      $nutzlast->addNode(new XMLNode('nomapping', 'W'));
    }

    $abgleichAPI->sendeNachricht(
      AbgleichAPI::ABGLEICH_TEILNEHMERDELETE,
      $nutzlast
    );
  }

  
  public static function saveTeilnehmer($builder, $pModeUpdate = false)
  {
    $statusMessage = '';
    
    $teilnehmer = $builder->getData();
    
    if ($teilnehmer->getVarValue('erm_ende') === '') {
      $teilnehmer->setValue2Var('erm_ende', DateTimeOperations::getDateNow());
    }
    $dbwTn = new DBWorkTeilnehmer(1, true);
    $origTeilnehmer = null;
    $changedFields = array();
    if ($pModeUpdate) {
      $origTeilnehmer = $dbwTn->getTeilnehm($teilnehmer->id, true);
      $benutzerId = SessionOperations::getCurrentWebToolsUser()->ben;
      $dbwBASysUser = DBWorkBASysUser::getDefaultInstance();
      $benutzerKuerzel = $dbwBASysUser->getBASysUser($benutzerId)->kennung;
      $tnAndChangedFields = self::aktualisiereBerechneteTeilnehmerDaten($origTeilnehmer, $teilnehmer, $benutzerKuerzel);
      $teilnehmer = $tnAndChangedFields['teilnehmer'];
      $changedFields = $tnAndChangedFields['changedFields'];
      
      
      
    }
    
    if ($teilnehmer->arykennzeichen === false) {
      $kennzAddAry = array();
      $kennzDelAry = array();
    } else {
      
      $kennzeichenActionObj = self::getKennzeichenAry($teilnehmer);
      $kennzAddAry = $kennzeichenActionObj->add;
      $kennzDelAry = $kennzeichenActionObj->del;
    }

    $allgsettings = AllgSettingsAPI::getAllgSettings();
    
    $changedFields = array_merge($changedFields, $builder->getFieldNamesOfChangedFields($origTeilnehmer), $teilnehmer->getKommAnzeigeAry($origTeilnehmer));
    
    if (count($changedFields) == 0 && count($kennzAddAry) == 0 && count($kennzDelAry) == 0) {
      $statusMessage .= HTMLOperations::getInfoBox('<div class="infobox_text">' . CleanOperations::cleanStringForHtml($allgsettings->failMsgChangeTeilnehmer) . '</div>', 'Hinweis', 'in_background');

      return array('statusMessage' => $statusMessage, 'tnId' => -1);
    }

    $insertedTnId = -1;
    try {
      if (SessionOperations::isDmzBetrieb()) {
        
        if ($pModeUpdate) {
          
          
          $teilnehmer->updateKommAnzeige();
          $teilnehmerTuple = new Tuple($teilnehmer, $changedFields, $origTeilnehmer);

          
          self::updateTeilnehmer4DMZ($teilnehmerTuple, 'update', $kennzAddAry, $kennzDelAry);
        } else { 
          
          $tnIds = self::insertTeilnehmer4DMZ($teilnehmer, $kennzAddAry, $changedFields);
          $insertedTnId = $tnIds['replikatid'];
        }

        
        StammBvAPI::bereinigeBankdatenAnhandTeilnehmer($teilnehmer, true, true);
      }

      
      else {
        if ($pModeUpdate) {
          
          self::updateTeilnehmerRepoDirekt($dbwTn, $teilnehmer, false, $kennzAddAry, $kennzDelAry);
        } else {
          
          $insertedTnId = self::insertTeilnehmerRepoDirekt($dbwTn, $teilnehmer, $kennzAddAry);
        }

        StammBvAPI::bereinigeBankdatenAnhandTeilnehmer($teilnehmer, true, false);
      }
      $statusMessage .= HTMLOperations::getSuccessBox('<div class="successbox_text">' . CleanOperations::cleanStringForHtml($allgsettings->successMsgTeilnehmerNeu) . '</div>' . "\n", 'Übermittlung erfolgreich', 'in_background');
    } catch (AbgleichApiException $aae) {
      Logger::logg('Teilnehmerkorrektur - folgende Exception ist aufgetreten: ' . $aae->getMessage() . "\n" . ' [' . $aae->getTraceAsString() . ']', 200);

      if ($aae->errorType == AbgleichApiResult::CONFLICT) {
        $statusMessage .= HTMLOperations::getAlertBox('<div class="alertbox_text">' . CleanOperations::cleanStringForHtml($allgsettings->failSubmitMsgConflict) . '</div>', 'Fehler', 'in_background');
      } else {
        $statusMessage .= HTMLOperations::getAlertBox('<div class="alertbox_text">' . CleanOperations::cleanStringForHtml($allgsettings->failSubmitMsgTeilnehmer) . '</div>', 'Fehler', 'in_background');
      }
    }
    
    
    catch (Exception $e) {
      if ($pModeUpdate) {
        $statusMessage .= HTMLOperations::getInfoBox('<div class="infobox_text">' . CleanOperations::cleanStringForHtml($allgsettings->failMsgChangeTeilnehmer) . '</div>', 'Hinweis', 'in_background');
      } else {
        $statusMessage .= HTMLOperations::getAlertBox('<div class="alertbox_text">' . CleanOperations::cleanStringForHtml($allgsettings->failMsgTeilnehmerNeu) . '</div>', 'Fehler', 'in_background');
      }
      Logger::logg('Teilnehmerkorrektur - folgende Exception ist aufgetreten: ' . $e->getMessage() . "\n" . ' [' . $e->getTraceAsString() . ']', 200);
    }

    return array('statusMessage' => $statusMessage, 'tnId' => $insertedTnId);
  }

  
  public static function saveTeilnehmerBySightBuilder($pSightBuilder)
  {
    $builder = $pSightBuilder;
    $saveResult = array('statusMessage' => '', 'tnId' => -1);
    
    $builder->saveData();
    $validationOK = $builder->checkValidation();

    if ($validationOK) {
      
      $saveResult = TeilnehmerAPI::saveTeilnehmer($builder, false);
    } else {
      $saveResult['statusMessage'] = $builder->buildInvalidFieldsDiv();
    }
    
    return $saveResult;
  }

  
  public static function getKennzeichenAry($pTeilnehmer)
  {
    $dbwkennz = new DBWorkKennz();
    $origKennzIds = array();
    $origKennzAry = $dbwkennz->getKennzeichen4Teilnehmer($pTeilnehmer->id);
    
    foreach ($origKennzAry as $origKennz) {
      $origKennzIds[] = $origKennz->kennz;
    }
    
    $newKennzIds = array();
    if ($pTeilnehmer->arykennzeichen != '') {
      foreach ($pTeilnehmer->arykennzeichen as $newKennz) {
        $newKennzIds[] = $newKennz->kennz;
      }
    }

    
    $kennzAddAry = array();
    $kennzDelAry = array();
    
    foreach ($origKennzIds as $oldKennzId) {
      if (!in_array($oldKennzId, $newKennzIds)) {
        $kennzDelAry[] = $oldKennzId;
      }
    }

    
    foreach ($newKennzIds as $newKennzId) {
      if (!in_array($newKennzId, $origKennzIds)) {
        $kennzAddAry[] = $newKennzId;
      }
    }
    $kennzActObj = new stdClass();
    $kennzActObj->add = $kennzAddAry;
    $kennzActObj->del = $kennzDelAry;

    return $kennzActObj;
  }

  
  public static function updateTeilnehmer4DMZ($pTeilnehmerTuple, $pCorrectMode, $pKennzAddAry, $pKennzDelAry)
  {
    $teilnehmer = $pTeilnehmerTuple->getFirst();
    $origTeilnehmer = $pTeilnehmerTuple->getThird();
    $dbwTn = new DBWorkTeilnehmer();
    $dbwkennzAd = new DBWorkKennzAd();
    
    $noProtocol = true;
    
    
    $origKommAry = KommunikationsAPI::getOrigKommunikation($teilnehmer);
    $currentKommAry = array();

    try { 
      
      self::correctTeilnehmer($pTeilnehmerTuple, $pCorrectMode);
      
      
      
      $dbwTn->updateTeilnehmer($teilnehmer, $noProtocol);


      try { 
        
        


        self::buildAndSendKennzeichen($teilnehmer, array(), $pKennzDelAry);

        
        foreach ($pKennzDelAry as $kennzId) {
          $dbwkennzAd->deleteKennzeichen($kennzId, 'T', $teilnehmer->id);
        }

        try { 
          
          
          self::buildAndSendKennzeichen($teilnehmer, $pKennzAddAry, array());
          
          foreach ($pKennzAddAry as $kennzId) {
            $dbwkennzAd->insertKennzeichen($kennzId, 'T', $teilnehmer->id);
          }
          try { 
            
            $teilnehmer = $dbwTn->updateKommBlock($teilnehmer, $noProtocol);
            $currentKommAry = KommunikationsAPI::getCurrentKommunikation($teilnehmer);

            
            
            KommunikationsAPI::buildAndSendKommunikation($teilnehmer, $origKommAry);

            try {
              NewsletterAPI::updateTeilnehmerNewsletterInteressensgebieteByDMZ(array($teilnehmer));
              NewsletterAPI::updateTeilnehmerNewsletterInteressensgebieteInWebDB($teilnehmer);
            } catch (Exception $ex) {
              throw $ex;
            }

            
            
            
          } 
          catch (Exception $e) { 
            
            
            KommunikationsAPI::revertChangesOfKommunikation4DMZ($dbwTn, $origTeilnehmer, $currentKommAry, $origKommAry, $noProtocol);
            
            self::buildAndSendKennzeichen($teilnehmer, array(), $pKennzAddAry);
            
            foreach ($pKennzAddAry as $kennzId) {
              $dbwkennzAd->deleteKennzeichen($kennzId, 'T', $teilnehmer->id);
            }

            throw($e);
          } 
        } 
        catch (Exception $e) { 
          

          
          self::buildAndSendKennzeichen($teilnehmer, $pKennzDelAry, array());
          
          foreach ($pKennzDelAry as $kennzId) {
            $dbwkennzAd->insertKennzeichen($kennzId, 'T', $teilnehmer->id);
          }

          throw($e);
        } 
      } 
      catch (Exception $e) { 
        
        

        

        $origTeilnehmer = $pTeilnehmerTuple->getThird();
        $origTeilnehmTuple = clone $pTeilnehmerTuple;
        $origTeilnehmTuple->setFirst($origTeilnehmer);
        $origTeilnehmTuple->setThird($teilnehmer);
        self::correctTeilnehmer($origTeilnehmTuple, $pCorrectMode);

        
        
        $dbwTn->updateTeilnehmer($origTeilnehmer, $noProtocol, $teilnehmer);

        throw($e);
      } 
    } catch (Exception $e) {
      
      
      throw($e);
    }
  }

  
  public static function insertTeilnehmer4DMZ(
    \Teilnehmer $pTeilnehmer,
    array $pKennzAddAry,
    array $pChangedFields,
    ?int $pOperation = null,
    bool $pFuegeTnDatenInWebDbEin = true
  ): array {
    $teilnehmer4DMZAPI = new Teilnehmer4DMZAPI(
      $pTeilnehmer,
      $pKennzAddAry,
      $pChangedFields,
      $pOperation,
      $pFuegeTnDatenInWebDbEin
    );

    return $teilnehmer4DMZAPI->insertTeilnehmer4DMZ();
  }

  public static function fuelleKommBlockTnr($pTeilnehmer)
  {
    $teilnehmer = $pTeilnehmer;
    foreach ($teilnehmer as $evtlKommobj) {
      
      
      if ($evtlKommobj instanceof Kommunikation) {
        $evtlKommobj->nr = $pTeilnehmer->id;
      }
    }

    return $teilnehmer;
  }

  
  public static function updateTeilnehmerRepoDirekt($pDbwTn, $pTeilnehmer, $pForceNoProtokoll = false, $pKennzAddAry = null, $pKennzDelAry = null)
  {
    
    
    
    $protokollieren = false;
    if (!$pForceNoProtokoll && SessionOperations::isReplikat()) {
      $dbwWebReplikatSettings = new DBWorkWebReplikatSettings();
      $highestTnr = $dbwWebReplikatSettings->getHighestTNNr();
      if ($pTeilnehmer->id <= $highestTnr->value) {
        $protokollieren = true;
      }
    }
    
    $pDbwTn->updateTeilnehmer($pTeilnehmer, !$protokollieren);

    $dbwkennzAd = new DBWorkKennzAd();
    
    if (is_array($pKennzAddAry)) {
      foreach ($pKennzAddAry as $kennzId) {
        
        
        $dbwkennzAd->insertKennzeichen($kennzId, 'T', $pTeilnehmer->id);
      }
    }

    
    if (is_array($pKennzDelAry)) {
      foreach ($pKennzDelAry as $kennzId) {
        $dbwkennzAd->deleteKennzeichen($kennzId, 'T', $pTeilnehmer->id);
      }
    }
    
    $pDbwTn->updateKommBlock($pTeilnehmer, !$protokollieren);

    NewsletterAPI::updateTeilnehmerNewsletterInteressensgebieteInWebDB($pTeilnehmer);
  }

  
  public static function insertTeilnehmerRepoDirekt($pDbwTn, $pTeilnehmer, $pKennzAddAry)
  {
    
    $protokollieren = false;
    $insertedTnId = $pDbwTn->insertTeilnehmer($pTeilnehmer, !$protokollieren);
    
    
    if ($insertedTnId > 0) {
      
      $dbwkennzAd = new DBWorkKennzAd();
      foreach ($pKennzAddAry as $kennzId) {
        
        
        $dbwkennzAd->insertKennzeichen($kennzId, 'T', $pTeilnehmer->id);
      }
      $pDbwTn->insertKommBlock($pTeilnehmer, !$protokollieren);
    }
    $tnWithId = $pTeilnehmer;
    $tnWithId->id = $insertedTnId;
    NewsletterAPI::updateTeilnehmerNewsletterInteressensgebieteInWebDB($tnWithId);

    return $insertedTnId;
  }

  
  public static function buildAndSendKennzeichen($pPerson, $pKennzAddAry, $pKennzDelAry = array())
  {
    $kennzAry4Insert = array();
    $kennzAry4Delete = array();

    
    
    foreach ($pKennzAddAry as $kennzId) {
      $kennzObj = new KennzAd();
      $kennzObj->nr = $pPerson->id;
      $kennzObj->kennz = $kennzId;
      $kennzObj->typ = 'T';
      $kennzObj->text = '';
      $kennzObj->bearbeiter = SessionOperations::getCurrentWebToolsUserKennung();
      $kennzObj->bearbdatum = DateTimeOperations::getDateTimeNow();
      $kennzAry4Insert[] = $kennzObj;
    }
    
    foreach ($pKennzDelAry as $kennzId) {
      $kennzObj = new KennzAd();
      $kennzObj->nr = $pPerson->id;
      $kennzObj->kennz = $kennzId;
      $kennzObj->typ = 'T';
      $kennzAry4Delete[] = $kennzObj;
    }

    
    self::correctKennzeichen($kennzAry4Insert, 'insert');
    self::correctKennzeichen($kennzAry4Delete, 'delete');
  }

  
  public static function correctKennzeichen($pKennzAry, $pCorrectMode = 'insert')
  {
    if (count($pKennzAry) == 0) {
      return 'noCorrection';
    }
    $abgleichAPI = new AbgleichAPI();
    if (!$abgleichAPI->isAktiviert()) {
      return 'nichtAktiviert';
    }

    $message = new XMLNode('kennzeichen');
    
    
    $dbworkWebReplikatSettings = new DBWorkWebReplikatSettings();
    $webreplikatsetting = $dbworkWebReplikatSettings->getMaxPk('kennzeichen');
    $childNode = new XMLNode('highestpk', '-', 'leer="true"');
    if (isset($webreplikatsetting) && $webreplikatsetting->value != '') {
      $childNode = new XMLNode('highestpk', $webreplikatsetting->value);
    }
    $message->addChild($childNode);

    $nothingToDo = true;
    foreach ($pKennzAry as $kennzAd) {
      $kennzAdNode = new XMLNode('kennzad');

      
      $kennzAdNode->addChild(new XMLNode('nr', $kennzAd->nr));
      $kennzAdNode->addChild(new XMLNode('typ', $kennzAd->typ));
      $kennzAdNode->addChild(new XMLNode('kennz', $kennzAd->kennz));

      
      if ($pCorrectMode == 'insert') {
        
        $textNode = new XMLNode('text', '-', 'leer="true"');
        if ($kennzAd->text != '') {
          $textNode = new XMLNode('text', $kennzAd->text);
        }
        $kennzAdNode->addChild($textNode);
        $kennzAdNode->addChild(new XMLNode('bearbeiter', $kennzAd->bearbeiter));
        $kennzAdNode->addChild(new XMLNode('bearbdatum', $kennzAd->bearbdatum));
      }
      $nothingToDo = false;

      
      $message->addChild($kennzAdNode);
    }

    if (!$nothingToDo) {
      

      
      if ($pCorrectMode == 'delete') {
        $operation = AbgleichAPI::ABGLEICH_KENNZEICHENDELETE;
      } 
      else { 
        $operation = AbgleichAPI::ABGLEICH_KENNZEICHEN;
      } 
      

      $abgleichAPI = new AbgleichAPI();
      
      $abgleichAPI->sendeNachricht($operation, new Nutzlast($message));

      return 'sendDone';
    }

    return 'noCorrection';
  }

  
  private static function isDubletteBasicEqual($tnOrig, $tnDublette): bool
  {
    $mailTn = $tnDublette->getVarValueEx('email', 'Kommunikation');

    $origEmails = array();
    if (!empty($tnOrig->id) && $tnOrig->id > 0) {
      $dbwKomms = \DBWorkKommunikation::getDefaultInstance();
      $emails = $dbwKomms->getKommunikationByNrTypArt($tnOrig->id, $tnOrig->getDbTyp(), 'E');
      $origEmails = \array_filter(\ArrayOperations::mapAttribut($emails, 'wert'));
      if (!empty($origEmails)) {
        $origEmails[] = '';
      }
    }

    return $tnOrig->name == $tnDublette->name
      && $tnOrig->vorname == $tnDublette->vorname
      && in_array($mailTn, $origEmails);
  }

  
  public static function isDublette($pTeilnehmer, $pAlgorithmus = false)
  {
    $abgleichAPI = new AbgleichAPI();
    if (!$abgleichAPI->isAktiviert()) {
      return 'nichtAktiviert';
    }

    $message = new XMLNode('teilnehmer');

    $datamodulNode = $pTeilnehmer->ToXml(
      array('aryattachments', 'arykennzeichenJS', 'aryattachmentsJS', 'uploadAttachments'),
      true,
      array(),
      'teilnehmer'
    );

    
    $message->addChild($datamodulNode);

    $nutzlast = new Nutzlast($message);

    if (false !== $pAlgorithmus) {
      $algoNode = new XMLNode('algorithm', $pAlgorithmus);
      $nutzlast->addNode($algoNode);
    }

    
    $result = $abgleichAPI->sendeNachricht(
      AbgleichAPI::ABGLEICH_TEILNEHMER_IS_DUBLETTE,
      $nutzlast
    );

    if ($result->code == AbgleichApiResult::CODE_DUPLICATE) {
      $matches = array();
      if (preg_match_all('/\\d+/', $result->reason, $matches)) {
        $idResult = array('sqlid' => $matches[0][0], 'replikatid' => $matches[0][1]);
        if ($idResult['sqlid'] == $idResult['replikatid']) {
          $dbwRepSettings = DBWorkWebReplikatSettings::getDefaultInstance();
          if (!$dbwRepSettings->isOldTN($idResult['replikatid'])) {
            
            
            
            $dbwtn = DBWorkTeilnehmer::getDefaultInstance();
            $tn = $dbwtn->getTeilnehm($idResult['replikatid']);
            if (!static::isDubletteBasicEqual($tn, $pTeilnehmer)) {
              $idResult['replikatid'] = 0;
            }
          }
        }

        return $idResult;
      }
    }
    if ($result->code == AbgleichApiResult::CODE_SUCCESS) {
      if ($result->errorType == AbgleichApiResult::TEILNEHMER_NICHT_VORHANDEN) {
        return array('sqlid' => false, 'replikatid' => false);
      }
    }
    $reason = print_r($result, true);
    Logger::logg('unvorgesehener Fall bei TeilnehmerAPI::isDublette() ' . $reason, 600);

    throw new Exception('Invalid State: unvorgesehener Fall bei TeilnehmerAPI::isDublette() - ' . $reason);
  }

  
  public static function isKindDublette($pTeilnehmerKind, $mssqlidElternteil)
  {
    $abgleichAPI = new AbgleichAPI();
    if (!$abgleichAPI->isAktiviert()) {
      return 'nichtAktiviert';
    }

    $message = new XMLNode('teilnehmer');

    $kindNode = $pTeilnehmerKind->ToXml(array('aryattachments', 'arykennzeichenJS', 'aryattachmentsJS'), true, array(), 'teilnehmer');
    $elternteilNode = new XMLNode('mssqlidElternteil', $mssqlidElternteil);
    $kindNode->addChild($elternteilNode);

    $message->addChild($kindNode);
    $nutzlast = new Nutzlast($message);

    
    $result = $abgleichAPI->sendeNachricht(
      AbgleichAPI::ABGLEICH_TEILNEHMER_IS_DUBLETTE_ELTERN_KIND,
      $nutzlast
    );

    if ($result->code == AbgleichApiResult::CODE_DUPLICATE) {
      $matches = array();
      if (preg_match_all('/\\d+/', $result->reason, $matches)) {
        $idResult = array('sqlid' => $matches[0][0], 'replikatid' => $matches[0][1]);
        if ($idResult['sqlid'] == $idResult['replikatid']) {
          $dbwRepSettings = DBWorkWebReplikatSettings::getDefaultInstance();
          if (!$dbwRepSettings->isOldTN($idResult['replikatid'])) {
            
            
            
            $dbwtn = DBWorkTeilnehmer::getDefaultInstance();
            $tn = $dbwtn->getTeilnehm($idResult['replikatid']);
            if (!static::isDubletteBasicEqual($tn, $pTeilnehmerKind)) {
              $idResult['replikatid'] = 0;
            }
          }
        }

        return $idResult;
      }
    }
    if ($result->code == AbgleichApiResult::CODE_SUCCESS) {
      if ($result->errorType == AbgleichApiResult::TEILNEHMER_NICHT_VORHANDEN) {
        return array('sqlid' => false, 'replikatid' => false);
      }
    }
    $reason = print_r($result, true);
    Logger::logg('unvorgesehener Fall bei TeilnehmerAPI::isDublette() ' . $reason, 600);

    throw new Exception('Invalid State: unvorgesehener Fall bei TeilnehmerAPI::isDublette() - ' . $reason);
  }

  
  public static function fuelleSonstigeTeilnehmerDaten($pTeilnehmer, $pDbTyp)
  {
    $teilnehmer = $pTeilnehmer;

    $dbbasysuser = new DBWorkBASysUser($pDbTyp, true);
    $benutzer = SessionOperations::getCurrentWebToolsUser();
    $basysbenutzer = $dbbasysuser->getBASysUser($benutzer->ben);
    $teilnehmer->erstelltvon = $basysbenutzer->kennung;
    $teilnehmer->erstelltdatum = DateTimeOperations::getDateNow();
    if (!isset($teilnehmer->suchbegriff) || trim($teilnehmer->suchbegriff) === '') {
      $teilnehmer->suchbegriff = StringOperations::substr(StringOperations::strtoupper($teilnehmer->name), 0, 16); 
    }
    $teilnehmer->name_vorname = StringOperations::strtoupper($teilnehmer->name) . '  ' . StringOperations::strtoupper($teilnehmer->vorname) . '_' . $teilnehmer->id; 

    if ($teilnehmer->dse_unterschrieben_datum !== '' || $teilnehmer->dse_unterschrieben_weg !== '') {
      $teilnehmer->dse_unterschrieben_bearbeiter = $basysbenutzer->kennung;
      if ($teilnehmer->dse_unterschrieben_datum === '') {
        $teilnehmer->dse_unterschrieben_datum = DateTimeOperations::getDateTimeNow();
      }
    }

    if ($teilnehmer->dse_widerrufen_datum !== '' || $teilnehmer->dse_widerrufen_weg !== '') {
      $teilnehmer->dse_widerrufen_bearbeiter = $basysbenutzer->kennung;
      if ($teilnehmer->dse_widerrufen_datum === '') {
        $teilnehmer->dse_widerrufen_datum = DateTimeOperations::getDateTimeNow();
      }
    }

    return $teilnehmer;
  }

  
  public static function aktualisiereBerechneteTeilnehmerDaten($pOrigTeilnehmer, $pTeilnehmer, $pBenutzerKuerzel)
  {
    $changedFields = array();
    $pTeilnehmer->name_vorname = StringOperations::strtoupper($pTeilnehmer->name) . '  ' . StringOperations::strtoupper($pTeilnehmer->vorname) . '_' . $pTeilnehmer->id; 

    if (StringOperations::substr(StringOperations::strtoupper($pOrigTeilnehmer->name), 0, 16) == $pTeilnehmer->suchbegriff) {
      $pTeilnehmer->suchbegriff = StringOperations::substr(StringOperations::strtoupper($pTeilnehmer->name), 0, 16); 
      $changedFields[] = 'suchbegriff';
    }

    if ($pOrigTeilnehmer->ansprache !== '' && $pOrigTeilnehmer->ansprache == $pTeilnehmer->ansprache) {
      $pTeilnehmer->ansprache = str_replace($pOrigTeilnehmer->name, $pTeilnehmer->name, $pTeilnehmer->ansprache);
      $pTeilnehmer->ansprache = str_replace($pOrigTeilnehmer->vorname, $pTeilnehmer->vorname, $pTeilnehmer->ansprache);
      $changedFields[] = 'ansprache';
    }

    if ($pOrigTeilnehmer->dse_unterschrieben_datum !== $pTeilnehmer->dse_unterschrieben_datum
            || $pOrigTeilnehmer->dse_unterschrieben_weg !== $pTeilnehmer->dse_unterschrieben_weg) {
      $pTeilnehmer->dse_unterschrieben_bearbeiter = $pBenutzerKuerzel;
      $changedFields[] = 'dse_unterschrieben_bearbeiter';
      if ($pTeilnehmer->dse_unterschrieben_datum === '' && $pTeilnehmer->dse_unterschrieben_weg !== '') {
        $pTeilnehmer->dse_unterschrieben_datum = DateTimeOperations::getDateTimeNow();
        $changedFields[] = 'dse_unterschrieben_datum'; 
      }
    }

    if ($pOrigTeilnehmer->dse_widerrufen_datum !== $pTeilnehmer->dse_widerrufen_datum
            || $pOrigTeilnehmer->dse_widerrufen_weg !== $pTeilnehmer->dse_widerrufen_weg) {
      $pTeilnehmer->dse_widerrufen_bearbeiter = $pBenutzerKuerzel;
      $changedFields[] = 'dse_widerrufen_bearbeiter';
      if ($pTeilnehmer->dse_widerrufen_datum === '' && $pTeilnehmer->dse_widerrufen_weg !== '') {
        $pTeilnehmer->dse_widerrufen_datum = DateTimeOperations::getDateTimeNow();
        $changedFields[] = 'dse_widerrufen_datum'; 
      }
    }

    return array('teilnehmer' => $pTeilnehmer, 'changedFields' => array_unique($changedFields));
  }

  
  public static function getTeilnehmerInfosPerDMZ($pTnId, $pNoMapping = false)
  {
    $abgleichAPI = new AbgleichAPI();
    $message = new XMLNode('teilnehmer');
    $message->addChild(new XMLNode('id', $pTnId, '', '', true));
    $nutzlast = new Nutzlast($message);
    if ($pNoMapping) {
      $nutzlast->addNode(new XMLNode('nomapping', 'W'));
    }
    $result = $abgleichAPI->sendeNachricht(
      AbgleichAPI::ABGLEICH_GET_TEILNEHMER,
      $nutzlast
    );
    $teilnehmerOriginalInfos = JsonOperations::getFromString($result->reason);
    if (is_null($teilnehmerOriginalInfos)) {
      return new Teilnehmer();
    }
    $tn = Datamodul::toDatamodul('Teilnehmer', $teilnehmerOriginalInfos);
    $tn->tnr = $teilnehmerOriginalInfos->tnr;

    return $tn;
  }

  
  public static function eMailBeiDublette($pTeilnehmer, $pTeilnehmerMSSQLInfosForEmail, $pKommunikationMSSQLInfos, $pIsAbwZahler = false)
  {
    
    if (DBWorkBASysSettings::isInnsbruckStadt()) {
      return false;
    }

    $allgsettings = AllgSettingsAPI::getAllgSettings();
    $tool0Settings = ToolSettingsAPI::getToolSettings(0);
    
    $emailadr = ($tool0Settings->stammhoererDatenAendernEmailAddresse == '') ? $allgsettings->vhsemail : $tool0Settings->stammhoererDatenAendernEmailAddresse;
    $teilnehmer = clone $pTeilnehmer;
    $oldData = $pTeilnehmerMSSQLInfosForEmail;
    $oldData = self::_ordneKommunikationZu($oldData, $pKommunikationMSSQLInfos);

    $excludeAry = array('blz', 'konto', 'bankbez', 'bic', 'iban', 'kontoinhaber'); 
    $abweichendeTeilnehmerdaten = self::vergleicheTeilnehmerdaten($teilnehmer, $oldData, $excludeAry);
    if ((count($abweichendeTeilnehmerdaten) > 0)) {
      $title = 'Sofort eingebucht: Teilnehmer ' . ($pIsAbwZahler ? '(abw. Zahler) ' : '') . $oldData->vorname . ' ' . $oldData->name . ' (Nr.:' . $oldData->tnr . ') als Dublette erkannt / Von vorhandenen Informationen abweichende Teilnehmerdaten';
      $content = self::_getEmailContent($abweichendeTeilnehmerdaten, $oldData, $teilnehmer, $pIsAbwZahler);
      $email = new smtpMail();
      $email->SetVar2Value('to', $emailadr);
      $email->SetVar2Value('subject', $title);
      $email->SetVar2Value('contenttype', SMTP_CONTENTTYPE_HTML);
      $email->SetVar2Value('body', $content);
      $sent = $email->sendMail();
      LoggerAnmeldung::logg('E-Mail wegen abweichender Dublettendaten versendet.', 80);

      return $sent;
    }
    LoggerAnmeldung::logg('Dublettendaten unverändert.', 80);

    return false; 
  }

  private static function _getEmailContent($abweichendeTeilnehmerdaten, $oldData, $newData, $pIsAbwZahler)
  {
    $content = '<p>Der Teilnehmer ' . ($pIsAbwZahler ? '(abw. Zahler) ' : '') . '<b>' . $oldData->vorname . ' ' . $oldData->name . '</b> mit Teilnehmernr. <b>' . $oldData->tnr . '</b> wurde über das Web angemeldet und für ihn existieren bereits Daten in KuferSQL. Es wurden folgende abweichende Daten angegeben:</p>';
    $content .= '<br>';
    $content .= '<pre>'
        . '<font font-family="Courier New">';
    foreach ($abweichendeTeilnehmerdaten as $varname => $value) {
      if (StringOperations::startsWith($varname, 'tel')) {
        $content .= '<font color="#ff0000">neue Telefon-Nr.: ' . $newData->{$varname} . '</font>';
      } elseif (StringOperations::startsWith($varname, 'fax')) {
        $content .= '<font color="#ff0000">neue Fax-Nr.: ' . $newData->{$varname} . '</font>';
      } elseif (StringOperations::startsWith($varname, 'mobil')) {
        $content .= '<font color="#ff0000">neue Mobil-Nr.: ' . $newData->{$varname} . '</font>';
      } elseif (StringOperations::startsWith($varname, 'email')) {
        $content .= '<font color="#ff0000">neue E-Mail-Adresse: ' . $newData->{$varname} . '</font>';
      } else {
        $varnameAnzeige = TeilnehmerPflicht::getVarnameAnzeigbar($varname);
        $content .= '<font color="#ff0000">' . $varnameAnzeige . ' neu: </font>';
        if (property_exists($newData, $varname) && $newData->{$varname} instanceof Kommunikation) {
          $content .= $newData->{$varname}->wert;
        } else {
          $content .= property_exists($newData, $varname) ? TeilnehmerPflicht::getVarValueAnzeigbar($varname, $newData->{$varname}) : '';
        }

        switch ($varname) {
          default: $wert = property_exists($oldData, $varname) ? $oldData->{$varname} : '';
            break;
          case 'nurplz': $wert = StringOperations::getPLZ($oldData->ort);
            break;
          case 'nurort': $wert = StringOperations::getOrt($oldData->ort);
            break;
          case 'nurhausnr': $wert = StringOperations::getHausnr($oldData->strasse);
            break;
          case 'nurstrasse': $wert = StringOperations::getStrasse($oldData->strasse);
            break;
            
            
        }

        $content .= '<br>';
        $content .= $varnameAnzeige . ' alt: ';
        if ($wert != '' && $wert instanceof Kommunikation) {
          $content .= $wert->wert;
        } else {
          $content .= TeilnehmerPflicht::getVarValueAnzeigbar($varname, $wert); 
        }
      }
      $content .= '<br><br>';
    }
    $content .= '</font>'
        . '</pre>';

    return $content;
  }

  
  public static function erweitereTeilnehmerPflichtUmKommunikation($pTeilnehmerpflicht, $pGruppierteKommunikationsEintraege)
  {
    $teilnehmerpflicht = $pTeilnehmerpflicht;
    $map = array('E' => 'email', 'F' => 'fax', 'M' => 'mobil', 'T' => 'tel');
    foreach ($map as $art => $varname) {
      if (isset($pGruppierteKommunikationsEintraege[$art])) {
        foreach ($pGruppierteKommunikationsEintraege[$art] as $key => $kommunikation) {
          $zahl = ($key > 0) ? $key + 1 : '';

          
          if ($varname == 'email') {
            $attributeName = $zahl === '' ? $varname : $varname . '_' . $zahl;
          } else {
            $attributeName = $varname . $zahl;
          }
          $teilnehmerpflicht->{$attributeName} = $kommunikation->Wert;
        }
      }
    }

    return $teilnehmerpflicht;
  }

  
  private static function _ordneKommunikationZu($pTeilnehmerPflicht, $pKommunikationMSSQLInfos)
  {
    $teilnehmerpflicht = $pTeilnehmerPflicht;
    $sortierteKommunikation = KommunikationsAPI::sortKommunikationen($pKommunikationMSSQLInfos);
    $gruppierteKommunikationsEintraege = KommunikationsAPI::gruppiereKommunikationenNachArt($sortierteKommunikation);

    return self::erweitereTeilnehmerPflichtUmKommunikation($teilnehmerpflicht, $gruppierteKommunikationsEintraege);
  }

  
  public static function vergleicheTeilnehmerdaten($pTNPflichtWeb, $pTNPflichtMSSQL, $pExcludeAry = array())
  {
    $tool0Settings = ToolSettingsAPI::getToolSettings(0);

    $dbwHlEmailXml = new DBWorkHLEmailXML();
    $fieldsToCheck = $dbwHlEmailXml->getHlEmailXmlPruefen();

    if (!empty($tool0Settings->unterschiedsPruefungFelder)) {
      $fieldsToCheck = array_merge($fieldsToCheck, explode(',', $tool0Settings->unterschiedsPruefungFelder));
    }

    $result = array();
    foreach ($fieldsToCheck as $field) {
      $fieldName = is_string($field) ? $field : $pTNPflichtWeb->getTnVarnameFromHlEmailXml($field);
      if (is_null($fieldName) || in_array($fieldName, $pExcludeAry)) {
        continue;
      }

      if (is_array($fieldName)) {
        foreach ($fieldName as $entry) {
          $valueWeb = self::getDefaultValueIfEmpty($pTNPflichtWeb->getTyp($entry), $pTNPflichtWeb->{$entry});
          $kommAry = self::getKommAry($entry, $pTNPflichtMSSQL);
          if ($valueWeb != '' && !in_array($valueWeb, $kommAry)) {
            $result[$entry] = $valueWeb;
          }
        }
      } else {
        $valueWeb = trim(self::getDefaultValueIfEmpty($pTNPflichtWeb->getTyp($fieldName), $pTNPflichtWeb->{$fieldName}));
        $valueMSSQL = trim(self::getDefaultValueIfEmpty($pTNPflichtMSSQL->getTyp($fieldName), $pTNPflichtMSSQL->{$fieldName}));
        if ($valueWeb != $valueMSSQL) {
          $result[$fieldName] = $valueWeb;
        }
      }
    }

    return $result;
  }

  
  private static function getKommAry($pVarname, $pTNPflichtMSSQL)
  {
    $result = array();

    if (StringOperations::startsWith($pVarname, 'tel')) {
      $result = $pTNPflichtMSSQL->getAllKommEintraege('tel');
    } elseif (StringOperations::startsWith($pVarname, 'fax')) {
      $result = $pTNPflichtMSSQL->getAllKommEintraege('fax');
    } elseif (StringOperations::startsWith($pVarname, 'mobil')) {
      $result = $pTNPflichtMSSQL->getAllKommEintraege('mobil');
    } elseif (StringOperations::startsWith($pVarname, 'email')) {
      $result = $pTNPflichtMSSQL->getAllKommEintraege('email');
    }

    return $result;
  }

  
  private static function getDefaultValueIfEmpty($pTyp, $pValue)
  {
    if (empty($pValue)) {
      if ($pTyp == \DatamodulVarType::TYPE_INT || $pTyp == \DatamodulVarType::TYPE_FLOAT) {
        $pValue = 0;
      } elseif ($pTyp == \DatamodulVarType::TYPE_BOOL_WF) {
        $pValue = 'F';
      } elseif ($pTyp == \DatamodulVarType::TYPE_DATE) {
        $pValue = DEFAULTDATE;
      } else {
        $pValue = '';
      }
    }

    return $pValue;
  }

  
  public static function getTeilnehmerQualifikationen($tnr, $status = 'A')
  {
    static $cache = array();

    if (!isset($cache[$tnr])) {
      $cache[$tnr] = 'error';
      $message = new XMLNode('teilnehmer');
      $tnrNode = new XMLNode('nr', $tnr);
      $message->addChild($tnrNode);
      $statusNode = new XMLNode('status', $status);
      $message->addChild($statusNode);
      $abgleichAPI = new AbgleichAPI();
      $result = $abgleichAPI->sendeNachricht(
        AbgleichAPI::ABGLEICH_GET_TEILNEHMER_QUALIFIKATIONEN,
        new Nutzlast($message)
      );

      
      
      $cache[$tnr] = JsonOperations::getFromString($result->reason);
    }
    if ($cache[$tnr] == 'error') {
      throw(new Exception('TeilnehmerAPI::getTeilnehmerQualifikationen: Es gab beim vorigen Aufruf der DMZ einen Fehler, daher wird der DMZ-Aufruf nicht wiederholt.'));
    }

    return $cache[$tnr];
  }

  public static function insertDmzMappingAnhandGuid(\TeilnehmerParent $teilnehmer)
  {
    $teilnehmerNode = new XMLNode('teilnehmer');
    $teilnehmerNode->addChild(new XMLNode('mysqlid', $teilnehmer->getDMZValue('id')));
    $teilnehmerNode->addChild(new XMLNode('guid', $teilnehmer->getDMZValue('guid')));

    
    $message = new XMLNode('teilnehmerContainer');
    $message->addChild($teilnehmerNode);

    $abgleichAPI = new AbgleichAPI();
    
    $abgleichAPI->sendeNachricht(AbgleichAPI::ABGLEICH_INSERT_TEILNEHMER_MAPPING_ANHAND_GUID, new Nutzlast($message));
  }
}