<?php
namespace MailPoetVendor\Doctrine\Common\Collections\Expr;
if (!defined('ABSPATH')) exit;
use ArrayAccess;
use Closure;
use RuntimeException;
use function explode;
use function in_array;
use function is_array;
use function is_scalar;
use function iterator_to_array;
use function method_exists;
use function preg_match;
use function preg_replace_callback;
use function strlen;
use function strpos;
use function strtoupper;
use function substr;
class ClosureExpressionVisitor extends ExpressionVisitor
{
 public static function getObjectFieldValue($object, $field)
 {
 if (strpos($field, '.') !== \false) {
 [$field, $subField] = explode('.', $field, 2);
 $object = self::getObjectFieldValue($object, $field);
 return self::getObjectFieldValue($object, $subField);
 }
 if (is_array($object)) {
 return $object[$field];
 }
 $accessors = ['get', 'is', ''];
 foreach ($accessors as $accessor) {
 $accessor .= $field;
 if (method_exists($object, $accessor)) {
 return $object->{$accessor}();
 }
 }
 if (preg_match('/^is[A-Z]+/', $field) === 1 && method_exists($object, $field)) {
 return $object->{$field}();
 }
 // __call should be triggered for get.
 $accessor = $accessors[0] . $field;
 if (method_exists($object, '__call')) {
 return $object->{$accessor}();
 }
 if ($object instanceof ArrayAccess) {
 return $object[$field];
 }
 if (isset($object->{$field})) {
 return $object->{$field};
 }
 // camelcase field name to support different variable naming conventions
 $ccField = preg_replace_callback('/_(.?)/', static function ($matches) {
 return strtoupper($matches[1]);
 }, $field);
 foreach ($accessors as $accessor) {
 $accessor .= $ccField;
 if (method_exists($object, $accessor)) {
 return $object->{$accessor}();
 }
 }
 return $object->{$field};
 }
 public static function sortByField($name, $orientation = 1, ?Closure $next = null)
 {
 if (!$next) {
 $next = static function () : int {
 return 0;
 };
 }
 return static function ($a, $b) use($name, $next, $orientation) : int {
 $aValue = ClosureExpressionVisitor::getObjectFieldValue($a, $name);
 $bValue = ClosureExpressionVisitor::getObjectFieldValue($b, $name);
 if ($aValue === $bValue) {
 return $next($a, $b);
 }
 return ($aValue > $bValue ? 1 : -1) * $orientation;
 };
 }
 public function walkComparison(Comparison $comparison)
 {
 $field = $comparison->getField();
 $value = $comparison->getValue()->getValue();
 // shortcut for walkValue()
 switch ($comparison->getOperator()) {
 case Comparison::EQ:
 return static function ($object) use($field, $value) : bool {
 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) === $value;
 };
 case Comparison::NEQ:
 return static function ($object) use($field, $value) : bool {
 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) !== $value;
 };
 case Comparison::LT:
 return static function ($object) use($field, $value) : bool {
 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) < $value;
 };
 case Comparison::LTE:
 return static function ($object) use($field, $value) : bool {
 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) <= $value;
 };
 case Comparison::GT:
 return static function ($object) use($field, $value) : bool {
 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) > $value;
 };
 case Comparison::GTE:
 return static function ($object) use($field, $value) : bool {
 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) >= $value;
 };
 case Comparison::IN:
 return static function ($object) use($field, $value) : bool {
 $fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
 return in_array($fieldValue, $value, is_scalar($fieldValue));
 };
 case Comparison::NIN:
 return static function ($object) use($field, $value) : bool {
 $fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
 return !in_array($fieldValue, $value, is_scalar($fieldValue));
 };
 case Comparison::CONTAINS:
 return static function ($object) use($field, $value) {
 return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) !== \false;
 };
 case Comparison::MEMBER_OF:
 return static function ($object) use($field, $value) : bool {
 $fieldValues = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
 if (!is_array($fieldValues)) {
 $fieldValues = iterator_to_array($fieldValues);
 }
 return in_array($value, $fieldValues, \true);
 };
 case Comparison::STARTS_WITH:
 return static function ($object) use($field, $value) : bool {
 return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) === 0;
 };
 case Comparison::ENDS_WITH:
 return static function ($object) use($field, $value) : bool {
 return $value === substr(ClosureExpressionVisitor::getObjectFieldValue($object, $field), -strlen($value));
 };
 default:
 throw new RuntimeException('Unknown comparison operator: ' . $comparison->getOperator());
 }
 }
 public function walkValue(Value $value)
 {
 return $value->getValue();
 }
 public function walkCompositeExpression(CompositeExpression $expr)
 {
 $expressionList = [];
 foreach ($expr->getExpressionList() as $child) {
 $expressionList[] = $this->dispatch($child);
 }
 switch ($expr->getType()) {
 case CompositeExpression::TYPE_AND:
 return $this->andExpressions($expressionList);
 case CompositeExpression::TYPE_OR:
 return $this->orExpressions($expressionList);
 default:
 throw new RuntimeException('Unknown composite ' . $expr->getType());
 }
 }
 private function andExpressions(array $expressions) : callable
 {
 return static function ($object) use($expressions) : bool {
 foreach ($expressions as $expression) {
 if (!$expression($object)) {
 return \false;
 }
 }
 return \true;
 };
 }
 private function orExpressions(array $expressions) : callable
 {
 return static function ($object) use($expressions) : bool {
 foreach ($expressions as $expression) {
 if ($expression($object)) {
 return \true;
 }
 }
 return \false;
 };
 }
}
