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


class DBWorkKurseTageMin extends DBWorkStrict
{
  
  public $dbwkurse;
  
  public $dbwkursorte;
  
  public $dbwdozenten;
  
  public $toolsettings;
  
  public $minselect;
  
  protected $addKurstagWithSelectedStatus;

  
  protected $withoutDozentenUrlaube;

  protected static $_cache_KursTage = array();

  
  public function __construct($pDBTyp = 1, $newInstance = false, $pNoInternetCare = false, $pAddKurstagWithSelectedStatus = true, $pWithoutDozentenUrlaube = true)
  {
    parent::__construct($pDBTyp, $newInstance);
    $this->dbwkurse = new DBWorkKurse($this->dbtyp, true);
    $this->dbwkursorte = new DBWorkKursorte($this->dbtyp, true);
    
    $this->dbwdozenten = new DBWorkDozenten($this->dbtyp, true, $pNoInternetCare);
    $this->select = 'kt.id,kt.knr,kt.dnr,kt.ort, kt.datum,kt.zeit_beg,kt.zeit_ende, kt.ausf,kt.nodoztool,kt.notntool,kt.wotag ';
    
    
    $this->minselect = 'kt.id,kt.knr,kt.dnr,kt.ort,kt.datum,kt.zeit_beg,kt.zeit_ende, kt.ausf,kt.nodoztool,kt.notntool,kt.wotag ';
    
    $this->addKurstagWithSelectedStatus = $pAddKurstagWithSelectedStatus;
    $this->withoutDozentenUrlaube = $pWithoutDozentenUrlaube;

    $toolid = RequestOperations::getVarValue('tool_id', 4);
    
    if (RequestOperations::isDefined('toolid')) {
      $toolid = RequestOperations::getVarValue('toolid');
    }

    $this->toolsettings = ToolSettingsAPI::getToolSettings($toolid);
    
  }

  
  public function newSearch(): void
  {
    parent::newSearch();
    $this->toobject->dnr = -1;
    $this->fromobject->dnr = -1;
  }

  
  public function getNewObject()
  {
    $kt = new Kurstag();
    $kt->kurs = new Kurs();
    $kt->dozent = new Dozent();
    $kt->kursort = new Kursort();

    return $kt;
  }

  public function getTableName(): string
  {
    return 'kurstage';
  }

  
  public function filterExcludeStatus()
  {
    $this->addKurstagWithSelectedStatus = false;
  }

  public function getOnlyIds($dbwFunction, $params)
  {
    $select = $this->select;
    $this->select = 'kt.id';
    $kurstage = call_user_func_array($dbwFunction, $params);
    $this->select = $select;

    return ArrayOperations::mapAttribut($kurstage, 'id');
  }

  
  public function getCurrentRow($pRefreshCache = false)
  {
    $tmp = $this->getNewObject();
    $tmp->id = $this->getDatamodulValue('id');
    $tmp->knr = $this->getDatamodulValue('knr');
    $tmp->dnr = $this->getDatamodulValue('dnr');
    $tmp->invisibleDnr = $tmp->dnr;
    $tmp->ort = $this->getDatamodulValue('ort');
    $tmp->datum = $this->getDatamodulValue('datum');
    $tmp->datum_kurz = $this->datetimeop->getShortForm4DateStr(
      $this->getDatamodulValue('datum')
    );
    $tmp->wotag = $this->getDatamodulValue('wotag');
    $tmp->wotagkurz = $this->datetimeop->getWeekDayShort($tmp->datum);
    $tmp->wotaglang = $this->datetimeop->getWeekDay($tmp->datum);

    $tmp->datum_jahrkurz = $this->datetimeop->getShortForm4DateStr($tmp->datum);
    $tmp->datum_komplettlang = $tmp->wotaglang . ', ' . $tmp->datum;
    $tmp->datum_komplettkurz = $tmp->wotagkurz . ', ' . $tmp->datum;
    $tmp->datum_komplettkurz_jahrkurz = $tmp->wotagkurz . ', ' . $tmp->datum_jahrkurz;

    $tmp->zeit_beg = $this->getDatamodulValue('zeit_beg');
    $tmp->zeit_ende = $this->getDatamodulValue('zeit_ende');
    $tmp->zeit_beg_ende = $tmp->zeit_beg . ' - ' . $tmp->zeit_ende;
    $tmp->datum_komplettkurz_jahrkurz_beg_ende = $tmp->datum_komplettkurz_jahrkurz . ' ' . $tmp->zeit_beg_ende;
    $tmp->ausfall = $this->getDatamodulValue('ausf');
    if ($tmp->ausfall == ' ') {
      $tmp->ausfall = '';
    }
    $tmp->invisibleAusfall = $tmp->ausfall;
    $tmp->kursortstrasse = '';

    $tmp->geprueft_3g = $this->getDatamodulValue('geprueft_3g');

    return $tmp;
  }

  

