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

namespace Kufer\Web\Classes\Scripting3;

class ExprSingleCondition extends Expr
{
  
  public $expr0;

  
  public $expr1;
  public $op;

  public function __construct(Expr $expr0, Expr $expr1, int $op)
  {
    parent::__construct();
    $this->expr0 = $expr0;
    $this->expr1 = $expr1;
    $this->op = $op;
  }

  public function toString(): string
  {
    $val0 = $this->expr0->toString();
    $val1 = $this->expr1->toString();

    switch ($this->op) {
      default:
        throw new \RuntimeException("Unerwarteter Operator: $this->op");
      case self::OP_EQUALS:
        return $val0 . ' == ' . $val1;
      case self::OP_NOT_EQUALS:
        return $val0 . ' != ' . $val1;
      case self::OP_GREATER:
        return $val0 . ' > ' . $val1;
      case self::OP_LESS:
        return $val0 . ' < ' . $val1;
      case self::OP_EQ_GREATER:
        return $val0 . ' >= ' . $val1;
      case self::OP_EQ_LESS:
        return $val0 . ' <= ' . $val1;
      case self::OP_VOR:
        return $val0 . ' vor ' . $val1;
      case self::OP_CONTAINS:
        return $val0 . ' contains ' . $val1;
      case self::OP_MATCHES:
        return $val0 . ' matches ' . $val1;
      case self::OP_PARTMATCHES:
        return $val0 . ' partmatches ' . $val1;
    }
  }

  public static function transformPHPCondition(ParserHelper $phpcode, array $fnvars, Expr $expr)
  {
    $expr = $expr->optimize();

    if ($expr instanceof ExprText) {
      $text = static::transformCondition($expr->text);
      if (is_int($text) || is_float($text)) {
        return $text;
      } else {
        return (new ExprText($text))->toPHP(false, $phpcode, $fnvars);
      }
    }

    $text = $expr->toPHP(false, $phpcode, $fnvars);
    if (mb_ereg_match('^\'-?([0-9]+([.,][0-9]*)?)\'$', $text)) {
      return "'" . self::transformCondition(\StringOperations::substr($text, 1, \StringOperations::strlen($text) - 2)) . "'";
    }

    if (\mb_ereg_match('^\'[A-Za-z0-9_ \\t\\n\\r]*\'$', $text)) {
      return $text;
    }

    return trim($text) == '\'\'' ? '\'\'' : \Kufer\Web\Classes\Scripting3\ExprSingleCondition::class . '::tc(' . $text . ')';
  }

  public static function conditionMatches(string $var0, string $var1, bool $part)
  {
    $matches = array();
    $var0 = \StringOperations::html_entity_decode($var0);
    $var1 = \StringOperations::html_entity_decode($var1);
    $matchCount = \preg_match($var0, $var1, $matches);
    if ($matchCount === false) {
      if (DEBUG) {
        die('Falscher PREG-Ausdruck: ' . $var0);
      }

      return false;
    }

    if ($part) {
      return $matchCount > 0;
    }

    return $matchCount > 0 && $matches[0] === $var1;
  }

  public static function transformCondition($text)
  {
    $trimmedText = trim($text);
    
    if (preg_match('/^-?\\d+([.,]\\d*)$/', $trimmedText) === 1) {
      
      $val = str_replace(',', '.', $trimmedText);
      if (!preg_match('/^-?\\d+(\\.\\d*)$/', $val)) {
        return \StringOperations::html_entity_decode($val);
      }

      return floatval($val);
    } elseif (preg_match('/^-?\\d+$/', $trimmedText) === 1) {
      $val = $trimmedText;

      return intval($val);
    }

    return \StringOperations::html_entity_decode($text);
  }

  public static function tc($text)
  {
    return static::transformCondition($text);
  }

  public function toPHP(bool $isleaf, ParserHelper $phpcode, array $fnvars): string
  {
    $result = '';
    $val0 = static::transformPHPCondition($phpcode, $fnvars, $this->expr0);
    $val1 = static::transformPHPCondition($phpcode, $fnvars, $this->expr1);

    switch ($this->op) {
      case self::OP_EQUALS:
        $result .= $val0 . '==' . $val1;
        break;
      case self::OP_NOT_EQUALS:
        $result .= $val0 . '!=' . $val1;
        break;
      case self::OP_GREATER:
        $result .= $val0 . '>' . $val1;
        break;
      case self::OP_LESS:
        $result .= $val0 . '<' . $val1;
        break;
      case self::OP_EQ_GREATER:
        $result .= $val0 . '>=' . $val1;
        break;
      case self::OP_EQ_LESS:
        $result .= $val0 . '<=' . $val1;
        break;
      case self::OP_VOR:
        $result .= \DateTimeOperations::class . '::isDateBefore(' . $val0 . ', ' . $val1 . ')';
        break;
      case self::OP_CONTAINS:
        $result .= \StringOperations::class . '::strstr(' . \StringOperations::class . '::html_entity_decode(' . $val0 . '), ' . \StringOperations::class . '::html_entity_decode(' . $val1 . '))!==false';
        break;
      case self::OP_MATCHES:
        $result .= \Kufer\Web\Classes\Scripting3\ExprSingleCondition::class . '::conditionMatches(' . $val0 . ',' . $val1 . ',false)';
        break;
      case self::OP_PARTMATCHES:
        $result .= \Kufer\Web\Classes\Scripting3\ExprSingleCondition::class . '::conditionMatches(' . $val0 . ',' . $val1 . ',true)';
        break;
    }

    $result = '(' . $result . ')';

    return $result;
  }

  public const OP_EQUALS = 0;
  public const OP_NOT_EQUALS = 1;
  public const OP_GREATER = 2;
  public const OP_LESS = 3;
  public const OP_EQ_GREATER = 4;
  public const OP_EQ_LESS = 5;
  public const OP_VOR = 6;
  public const OP_CONTAINS = 7;
  public const OP_MATCHES = 8;
  public const OP_PARTMATCHES = 9;

  public const OP_TO_STR = array(
    '==' => self::OP_EQUALS,
    '!=' => self::OP_NOT_EQUALS,
    '<=' => self::OP_EQ_LESS,
    '>=' => self::OP_EQ_GREATER,
    '<' => self::OP_LESS,
    '>' => self::OP_GREATER,
    'VOR' => self::OP_VOR,
    'CONTAINS' => self::OP_CONTAINS,
    'MATCHES' => self::OP_MATCHES,
    'PARTMATCHES' => self::OP_PARTMATCHES, );

  public static function fromString(string $str)
  {
    return self::OP_TO_STR[$str];
  }
}