<?php
/**
 * This file is part of the DATAtourisme project.
 *
 *  @author Conjecto <contact@conjecto.com>
 *
 * For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
 */

namespace Datatourisme\Api\Resolver\SparqlResolver\Filter\Conditional;

use Datatourisme\Api\Resolver\SparqlResolver\Collection\FlatCollection;
use Datatourisme\Api\Resolver\SparqlResolver\Filter\ConditionalFilterInterface;
use Datatourisme\Api\Resolver\SparqlResolver\Sparql\Functions\Filter;
use Datatourisme\Api\Resolver\SparqlResolver\Sparql\Triplet;
use Datatourisme\Api\Resolver\SparqlResolver\Utils\SparqlUtils;
use Datatourisme\Api\Schema\Field\AbstractField;

class GeoDistance implements ConditionalFilterInterface
{
    private $latitudeProperty;
    private $longitudeProperty;

    const BASE = 0.874275984;
    const FIXER = 0.008705409;
    const DEGREE_KM = 111.1949;

    public function getName()
    {
        return '_geo_distance';
    }

    /**
     * @param $subject
     * @param AbstractField $fieldDef
     * @param $value
     *
     * @return FlatCollection
     */
    public function generate($subject, AbstractField $fieldDef, $value)
    {
        $set = new FlatCollection();

        $distance = number_format(pow(floatval($value['distance']) / self::DEGREE_KM, 2), 9, '.', '');

        $latId = SparqlUtils::uniqVariable($subject, $this->latitudeProperty);
        $lngId = SparqlUtils::uniqVariable($subject, $this->longitudeProperty);

        $set->add(new Triplet($subject, '<'.$this->latitudeProperty.'>', $latId));
        $set->add(new Triplet($subject, '<'.$this->longitudeProperty.'>', $lngId));

        $set->add(new Filter('(xsd:float('.$value['lat'].") - xsd:float($latId)) * (xsd:float(".$value['lat'].") - xsd:float($latId))
            + (xsd:float(".$value['lng'].") - xsd:float($lngId)) * (xsd:float(".$value['lng'].") - xsd:float($lngId)) * (".self::BASE.' - ('.self::FIXER." * xsd:float($latId)))
            < ".$distance.' '));

        return $set;
    }

    /**
     * @param $latitudeProperty
     *
     * @return $this
     */
    public function setLatitudeProperty($latitudeProperty)
    {
        $this->latitudeProperty = $latitudeProperty;

        return $this;
    }

    /**
     * @param $longitudeProperty
     *
     * @return $this
     */
    public function SetLongitudeProperty($longitudeProperty)
    {
        $this->longitudeProperty = $longitudeProperty;

        return $this;
    }
}