  protected function postGetAllRowsHook($pDatamodules, $pRefreshCache = false)
  {
    
    $datamodule = parent::postGetAllRowsHook($pDatamodules, $pRefreshCache);

    $kursnummern = \ArrayOperations::mapUniqueAttribute($datamodule, 'knr');
    $kurse = $this->dbwkurse->getKurseByKursnummernKeepOrder($kursnummern, $pRefreshCache);
    $kurseByKnr = ArrayOperations::setAttributAsKey($kurse, 'id');

    $mkTexte = ArrayOperations::mapAttribut($datamodule, 'ort');
    $kursorte = $this->dbwkursorte->getKursorteByMktext($mkTexte);
    foreach ($kursorte as $kursort) {
      $kursort->mktext = trim($kursort->mktext);
    }
    
    $kursorteByMkText = ArrayOperations::setAttributAsKey($kursorte, 'mktext');


    $dozAnzeigeErlaubtByKnrDnr = $this->dbwdozenten->getDozAnzeigeErlaubtMatrixKnrDnr($datamodule);

    $dnrs = ArrayOperations::mapAttribut($datamodule, 'dnr');
    $dozenten = $this->dbwdozenten->getDozentenByIDArray($dnrs, $pRefreshCache);
    $dozentenByDnr = ArrayOperations::setAttributAsKey($dozenten, 'id');


    foreach ($datamodule as $kurstag) {
      if (isset($kurseByKnr[$kurstag->knr])) {
        $kurstag->kurs = $kurseByKnr[$kurstag->knr];
      } 
      if (array_key_exists(trim($kurstag->ort), $kursorteByMkText)) {
        $kurstag->kursort = ($kursorteByMkText[$kurstag->ort] ?? $kursorteByMkText[\trim($kurstag->ort)]) ?? new \Kursort();
      } else {
        $kurstag->kursort = new \Kursort();
      }
      if ($kurstag->kursort->strasse == '') {
        $kurstag->kursortstrasse = $kurstag->ort;
      } else {
        $kurstag->kursortstrasse = $kurstag->kursort->strasse;
      }

      if (isset($dozentenByDnr[$kurstag->dnr], $dozAnzeigeErlaubtByKnrDnr[$kurstag->knr], $dozAnzeigeErlaubtByKnrDnr[$kurstag->knr][$kurstag->dnr])) {
        $kurstag->dozent = $dozentenByDnr[$kurstag->dnr];
      } else {
        $kurstag->dozent = $this->dbwdozenten->getNewObject();
      }
    }

    return $datamodule;
  }

  
  public function translateVarName($varname)
  {
    switch ($varname) {
      
      default:             return parent::translateVarName($varname);
      case 'ausfall':      return 'ausf';
    }
  }

  
  public function canupdate($varname)
  {
    switch ($varname) {
      
      default:
        return parent::canupdate($varname);
      case 'id':
      case 'datum_kurz':
      case 'wotagkurz':
      case 'wotaglang':
      case 'kurs':
      case 'dozent':
      case 'kursort':
      case 'kursortstrasse':
      case 'invisibleAusfall':
      case 'datum_jahrkurz':
      case 'datum_komplettlang':
      case 'datum_komplettkurz':
      case 'datum_komplettkurz_jahrkurz':
      case 'datum_komplettkurz_jahrkurz_beg_ende':
      case 'zeit_beg_ende':
      case 'invisibleDnr':
      case 'rechnungStatus':
        return false;
    }
  }

  
  public function getSearchSQL($pPraefix, $pTageUebergreifend = false)
  {
    $praefix = $this->dboperation->getString4Sql($pPraefix);
    $sql = '';

    
    if ($this->withoutDozentenUrlaube) {
      $underscore = $this->dboperation->dbparser->escapeCharInLike('_');
      $sql .= ' AND NOT ' . $this->dboperation->dbparser->caseInsensitiveLike('kt.', 'knr', $underscore . $underscore . '%')
              . $this->dboperation->dbparser->escapeClauseForLike();
    }

    
    
    if (isset($this->toolsettings->colorkurstageausf) && $this->toolsettings->colorkurstageausf == '#blind') {
      $sql .= ' AND ' . $this->dboperation->dbparser->isNull('kt.ausf', '\'-\'') . ' <> \'A\'';
    }

    if (DBWorkBASysSettings::isWienUni()) {
      $sql .= ' AND ' . $this->dboperation->dbparser->isNull('kt.ausf', '\'-\'') . ' <> \'!\'';
    }

    if ((isset($this->fromobject)) && (isset($this->toobject))) {
      if ($this->fromobject->ausfall != '') {
        $normal = false;

        $ktStatusAry = \StringOperations::str_split($this->fromobject->ausfall);
        $s = (new \Kufer\Web\Classes\Stream\ArrayStream($ktStatusAry))
          ->map(static function(string $status): array {
            if ($status === '-') {
              return array(' ', '');
            } else {
              return array($status);
            }
          })
          ->flatten()
          ->toArray();

        
        
        $negation = '';
        if (!$this->addKurstagWithSelectedStatus) {
          $negation = 'NOT';
        }
        $orAusfIsNull = ' OR ' . $praefix . 'ausf IS NULL';

        $sql .= ' AND (' . $negation . '(' . $praefix . 'ausf IN (\'' . implode('\', \'', $s) . '\')';
        if ($normal && !$negation) {
          $sql .= $orAusfIsNull;
        }
        $sql .= ')';
        if (!$normal && $negation) {
          $sql .= $orAusfIsNull;
        }
        $sql .= ')' . PHP_EOL;
      } 

      if (isset($this->fromobject->dnr) && $this->fromobject->dnr != -1 && $this->fromobject->dnr != ''
         && isset($this->toobject->dnr) && $this->toobject->dnr != -1 && $this->toobject->dnr != ''
         && $this->fromobject->dnr == $this->toobject->dnr) {
        $sql .= ' AND ' . $praefix . 'dnr = ' . $this->getSQLValue('dnr', $this->fromobject);
      } else {
        if (isset($this->fromobject->dnr) && $this->fromobject->dnr != -1 && $this->fromobject->dnr != '') {
          $sql .= ' AND ' . $praefix . 'dnr >= ' . $this->getSQLValue('dnr', $this->fromobject);
        }
        if (isset($this->toobject->dnr) && $this->toobject->dnr != -1 && $this->toobject->dnr != '') {
          $sql .= ' AND ' . $praefix . 'dnr <= ' . $this->getSQLValue('dnr', $this->toobject);
        }
      }

      if (isset($this->fromobject->doz_namevorname) && $this->fromobject->doz_namevorname !== '') {
        $dbwDozenten = new DBWorkDozenten(1, true);
        $dbwDozenten->newSearch();
        $dbwDozenten->fromobject->namevorname = $this->fromobject->doz_namevorname;
        $dnrs = $dbwDozenten->getDozentenIdsbyFilter();

        if (count($dnrs) == 0) {
          $sql .= ' AND (1=0) '; 
        } else {
          $sql .= ' AND ' . $praefix . 'dnr IN (' . implode(', ', $dnrs) . ') ';
        }
      }

      
      
      
      


      
      $fromBeg = (isset($this->fromobject->zeit_beg) && $this->fromobject->zeit_beg != '');
      $fromEnd = (isset($this->fromobject->zeit_ende) && $this->fromobject->zeit_ende != '');
      $toBeg = (isset($this->toobject->zeit_beg) && $this->toobject->zeit_beg != '');
      $toEnd = (isset($this->toobject->zeit_ende) && $this->toobject->zeit_ende != '');
      if ($pTageUebergreifend
         && (isset($this->fromobject->datum) && $this->fromobject->datum != '')
         && (isset($this->toobject->datum) && $this->toobject->datum != '')
         && (($fromBeg && $toBeg) || ($fromEnd && $toEnd) || ($fromBeg && $toEnd) || ($fromEnd && $toBeg))
         && ($this->fromobject->datum != $this->toobject->datum)) {
        $sql .= ' AND (' . PHP_EOL;

        $sql .= '  (' . $praefix . 'datum = ' . $this->getSQLValue('datum', $this->fromobject);
        if ($fromBeg) {
          $sql .= ' AND ' . $praefix . 'zeit_beg >= ' . $this->getSQLValue('zeit_beg', $this->fromobject);
        }
        if ($fromEnd) {
          $sql .= ' AND ' . $praefix . 'zeit_ende > ' . $this->getSQLValue('zeit_ende', $this->fromobject);
        }
        $sql .= ')' . PHP_EOL;

        $sql .= '  OR (' . $praefix . 'datum = ' . $this->getSQLValue('datum', $this->toobject);
        if ($toBeg) {
          $sql .= ' AND ' . $praefix . 'zeit_beg < ' . $this->getSQLValue('zeit_beg', $this->toobject);
        }
        if ($toEnd) {
          $sql .= ' AND ' . $praefix . 'zeit_ende <= ' . $this->getSQLValue('zeit_ende', $this->toobject);
        }
        $sql .= ')' . PHP_EOL;

        $sql .= '  OR (' . $praefix . 'datum > ' . $this->getSQLValue('datum', $this->fromobject)
                  . ' AND ' . $praefix . 'datum < ' . $this->getSQLValue('datum', $this->toobject) . ')' . PHP_EOL;

        $sql .= ')' . PHP_EOL;
      } else {
        
        if (isset($this->fromobject->datum) && $this->fromobject->datum != '') {
          $sql .= ' AND ' . $praefix . 'datum >= ' . $this->getSQLValue('datum', $this->fromobject);
        }

        if (isset($this->toobject->datum) && $this->toobject->datum != '') {
          $sql .= ' AND ' . $praefix . 'datum <= ' . $this->getSQLValue('datum', $this->toobject);
        }

        
        
        if ($fromBeg && $this->fromobject->zeit_beg != '00:00') {
          $sql .= ' AND ' . $praefix . 'zeit_beg >= ' . $this->getSQLValue('zeit_beg', $this->fromobject);
        }
        if ($toBeg && $this->toobject->zeit_beg != '00:00') {
          $sql .= ' AND ' . $praefix . 'zeit_beg < ' . $this->getSQLValue('zeit_beg', $this->toobject);
        }
        if ($fromEnd) {
          $sql .= ' AND ' . $praefix . 'zeit_ende > ' . $this->getSQLValue('zeit_ende', $this->fromobject);
        }
        if ($toEnd) {
          $sql .= ' AND ' . $praefix . 'zeit_ende <= ' . $this->getSQLValue('zeit_ende', $this->toobject);
        }
      }

      
      
      if (isset($this->fromobject->ranzprognoanz) && $this->fromobject->ranzprognoanz) {
        $sql .= ' AND NOT ' . $praefix . 'ranzprognoanz = \'W\' ';
      }

      if ($this->fromobject->minuten > 0) {
        $sql .= ' AND ' . $praefix . 'minuten >= ' . $this->fromobject->minuten;
      }
      if ($this->toobject->minuten > 0) {
        $sql .= ' AND ' . $praefix . 'minuten <= ' . $this->toobject->minuten;
      }

      if (isset($this->fromobject->ort) && $this->fromobject->ort !== '') {
        $sql .= ' AND ' . $this->dboperation->dbparser->caseInsensitiveLike($praefix, 'ort', '%' . $this->fromobject->ort . '%');
      }

      if (isset($this->fromobject->text) && $this->fromobject->text !== '') {
        $sql .= ' AND ' . $this->dboperation->dbparser->caseInsensitiveLike($praefix, 'text', '%' . $this->fromobject->text . '%');
      }

      if (isset($this->toobject->nodoztool) && $this->toobject->nodoztool) {
        $sql .= ' AND ' . $this->dboperation->dbparser->isNull($praefix . 'nodoztool', '\'F\'') . ' <> \'W\'';
      }

      if (isset($this->toobject->notntool) && $this->toobject->notntool) {
        $sql .= ' AND ' . $this->dboperation->dbparser->isNull($praefix . 'notntool', '\'F\'') . ' <> \'W\'';
      }

      $sql = $this->beachteNoweb($sql, $praefix);

      if (isset($this->fromobject->bemerkungen) && $this->fromobject->bemerkungen !== '') {
        $sql .= ' AND ' . $this->dboperation->dbparser->caseInsensitiveLike($praefix, 'text', '%' . $this->fromobject->bemerkungen . '%');
      }

      
      if (isset($this->fromobject->faecher) && \is_array($this->fromobject->faecher) && !empty($this->fromobject->faecher)) {
        
        $tnFaecherStr = \StringOperations::convertArray2InList($this->dboperation->getInts4Sql($this->fromobject->faecher), true);
        $sql .= ' AND ' . $this->dboperation->dbparser->isNull($pPraefix . 'fachid', '0') . ' IN (' . $tnFaecherStr . ') ';
      }

      
      if (isset($this->fromobject->faecherOrig) && \is_array($this->fromobject->faecherOrig) && !empty($this->fromobject->faecherOrig)) {
        $tnOrigFacherStr = \StringOperations::convertArray2InList($this->dboperation->getInts4Sql($this->fromobject->faecherOrig));
        $sql .= ' AND ' . $this->dboperation->dbparser->isNull($pPraefix . 'fachid', '0') . ' IN ('
            . 'SELECT kurs_fach.id FROM kurs_fach WHERE kurs_fach.knr = kt.knr AND kurs_fach.fach_nr IN (' . $tnOrigFacherStr . ')'
          . ') ';
      }

      
      $dbwkursedetails = new DBWorkKurseINetAktivDetails();
      
      $dbwkursedetails->newSearch();
      if (isset($this->fromobject->kurs)) {
        $dbwkursedetails->fromobject = $this->fromobject->kurs;
      }
      if (isset($this->toobject->kurs)) {
        $dbwkursedetails->toobject = $this->toobject->kurs;
      }

      $dbwkursedetails->beratungstageKurseAusblenden = false;

      $sql .= ' ' . $dbwkursedetails->getSearchSQL('k.') . ' ';
    }

    return $sql;
  }

  
  protected function beachteNoweb($sql, $praefix)
  {
    return $sql;
  }

  
  public function getJoinPartner()
  {
    return '';
  }

  
  public function getSubselectPart($kurs_id, $pModifier = '')
  {
    $cleanKursId = $this->dboperation->getString4Sql($kurs_id);
    if ($this->dbwkurse->isKursgruppe($kurs_id)) {
      
      $result = '';
      if ($pModifier !== 'A') {
        $result .= ' and 0 = (SELECT COUNT(*) FROM kurstage kt2 WHERE kt2.datum=kt.datum AND kt2.zeit_beg=kt.zeit_beg AND kt2.zeit_ende=kt.zeit_ende';
        $result .= " AND kt2.knr<>'$cleanKursId' AND kt2.knr IN(" . SQLOperations::unterKursFromKursGruppePart($cleanKursId) . '))';
      }
      $result .= ')';
      $result .= $this->getSearchSQL('kt.') . '
                UNION
                SELECT ' . $this->minselect . "
                FROM kurstage kt
                left outer JOIN kurse k ON k.nr=kt.knr
                WHERE
                ((kt.knr <> '$cleanKursId') AND kt.knr IN(" . SQLOperations::unterKursFromKursGruppePart($cleanKursId) . ')';

      return $result;
    } else {
      return '';
    }
  }

  

  
  public function _isKurstagDifferent($pKTage, $pKTag, $pTerminAnzeigeKrit = '')
  {
    switch ($pTerminAnzeigeKrit) {
      default:
      case 'D':  

        foreach ($pKTage as $ktag) {
          
          
          
          if (($pKTag->datum == $ktag->datum) && ($pKTag->zeit_beg == $ktag->zeit_beg)
               && ($pKTag->zeit_ende == $ktag->zeit_ende) && ($pKTag->dnr == $ktag->dnr) && ($pKTag->knr == $ktag->knr)) {
            return false;
          }
        }
        break;
      case 'R':  
        foreach ($pKTage as $ktag) {
          
          
          
          if (($pKTag->datum == $ktag->datum) && ($pKTag->zeit_beg == $ktag->zeit_beg)
               && ($pKTag->zeit_ende == $ktag->zeit_ende) && ($pKTag->ort == $ktag->ort) && ($pKTag->knr == $ktag->knr)) {
            return false;
          }
        }
        break;

      case 'X': 
        
        
        foreach ($pKTage as $ktag) {
          if (($pKTag->datum == $ktag->datum) && ($pKTag->zeit_beg == $ktag->zeit_beg)
           && ($pKTag->zeit_ende == $ktag->zeit_ende) && ($pKTag->knr == $ktag->knr)) {
            return false;
          }
        }
        break;

      case 'K': 
        foreach ($pKTage as $ktag) {
          if ($pKTag->datum == $ktag->datum && $pKTag->knr == $ktag->knr) {
            return false;
          }
        }
        break;

      
    }  

    
    return true;
  }

  
  private function getBeginEndTime4Kompression($pKursTag, $pAllKursTage)
  {
    
    
    if (!is_array($pAllKursTage) || count($pAllKursTage) == 0) {
      return false;
    }

    $minBegin = $pKursTag->zeit_beg;
    $maxEnde = $pKursTag->zeit_ende;
    foreach ($pAllKursTage as $ktag) {
      if ($pKursTag->datum == $ktag->datum) {
        
        
        if ($ktag->zeit_beg < $minBegin) {
          $minBegin = $ktag->zeit_beg;
        }
        if ($ktag->zeit_ende > $maxEnde) {
          $maxEnde = $ktag->zeit_ende;
        }
      } 
    } 
    
    return array('minBeg' => $minBegin, 'maxEnd' => $maxEnde);
  }

  

  
  public function _isKurstagDifferentWT($pKTage, $pKTag)
  {
    foreach ($pKTage as $ktag) {
      if (($pKTag->datum == $ktag->datum) && ($pKTag->zeit_beg == $ktag->zeit_beg)
          && ($pKTag->zeit_ende == $ktag->zeit_ende) && ($pKTag->knr == $ktag->knr)) {
        return false;
      }
    }

    return true;
  }

  
  public function getKurstage()
  {
    $sql = $this->getKurstageSQLPart();

    $this->dboperation->clear();
    $this->dboperation->query($sql);

    return $this->getAllRows();
  }

  
  public function getKurstageSQLPart($pSelect = '')
  {
    $select = SecurityOperations::filterSQL($pSelect);
    if (empty($select)) {
      $select = $this->minselect;
    }

    $sql = 'SELECT ' . $select . ' ';
    $sql .= 'FROM kurstage kt ';
    $sql .= 'WHERE 1=1 ' . $this->getSearchSQL('kt.');

    return $sql;
  }

  
  public function getKurstageFromIDs($pKurstageIDAry, $pRefreshCache = false)
  {
    if (count($pKurstageIDAry) == 0) {
      return array();
    }

    $ktids = array();
    foreach ($pKurstageIDAry as $ktid) {
      $ktids[] = $this->dboperation->getInt4Sql($ktid);
    }

    static $cache = array();
    $retour = array();
    $tosearch = array();
    foreach ($ktids as $id) {
      if (!$pRefreshCache && isset($cache[$id])) {
        
      } else {
        $tosearch[] = $id;
      }
    }

    if (count($tosearch) === 0) {
      foreach ($ktids as $id) {
        $retour[] = $cache[$id];
      }

      return $retour;
    }

    
    $sql = 'SELECT ' . $this->select
           . ' FROM kurstage kt WHERE kt.id IN (' . StringOperations::convertArray2InList($tosearch) . ')';

    $this->dboperation->clear();
    $this->dboperation->query($sql);
    $dbresult = $this->getAllRows();

    if ($dbresult != null) {
      foreach ($dbresult as $kurstag) {
        $cache[$kurstag->id] = $kurstag;
      }

      foreach ($ktids as $ktid) {
        $retour[] = $cache[$ktid];
      }
    }

    return $retour;
  }

  
  public function getKurstageCountFromIDs($pKurstageIDAry)
  {
    if (count($pKurstageIDAry) == 0) {
      return array();
    }
    $ktids = array();
    foreach ($pKurstageIDAry as $ktid) {
      $ktids[] = $this->dboperation->getInt4Sql($ktid);
    }
    $sql = 'SELECT kt.id FROM kurstage kt WHERE kt.id IN (' . StringOperations::convertArray2InList($ktids) . ')';
    $this->dboperation->clear();
    $this->dboperation->query($sql);

    return $this->getAllRowsSingleColumn('id');
  }

  
  public function getKurstagebyKursNRDozIDOnlyDifferent($pKurs_Id, $pDnr, $pTerminAnzeigeKrit = '')
  {
    $KurstageIDAry = $this->getKurstagebyKursNRDozIDOnlyDifferentMin($pKurs_Id, $pDnr, $pTerminAnzeigeKrit);
    
    return $this->getKurstageFromIDs($KurstageIDAry);
  }

  
  public function getKurstagebyKursNRArrayDozIDOnlyDifferent($pKurs_Ids, $pDnr, $pTerminAnzeigeKrit = '')
  {
    if (!is_array($pKurs_Ids) || empty($pKurs_Ids)) {
      return array();
    }

    $kurstagIds = array();
    foreach ($pKurs_Ids as $kurs) {
      $kurstagIds = array_merge($kurstagIds, $this->getKurstagebyKursNRDozIDOnlyDifferentMin($kurs, $pDnr, $pTerminAnzeigeKrit));
    }

    
    
    return $this->getKurstageFromIDs(array_values(array_unique($kurstagIds)));
  }

  
  public function getKurstagebyKursNROnlyDifferent($pKurs_Id, $pTerminAnzeigeKrit = '', $pStatus = null, $excludedStatus = array())
  {
    $KurstageIDAry = $this->getKurstagebyKursNROnlyDifferentMin($pKurs_Id, $pStatus, $pTerminAnzeigeKrit, $excludedStatus);
    
    return $this->getKurstageFromIDs($KurstageIDAry);
  }

  
  public function getKurstagebyKursNROnlyDifferentLimit($pKurs_Id, $start_kt, $limit = 0, $forward = true)
  {
    
    
    if ($this->toolsettings->kfsTerminAnzeige == 'K') {
      return $this->getKurstagebyKursNROnlyDifferentLimitKomprMin($pKurs_Id, $start_kt, $limit, $forward);
    }
    $KurstageIDAry = $this->getKurstagebyKursNROnlyDifferentLimitMin($pKurs_Id, $start_kt, $limit, $forward);
    
    return $this->getKurstageFromIDs($KurstageIDAry);
  }

  
  public function getKurstagebyKursNRDozIDOnlyDifferentMin($pKurs_Id, $pDnr, $pTerminAnzeigeKrit = '')
  {
    
    $kurs_id = $this->dboperation->getString4Sql($pKurs_Id);
    
    $dnr = $this->dboperation->getInt4Sql($pDnr);
    
    $sql = 'SELECT ' . $this->minselect . " \n"
      . "  FROM kurstage kt \n" . $this->getJoinPartner()
      . "  WHERE (kt.knr = '" . $kurs_id . "' AND kt.dnr = " . $dnr;
    
    if ($this->dboperation->subselectPossible() && ToolSettingsAPI::getMitUnterKursenSetting()) {
      $sql .= $this->getSubselectPart($kurs_id, $pTerminAnzeigeKrit)
           . ' AND kt.dnr = ' . $dnr;
    }
    $sql .= ') ';
    $sql .= $this->getSearchSQL('kt.') . " \n"
              . $this->getCompleteOrderByDefault(array('datum', 'zeit_beg'));   

    $this->dboperation->clear();
    $this->dboperation->query($sql);

    $result = $this->getAllRows(); 
    $ktageIDAry = array();
    $ktage = array();
    if ($pTerminAnzeigeKrit == 'A') {
      
      foreach ($result as $ktag) {
        $ktageIDAry[] = $ktag->id;
      }
    } else {
      foreach ($result as $ktag) {
        
        
        if ($this->_isKurstagDifferent($ktage, $ktag, $pTerminAnzeigeKrit)) {
          array_push($ktage, $ktag);
          $ktageIDAry[] = $ktag->id;
        }
      }
    } 
    
    return $ktageIDAry;
  }

  
  public function getKurstagebyKursNROnlyDifferentMin($pKurs_Id, $pStati = null, $pTerminAnzeigeKrit = '', $excludeStatus = array())
  {
    
    $terminanzeigekrit = (isset($this->toolsettings->kfsTerminAnzeige) ? $this->toolsettings->kfsTerminAnzeige : '');
    if ($pTerminAnzeigeKrit != '') {
      $terminanzeigekrit = $pTerminAnzeigeKrit;
    }

    
    $result = $this->getSQLQueryResult4Kurstage($pKurs_Id, $terminanzeigekrit, false, $excludeStatus); 
    if ($terminanzeigekrit == 'A') {
      
      $ktage = $result;
    } else {
      $ktage = array();
      foreach ($result as $ktag) {
        
        
        if ($this->_isKurstagDifferent($ktage, $ktag, $terminanzeigekrit)) {
          array_push($ktage, $ktag);
        }
      } 
    } 

    $ktageIDAry = array();
    
    
    foreach ($ktage as $ktag) {
      
      
      
      if (is_array($pStati) && count($pStati) > 0) {
        if ($this->addKurstagWithSelectedStatus && in_array(trim($ktag->ausfall), $pStati)
            || !$this->addKurstagWithSelectedStatus && !in_array(trim($ktag->ausfall), $pStati)) {
          
          $ktageIDAry[] = $ktag->id;
        }
      }
      
      else {
        
        $ktageIDAry[] = $ktag->id;
      }
    } 
    
    return $ktageIDAry;
  }

  

  
  public function getKurstagebyKursNROnlyDifferentLimitMin($pKurs_Id, $start_kt, $limit = 0, $forward = true)
  {
    
    $result = $this->getSQLQueryResult4Kurstage($pKurs_Id, $this->toolsettings->kfsTerminAnzeige); 
    
    

    if ($this->toolsettings->kfsTerminAnzeige == 'A') {
      
      $ktage = $result;
    } else {
      $ktage = array();
      foreach ($result as $ktag) {
        
        
        if ($this->_isKurstagDifferent($ktage, $ktag, $this->toolsettings->kfsTerminAnzeige)) {
          array_push($ktage, $ktag);
        }
      } 
    } 

    
    if (!empty($start_kt) && $start_kt->id != '') {
      $ktary = $this->getLimitRowsinResult($ktage, $limit, $forward, $start_kt->id);
    } else {
      $ktary = $this->getLimitRowsinResult($ktage, $limit, $forward);
    }
    
    $ktageIDAry = array();
    foreach ($ktary as $kurstag) {
      $ktageIDAry[] = $kurstag->id;
    }
    
    return $ktageIDAry;
  }

  

  
  
  private function getLimitRowsinResult($opAry, $limit, $forward = true, $idvalue = '')
  {
    $ary = array();
    
    
    
    if ($limit <= 0) {
      return $opAry;
    }
    $rows = count($opAry);
    
    if ($rows <= $limit) {
      return $opAry;
    }
    
    if ($forward) {
      $zaehler = 0;
      if (!empty($idvalue)) {
        
        
        while (($opAry[$zaehler]->id != $idvalue) && ($zaehler <= $rows)) {
          $zaehler++;
        }
        if ($opAry[$zaehler]->id == $idvalue) {
          $zaehler++;
        }
      }
      $count = min($limit, ($rows - $zaehler));
      $count--;
      if ($rows > 0) {
        $ary = array($count);
        for ($i = 0;$i <= $count;$i++) {
          $ary[$i] = $opAry[$i + $zaehler];
        }
      }
      $this->countBefore = $zaehler;
    } else {
      $zaehler = $rows - 1;
      if (!empty($idvalue)) {
        while (($opAry[$zaehler]->id != $idvalue) && ($zaehler <= $rows)) {
          $zaehler--;
        }
        if ($opAry[$zaehler]->id == $idvalue) {
          $zaehler--;
        }
        $zaehler++;
      }
      $count = min($limit, $zaehler);
      if ($rows > 0) {
        $c = 0;
        for ($i = ($zaehler - $count);$i < $zaehler;$i++) {
          $ary[$c] = $opAry[$i];
          $c++;
        }
      }
      $this->countBefore = ($zaehler - $count);
    }
    $this->countBehind = max(0, ($rows - $this->countBefore - $limit));
    $this->countAll = $rows;

    return $ary;
  }

  
  public function getKurstagebyKursNROnlyDifferentLimitKomprMin($pKurs_Id, $start_kt, $limit = 0, $forward = true)
  {
    
    $result = $this->getSQLQueryResult4Kurstage($pKurs_Id, $this->toolsettings->kfsTerminAnzeige); 
    $ktage = array();
    foreach ($result as $ktag) {
      
      
      if ($this->_isKurstagDifferent($ktage, $ktag, $this->toolsettings->kfsTerminAnzeige)) {
        array_push($ktage, $ktag);

        
        
        $ZeitAry = $this->getBeginEndTime4Kompression($ktag, $result);
        if ($ZeitAry !== false) {
          $ktag->zeit_beg = $ZeitAry['minBeg'];
          $ktag->zeit_ende = $ZeitAry['maxEnd'];
        }
      } 
    } 

    
    if (!empty($start_kt) && $start_kt->id != '') {
      $ktary = $this->getLimitRowsinResult($ktage, $limit, $forward, $start_kt->id);
    } else {
      $ktary = $this->getLimitRowsinResult($ktage, $limit, $forward);
    }
    
    return $ktary;
  }

  

  
  public $disableCacheForGetSQLQueryResult4Kurstage = false;

  
  public function getSQLQueryResult4Kurstage($pKursId, $pModifier = '', $pRefreshCache = false, $excludeStatus = array())
  {
    
    $kurs_id = $this->dboperation->getString4Sql($pKursId);
    $cacheKey = $kurs_id . '__' . $pModifier;
    if ($this->disableCacheForGetSQLQueryResult4Kurstage || $pRefreshCache || !array_key_exists($cacheKey, self::$_cache_KursTage)) {
      $excludeStatusSqlStr = '';
      if (!empty($excludeStatus)) {
        $excludeStatusSqlStr = ' AND NOT ' . $this->createInStatement('kt.ausf', $excludeStatus);
      }

      $sql = 'SELECT ' . $this->minselect . " \n"
      . "  FROM kurstage kt \n" . $this->getJoinPartner()
      . "  WHERE (kt.knr = '" . $kurs_id . "'" . $excludeStatusSqlStr;
      
      
      
      if ($this->dboperation->subselectPossible() && ToolSettingsAPI::getMitUnterKursenSetting()) {
        
        
        $tmp = $this->dbwkurse;
        if (is_a($tmp, 'DBWorkKurseINetAktiv')) {
          $this->dbwkurse = new DBWorkKurse();
        }

        $sql .= $this->getSubselectPart($kurs_id, $pModifier);
      }
      $sql .= ') ';
      $sql .= $this->getSearchSQL('kt.') . " \n"
            . '  ORDER BY ' . $this->getOrderbyDefault('datum') . ', zeit_beg ASC';
      if (DBWorkBASysSettings::isAimHeilbronn()) {
        $sql .= ', ausf';
      }
      if ($this->dboperation->subselectPossible() && ToolSettingsAPI::getMitUnterKursenSetting()) {
        
        $this->dbwkurse = $tmp;
      }
      $this->dboperation->clear();
      $this->dboperation->query($sql);

      if ($this->disableCacheForGetSQLQueryResult4Kurstage) {
        return $this->getAllRows();
      }

      self::$_cache_KursTage[$cacheKey] = $this->getAllRows();
    }


    
    return self::$_cache_KursTage[$cacheKey];
  }

  
  public function getKurstageCountbyKursNROnlyDifferent($pKurs_id, $pStati = null)
  {
    
    $kurstage = $this->getKurstagebyKursNrOnlyDifferentMin($pKurs_id, $pStati);

    return count($kurstage);
  }

  public function getAllQuery(): \SelectQueryBuilder
  {
    return $this->getSelectQueryBuilder()
        ->select($this->select)
        ->from('kurstage', 'kt')
        ->orderBySrcCode(
          $this->getCompleteOrderByDefault(array('datum', 'zeit_beg'), 'kt')
        )
        ->paramRaw('table', 'kt');
  }

  public function findByFilterQuery(\Kufer\Web\Classes\Dbfilter\KurstageSQLFilter $filter): \SelectQueryBuilder
  {
    $condition = $filter->createSql($this->dboperation);

    return $this->getAllQuery()
      ->and($condition);
  }

  
  public function findByFilter(\Kufer\Web\Classes\Dbfilter\KurstageSQLFilter $filter): array
  {
    $builder = $this->findByFilterQuery($filter);

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    return $this->getAllRows();
  }

  
  public function countByFilter(\Kufer\Web\Classes\Dbfilter\KurstageSQLFilter $filter): int
  {
    $builder = $this->findByFilterQuery($filter)
      ->select('COUNT(*) AS anzahl');

    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQLForInnerQuery());

    $this->dboperation->selectrow(0);

    return (int)$this->getValue('anzahl', \DatamodulVarType::TYPE_INT);
  }

  public function getKurstageByTnLimitQuery($pTnr, $pKursNrAry = null): \SelectQueryBuilder
  {
    $builder = $this->getAllQuery()
      ->innerJoin('belegung b', 'kt.knr = b.knr')
      ->innerJoin('kurse k', 'kt.knr = k.nr')
      ->and('b.tnr = :tnr:')
      ->addToWhere($this->getSearchSQL('kt.'))
      ->paramInt('tnr', $pTnr);

    if (!empty($pKursNrAry)) {
      $builder = $builder->and('kt.knr IN (:kurseNrs:)')
          ->paramStringArray('kurseNrs', $pKursNrAry);
    }

    return $builder;
  }

  
  public function getKurstageByTnLimit($pTnr, $pStartKt = null, $pLimit = 0, $pForward = true, $pKursNrAry = null)
  {
    $builder = $this->getKurstageByTnLimitQuery($pTnr, $pKursNrAry);
    $this->dboperation->clear();
    $this->dboperation->query($builder->getSQL());

    if ($pLimit > 0) {
      if (isset($pStartKt) && $pStartKt->id != '') {
        $result = $this->getLimitRows($pLimit, $pForward, 'id', $pStartKt->id);
      } else {
        $result = $this->getLimitRows($pLimit, $pForward);
      }

      return $result;
    }

    return $this->getAllRows();
  }

  

  
  public function getKurstageByTnLimitOnlyDifferent($pTnr, $pStartKt, $pLimit = 0, $pForward = true, $pKursNrAry = null)
  {
    
    $ktAry = $this->getKurstageByTnLimit($pTnr, $pStartKt, 0, $pForward, $pKursNrAry);

    
    foreach ($ktAry as $key => $kt) {
      $tmp = $kt;
      unset($ktAry[$key]); 
      if ($this->_isKurstagDifferentWT($ktAry, $tmp)) {
        
        $ktAry[$key] = $tmp;
      }
    }

    
    if (!$pForward) { 
      $ktAry = array_reverse($ktAry);
    }

    
    $countBefore = 0;
    $countBehind = 0;

    
    $ktAbHier = !(isset($pStartKt) && $pStartKt->id != '');
    $ktDiffAry = array();

    foreach ($ktAry as $kt) {
      if (!$ktAbHier) { 
        if ($kt->id == $pStartKt->id) {
          $ktAbHier = true;
        }
        $countBefore++;
      } else {
        if ($pLimit == 0 || $pLimit > count($ktDiffAry)) {
          
          $ktDiffAry[] = $kt;
        } else {
          
          $countBehind++;
        }
      }
    } 
    if ($pForward) {
      $this->countBefore = $countBefore;
      $this->countBehind = $countBehind;
    } else {
      $this->countBefore = $countBehind;
      $this->countBehind = $countBefore;
      $ktDiffAry = array_reverse($ktDiffAry);
    }

    return $ktDiffAry;
  }

  
  public function getKurstageNrByTn($pTnr, $pKursNrAry = null)
  {
    if ($pTnr === '') {
      return array();
    }

    $tnr = $this->dboperation->getInt4Sql($pTnr);
    $joinKurse = '';
    if ($this->fromobject->kurs != null && !$this->fromobject->kurs->isEmpty()) {
      $joinKurse = 'join kurse k on kt.knr = k.nr ';
    }

    $sql = 'select kt.id from belegung b join kurstage kt on b.knr = kt.knr ' . $joinKurse . 'where b.tnr=' . $tnr
     . $this->getSearchSQL('kt.');

    
    if (!empty($pKursNrAry)) {
      $kursNrString = '';
      foreach ($pKursNrAry as $knr) {
        $kursNrString .= "'" . $knr . "',";
      }
      
      $kursNrString = StringOperations::substr($kursNrString, 0, -2) . "'";
      $sql .= ' AND kt.knr IN (' . $kursNrString . ')' . "\n";
    }


    $sql .= $this->getCompleteOrderByDefault(array('datum', 'zeit_beg'));

    $this->dboperation->clear();
    $this->dboperation->query($sql);

    return $this->getAllRowsSingleColumn('id');
  }

  
  public function getKurstageByDozLimit($pDoznr, $pStartKt, $pLimit = 0, $pForward = true, $pKursNrAry = null, $pIsAdmin = false)
  {
    if ($pDoznr === '') {
      return array();
    }

    $doznr = $this->dboperation->getInt4Sql($pDoznr);

    $zusatzSql1 = 'where dk.dozent=' . $doznr;
    $zusatzSql2 = ' AND ';
    if ($pIsAdmin) {
      $zusatzSql1 = ' ';
      $zusatzSql2 = ' WHERE ';
    }
    $sql = 'select ' . $this->select . ' from doz_kurs dk join kurstage kt on dk.kurs = kt.knr ' . $zusatzSql1
            . $this->getSearchSQL('kt.');
    $sql .= $zusatzSql2 . $this->dboperation->dbparser->isStringEmptyOrNull('dk.art'); 

    
    if (!empty($pKursNrAry)) {
      $kursNrString = '';
      foreach ($pKursNrAry as $knr) {
        $kursNrString .= "'" . $knr . "',";
      }
      
      $kursNrString = StringOperations::substr($kursNrString, 0, -2) . "'";
      $sql .= ' AND kt.knr IN (' . $kursNrString . ')' . "\n";
    }

    $sql .= $this->getCompleteOrderByDefault(array('datum', 'zeit_beg'));
    $this->dboperation->clear();
    $this->dboperation->query($sql);

    if ($pLimit > 0) {
      if (isset($pStartKt) && $pStartKt->id != '') {
        $result = $this->getLimitRows($pLimit, $pForward, 'id', $pStartKt->id);
      } else {
        $result = $this->getLimitRows($pLimit, $pForward);
      }

      return $result;
    }

    return $this->getAllRows();
  }

  
  public function getKurseTageByIds($pIds)
  {
    if (!is_array($pIds)) {
      throw new InvalidArgumentExceptionExtended('$pIds', $pIds, 'Der Parameter $pIds muss ein Array sein.');
    }

    if (count($pIds) == 0) {
      return array();
    }

    for ($i = 0; $i < count($pIds); ++$i) {
      $pIds[$i] = (int)$pIds[$i];
    }

    $in = $this->createInStatement('kt.id', $pIds);

    $sql = 'SELECT ' . $this->select . ' FROM kurstage kt WHERE ' . $in;
    $sql .= $this->getCompleteOrderByDefault('kt.datum');

    $this->dboperation->clear();
    $this->dboperation->query($sql);

    return $this->getAllRows();
  }
}