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

namespace Kufer\Web\Classes\Scripting;

class ScriptingEngineHTMLScript2 implements ScriptingEngine
{
  public function interpret(VariableProviderAdapter $export, $code, ?string $cacheKey): void
  {
    $exportResults = $export->values();
    foreach ($exportResults as $value) {
      
      $parsedStream = $this->parseScripts($export, call_user_func($code));
      
      
      $varnames = $this->returnVarNames($export, $parsedStream);
      
      $export->addResult($this->fillVarsByVariableList($export, $parsedStream, $varnames), $varnames);
    }
  }

  
  public function returnVarNames(VariableProviderAdapter $export, string $inputstr)
  {
    $ary = array();
    $endpos = 0;
    do {
      $startpos = \StringOperations::strpos($inputstr, '{%', $endpos);
      if ($startpos !== false && $startpos >= $endpos) {
        $endpos = \StringOperations::strpos($inputstr, '%}', $startpos + 2);
        $varname = \StringOperations::substr($inputstr, $startpos + 2, $endpos - ($startpos + 2));
        if (!$this->varInArray($export, $varname, $ary)) { 
          $ary[] = $varname;
        }
        $endpos += 2;
      } else {
        $endpos = false;
      }
    } while ($endpos);

    return $ary;
  }

  
  private function parseScripts(VariableProviderAdapter $export, string $parsetext)
  {
    $str = $parsetext;

    
    
    
    
    $str = preg_replace(
      '&{§IF§}\\s*{§VALUE1§}\\s*?(.*)\\s*?{/§VALUE1§}\\s*{§EQUAL§}(.*){/§EQUAL§}\\s*{§VALUE2§}\\s*?(.*)\\s*?{/§VALUE2§}\\s*{§THEN§}(.*){/§THEN§}\\s*{§ELSE§}(.*){/§ELSE§}\\s*{§END§}&sU',
      '(§IF§)("$1" $2 "$3") {$4} else {$5}',
      $str
    );

    $str = preg_replace(
      '&{§DISPLAY§}\\s*?(.*)\\s*?{/§DISPLAY§}&sU',
      '(§IF§)("$1" == "") { style="display: none;"} else {}',
      $str
    );

    

    $expressionEvaluator = new class($this, $export) implements ExpressionEvaluator {
      public $scriptingEngine;
      public $export;

      public function __construct($scriptingEngine, $export)
      {
        $this->scriptingEngine = $scriptingEngine;
        $this->export = $export;
      }

      public function fillVarsByVariableList($code, $vars): string
      {
        return $this->scriptingEngine->fillVarsByVariableList($this->export, $code, $vars);
      }

      public function returnVarNames(string $code): array
      {
        return $this->scriptingEngine->returnVarNames($this->export, $code);
      }
    };

    if (\StringOperations::stripos($str, '(§foreach') !== false) {
      $str = $this->compileForeachTag($export, $expressionEvaluator, $str);
    }

    
    
    
    
    
    

    static $cache = array();
    if (!isset($cache[$str])) {
      $scanner = new \EasyHtmlScript2($str);
      $cache[$str] = $scanner->scan();
    }
    $str = $cache[$str]->getContent($expressionEvaluator);

    return $str;
  }

  private function compileForeachTag(VariableProviderAdapter $export, ExpressionEvaluator $expressionEvaluator, $pString)
  {
    $data = get_object_vars($export->currentValue());
    $engine = new \ForeachTemplateEngine($expressionEvaluator, $data, function($str) use ($export) {
      return $export->getVarValueForeach($str);
    });

    return $engine->process($pString);
  }

  
  public function fillVarsByVariableList(VariableProviderAdapter $export, $str, $pVars)
  {
    $nonPermanentVars = array();
    for ($i = 0; $i < count($pVars); $i++) {
      $var = $pVars[$i];
      $value = $this->getVarValue($export, $var);

      if (!$export->canCacheVariable($var)) {
        $str = $this->replaceVar($export, $var, $value, $str);
      } else {
        $nonPermanentVars['{%' . $var . '%}'] = $value;
      }
    }

    return \StringOperations::str_fast_parallel_replace($str, $nonPermanentVars);
  }

  private function getVarValue(VariableProviderAdapter $export, string $var)
  {
    $parts = explode(':', $var);
    for ($i = 1; $i < count($parts); ++$i) {
      $matches = array();
      if (preg_match('/^%(\\w+)%$/', $parts[$i], $matches) === 1) {
        $parts[$i] = \StringOperations::html_entity_decode($export->getVarValue($matches[1]));
      }
    }

    return $export->getVarValue(implode(':', $parts));
  }

  private function stripParam($variable)
  {
    $positionDoppelpunkt = \StringOperations::strpos($variable, ':');
    if ($positionDoppelpunkt === false) {
      return $variable;
    } else {
      return \StringOperations::substr($variable, 0, $positionDoppelpunkt);
    }
  }

  
  private function replaceVar(VariableProviderAdapter $export, string $var, string $value, string $str)
  {
    if ($export->canCacheVariable($var)) {
      
      $str = str_replace(
        '{%' . $var . '%}',               
        $value, 
        $str                                    
      );
    } else {
      
      $str = substr_replace(
        $str,                                   
        $value, 
        strpos($str, '{%' . $var . '%}'), 
        strlen('{%' . $var . '%}')        
      );                                        
    }

    return $str;
  }

  private function varInArray(VariableProviderAdapter $export, $pVarname, $pAry)
  {
    if (!$export->canCacheVariable($pVarname)) {
      return false;
    } else {
      return in_array($pVarname, $pAry);
    }
  }
}