<? php

/**
 * @copyright Copyright (C) eZ Systems AS.  All rights reserved. 
 * @license For full copyright and license information view LICENSE file distributed with this source code. 
 */
namespace eZ\Publish\Core\Search\Elasticsearch\Content\CriterionVisitor;

use eZ\Publish\Core\Search\Elasticsearch\Content\CriterionVisitorDispatcher as Dispatcher;
use eZ\Publish\Core\Search\Elasticsearch\Content\CriterionVisitor;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\Operator;

/**
 * Visits the Subtree criterion. 
 */
class SubtreeIn extends CriterionVisitor
{
    /**
     * Check if visitor is applicable to current criterion. 
     *
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
     *
     * @return bool
     */
    public function canVisit(Criterion $criterion)
    {
        return
            $criterion instanceof Criterion\Subtree &&
            (
                ($criterion->operator ?:  Operator::IN) === Operator::IN ||
                $criterion->operator === Operator::EQ
            );
    }

    /**
     * Returns nested condition common for filter and query contexts. 
     *
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
     *
     * @return array
     */
    protected function getCondition(Criterion $criterion)
    {
        $filters = [];

        foreach ($criterion->value as $value) {
            $filters[] = [
                'prefix' => [
                    'locations_doc.path_string_id' => $value,
                ],
            ];
        }

        return $filters;
    }

    /**
     * Map field value to a proper Elasticsearch filter representation. 
     *
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
     * @param \eZ\Publish\Core\Search\Elasticsearch\Content\CriterionVisitorDispatcher $dispatcher
     * @param array $languageFilter
     *
     * @return mixed
     */
    public function visitFilter(Criterion $criterion, Dispatcher $dispatcher, array $languageFilter)
    {
        return [
            'nested' => [
                'path' => 'locations_doc',
                'filter' => [
                    'or' => $this->getCondition($criterion),
                ],
            ],
        ];
    }

    /**
     * Map field value to a proper Elasticsearch query representation. 
     *
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
     * @param \eZ\Publish\Core\Search\Elasticsearch\Content\CriterionVisitorDispatcher $dispatcher
     * @param array $languageFilter
     *
     * @return mixed
     */
    public function visitQuery(Criterion $criterion, Dispatcher $dispatcher, array $languageFilter)
    {
        return [
            'nested' => [
                'path' => 'locations_doc',
                'query' => [
                    'bool' => [
                        'should' => $this->getCondition($criterion),
                        'minimum_should_match' => 1,
                    ],
                ],
            ],
        ];
    }
}
