<?php
namespace App\Utils\BaseParser\Utils\Extractor;


abstract class AbstractFindResponse
{
	/**
	 * The match count
	 * @var int
	 */
	protected $count = null;

	/**
	 * The list of raw matches
	 * @var array:string
	 */
	protected $rawMatches = null;

	public function __construct($count, $rawMatches)
	{
		$this->count = $count;
		$this->rawMatches = $rawMatches;
	}

	public function __get($key)
	{
		return $this->get($key);
	}

	/**
	 * Get an element value
	 */
	abstract function get($key);

	/**
	 * Get an element match offset
	 */
	abstract public function getOffset($key);

	/**
	 * Cleanup the internal structure, removing numerical keys, generated by the preg_match functions.
	 * It leaves $rawMatches[0] in place though, to be able to access the whole matched string
	 * @return $this
	 */
	public function cleanup()
	{
		$this->rawMatches = $this->getCleanedUp();

		return $this;
	}

	/**
	 * Apply the callback to the internal results list, allowing rewriting, inserting of removing values
	 * @return $this
	 */
	public function mapKeyValue($callback)
	{
		$remappedMatches = [];
		foreach ($this->rawMatches as $k=>$v) {
			$remappedMatches[]= [
				'key' => 	$k,
				'value' => 	$v[0],
				'offset' => $v[1]
			];
		}

		$remappedMatches = array_map($callback, $remappedMatches);

		$this->rawMatches = [];
		foreach ($remappedMatches as $rkv) {
			if ($rkv===null) {
				continue;	// special cases, skip null elements
			}
			foreach ($rkv as $kv) {
				$this->rawMatches[$kv['key']] = [$kv['value'], $kv['offset'], ];
			}
		}

		return $this;
	}

	/**
	 * Cleanup the internal structure, removing numerical keys, generated by the preg_match functions.
	 * @return array
	 */
	private function getCleanedUp()
	{
		$rawMatches = $this->rawMatches;
		$rawMatches = array_diff_key($rawMatches, range(1, count($rawMatches)));	// remove numeric keys

		// because of a PHP bug, preg_match will return inexistent keys, with a blank value. Remove them now
		$rawMatches = array_filter($rawMatches);

		return $rawMatches;
	}

	/**
	 * Get the list of raw matches
	 * @return array:array
	 */
	public function getRawMatches()
	{
		return $this->rawMatches;
	}

	/**
	 * Get the list of matched strings
	 * @return array:string
	 */
	public function getRawMatchedStrings()
	{
		return array_map(function($a) { return $a[0]; }, $this->getRawMatches());
	}


	/**
	 * Check if we have any value set
	 * @return boolean
	 */
	public function hasValue()
	{
		return $this->count!==0;
	}

	/**
	 * Get the count of matches
	 * @return int
	 */
	public function getCount()
	{
		return $this->count;
	}

	/**
	 * Get the count of matches
	 * @return int
	 */
	public function getRealCount()
	{
		return count($this->getCleanedUp());
	}
}
