<?php

namespace Snaju\Inception\Arrays;

use Snaju\Inception\Util\ArrayUtil;

class ArrayFilter
{

    private $array = [];

    private $filtered = [];

    /**
     * ArrayFilter constructor.
     * @param array $array
     */
    public function __construct(array &$array)
    {
        $this->array = ArrayUtil::getDotArray($array);
    }

    private function _allow(array &$source, array &$dest, $key)
    {
        $key = str_replace([
            ".",
            "*"
        ], [
            "\\.",
            "[0-9a-zA-Z]*"
        ], $key);

        foreach ($source as $k => $v) {
            if (preg_match('/^' . $key . '/mi', $k, $match, PREG_OFFSET_CAPTURE, 0)) {
                // Is a match
                $dest[$k] = $v;
            }
        }
    }

    private function _restrict(array &$dest, $key)
    {
        $key = str_replace([
            ".",
            "*"
        ], [
            "\\.",
            "[0-9a-zA-Z]*"
        ], $key);

        foreach ($dest as $k => $v) {
            if (preg_match('/^' . $key . '/mi', $k, $match, PREG_OFFSET_CAPTURE, 0)) {
                // Is a match
                $dest[$k] = null;
                unset($dest[$k]);
            }
        }
    }

    public function allowAll(): ArrayFilter
    {
        $this->filtered = $this->array;
        return $this;
    }

    public function allow(array $keys): ArrayFilter
    {
        foreach ($keys as $key) {
//            ArrayUtil::toArray($this->filtered, $key, ArrayUtil::fromArray($this->array, $key));
            $this->_allow($this->array, $this->filtered, $key);
        }

        return $this;
    }

    public function allowAllExcept(array $keys): ArrayFilter
    {
        $temp = $this->array;
        foreach ($keys as $key) {
            $this->_restrict($temp, $key);
//            ArrayUtil::unsetKey($temp, $key);
        }
        $this->filtered = $temp;

        return $this;
    }

    public function remove(array $keys): ArrayFilter
    {
        foreach ($keys as $key) {
//            ArrayUtil::unsetKey($this->filtered, $key);
            $this->_restrict($this->filtered, $key);
        }

        return $this;
    }

    public function clear(): ArrayFilter
    {
        $this->filtered = [];

        return $this;
    }

    public function get(): array
    {
        $arr = [];

        foreach ($this->filtered as $k => $v) {
            ArrayUtil::toArray($arr, $k, $v);
        }

        return $arr;
    }

    public function filteredSize(): int
    {
        return count($this->filtered);
    }

    public function sourceSize(): int
    {
        return count($this->array);
    }

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

    public function getRawFiltered(): array
    {
        return $this->filtered;
    }

    public static function create(array &$a)
    {
        return new ArrayFilter($a);
    }

}