<?php
/**
 * @copyright (c) Kufer Software GmbH, Loisachstrasse 4, D-84453 Mühldorf
 */

namespace Kufer\Web\KuferTools\Utils\FilterSearch\Method;

use Kufer\Web\Classes\Dbfilter\ISQLFilter;
use Kufer\Web\KuferTools\Utils\FilterSearch\ISearchFilter;
use Kufer\Web\KuferTools\Utils\FilterSearch\ToolSearchFilter;

class ChildSearchFilter implements ISearchFilter
{
  
  protected $praeffix;

  
  protected $searchFilter;

  
  protected $sqlFilter;

  
  protected $fnApplyFilter;

  
  protected $fnIsSearchMapKey;

  
  protected $fnTransformSearchMapKey;

  
  protected $fnRetransformSearchMapKey;

  
  public function __construct(
    string $praeffix,
    ISearchFilter $searchFilter,
    ISQLFilter $sqlFilter,
    $fnApplyFilter,
    $fnIsSearchMapKey = null,
    $fnTransformSearchMapKey = null,
    $fnRetransformSearchMapKey = null
  ) {
    $this->praeffix = $praeffix;
    $this->searchFilter = $searchFilter;
    $this->sqlFilter = $sqlFilter;
    $this->fnApplyFilter = $fnApplyFilter;
    $this->fnIsSearchMapKey = $fnIsSearchMapKey ?? static::createIsSearchMapKey($praeffix);

    assert(is_null($fnTransformSearchMapKey) === is_null($fnRetransformSearchMapKey));
    $this->fnTransformSearchMapKey = $fnTransformSearchMapKey ?? static::createTransformSearchMap($praeffix);
    $this->fnRetransformSearchMapKey = $fnRetransformSearchMapKey ?? static::createRetransformSearchMap($praeffix);
  }

  public static function createIsSearchMapKey(string $praeffix): callable
  {
    return static function(string $str) use ($praeffix) {
      if ($praeffix === '') {
        return true;
      }

      return \StringOperations::startsWith($str, $praeffix . '_')
        && !\StringOperations::startsWith($str, $praeffix . '_' . $praeffix . '_'); 
    };
  }

  public static function createTransformSearchMap(string $praeffix): callable
  {
    return static function(string $str) use ($praeffix) {
      if ($praeffix === '') {
        return $str;
      }

      return \StringOperations::substr($str, \StringOperations::strlen($praeffix) + 1);
    };
  }

  public static function createRetransformSearchMap(string $praeffix): callable
  {
    return static function(string $str) use ($praeffix) {
      if ($praeffix === '') {
        return $str;
      }

      return $praeffix . '_' . $str;
    };
  }

  public function getSearchFilter(): ISearchFilter
  {
    return $this->searchFilter;
  }

  public function getSQLFilter(): ISQLFilter
  {
    return $this->sqlFilter;
  }

  public function applySearch($filter, array $searchMap): ISQLFilter
  {
    $searchMap = $this->transformSearchMap($searchMap);
    if (empty($searchMap)) {
      return $filter; 
    }

    $sqlFilter = clone $this->sqlFilter;
    $sqlFilter = $this->searchFilter->applySearch($sqlFilter, $searchMap);

    return \call_user_func($this->fnApplyFilter, $filter, $sqlFilter);
  }

  public function getSearchMapEmptyValues(): array
  {
    return $this->retransformSearchMap($this->searchFilter->getSearchMapEmptyValues());
  }

  public function getSearchMapFromSession(string $toolSuffix, string $toolPraeffix = ''): array
  {
    return $this->retransformSearchMap($this->searchFilter->getSearchMapFromSession($toolSuffix, $this->transformToolPraeffix($toolPraeffix)));
  }

  public function getSearchMapFromRequest($fnTranformKeys = null): array
  {
    return $this->retransformSearchMap($this->searchFilter->getSearchMapFromRequest(
      \FunctionOperations::combine(
        $fnTranformKeys ?? \FunctionOperations::identity(),
        $this->fnRetransformSearchMapKey
      )
    ));
  }

  public function setSearchMapToSession(array $searchMapToValues, string $toolSuffix, string $toolPraeffix = ''): void
  {
    $this->searchFilter->setSearchMapToSession($this->transformSearchMap($searchMapToValues), $toolSuffix, $this->transformToolPraeffix($toolPraeffix));
  }

  public function isSearchMapFromSessionEmpty(string $toolSuffix, string $toolPraeffix = ''): bool
  {
    return $this->searchFilter->isSearchMapFromSessionEmpty($toolSuffix, $this->transformToolPraeffix($toolPraeffix));
  }

  public function resetSessionSearchMap(string $toolSuffix, string $toolPraeffix = ''): void
  {
    $this->searchFilter->resetSessionSearchMap($toolSuffix, $this->transformToolPraeffix($toolPraeffix));
  }

  public function applySearchFromSession($filter, string $toolSuffix, string $toolPraeffix = '', $fnFilterVariable = null): ISQLFilter
  {
    $searchMap = $this->getSearchMapFromSession($toolSuffix, $toolPraeffix);

    return $this->applySearch($filter, $searchMap);
  }

  public function filterSearchMap(array $searchMap): array
  {
    return \array_filter($searchMap, $this->fnIsSearchMapKey, ARRAY_FILTER_USE_KEY);
  }

  public function transformSearchMap(array $searchMap): array
  {
    $searchMap = $this->filterSearchMap($searchMap);
    $result = array();
    foreach ($searchMap as $key => $value) {
      $result[call_user_func($this->fnTransformSearchMapKey, $key)] = $value;
    }

    return $result;
  }

  public function retransformSearchMap(array $searchMap): array
  {
    $result = array();
    foreach ($searchMap as $key => $value) {
      $result[call_user_func($this->fnRetransformSearchMapKey, $key)] = $value;
    }

    return $result;
  }

  public function transformToolPraeffix(string $toolPraeffix): string
  {
    if ($this->praeffix !== '') {
      return $toolPraeffix . $this->praeffix . '_';
    } else {
      return $toolPraeffix;
    }
  }

  public function isRecursive(string $toolPraeffix): string
  {
    return !call_user_func($this->fnIsSearchMapKey, call_user_func($this->fnTransformSearchMapKey, $toolPraeffix));
  }
}