<?php
namespace Newland\Toubiz\Sync\Neos\Domain\Filter;

/*
 * This file is part of the "toubiz-sync-neos" package.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 */

use Newland\Toubiz\Sync\Neos\Domain\Model\AbstractEntity;

/**
 * Abstract filter class.
 */
abstract class AbstractFilter implements FilterInterface
{
    /**
     * @var int
     */
    const JOIN_LEFT = 0;

    /**
     * @var int
     */
    const JOIN_INNER = 1;

    /**
     * @var int|null
     */
    protected $limit;

    /**
     * @var int|null
     */
    protected $offset;

    /**
     * @var array
     */
    protected $orderBy = [];

    /**
     * @var array
     */
    protected $groupBy = [];

    /**
     * @var array Objects to exclude from the query result.
     */
    protected $excludes = [];

    /**
     * @var array Joins that are needed for filtering.
     */
    protected $joins = [
        self::JOIN_LEFT => [],
        self::JOIN_INNER => [],
    ];

    /**
     * @var array
     */
    protected $orderByRelations = [];

    /**
     * Initializes filter options.
     *
     * @param array $config
     * @return self
     */
    public function initialize(array $config)
    {
        if (array_key_exists('limit', $config)) {
            $this->limit = $config['limit'];
        }
        if (array_key_exists('offset', $config)) {
            $this->offset = $config['offset'];
        }

        return $this;
    }

    public function getLimit()
    {
        return $this->limit;
    }

    public function setLimit(int $limit = null): self
    {
        $this->limit = $limit;
        return $this;
    }

    public function getOffset()
    {
        return $this->offset;
    }

    public function setOffset(int $offset = null): self
    {
        $this->offset = $offset;
        return $this;
    }

    public function getOrderBy(): array
    {
        return $this->orderBy;
    }

    public function setOrderBy(array $orderBy): self
    {
        $this->orderBy = $orderBy;
        return $this;
    }

    public function setExcludes(array $excludes): self
    {
        $this->excludes = $excludes;
        return $this;
    }

    public function getExcludes(): array
    {
        return $this->excludes;
    }

    public function addExclude(AbstractEntity $exclude): self
    {
        $this->excludes[] = $exclude;
        return $this;
    }

    public function addLeftJoin(string $field, string $table): self
    {
        $this->joins[self::JOIN_LEFT][$field] = $table;
        return $this;
    }

    public function getLeftJoins(): array
    {
        return $this->joins[self::JOIN_LEFT];
    }

    public function addInnerJoin(string $field, string $table): self
    {
        $this->joins[self::JOIN_INNER][$field] = $table;
        return $this;
    }

    public function getInnerJoins(): array
    {
        return $this->joins[self::JOIN_INNER];
    }

    public function getGroupBy(): array
    {
        return $this->groupBy;
    }

    public function setGroupBy(array $groupBy): self
    {
        $this->groupBy = $groupBy;
        return $this;
    }

    public function orderByRelation(string $relation, string $alias, string $direction = 'ASC')
    {
        $this->orderByRelations[] = [
            'relation' => $relation,
            'alias' => $alias,
            'direction' => $direction,
        ];
    }

    public function getOrderByRelation(): array
    {
        return $this->orderByRelations;
    }

    /**
     * Helper for date and time.
     *
     * @var mixed $input
     * @return \DateTime
     */
    protected function asDateTime($input)
    {
        if (is_string($input)) {
            return new \DateTime($input);
        }

        return $input;
    }
}
