<?php
namespace ModulesAbstract\PluginReports\Report\Model\Gatherer;

/**
 * The base class for all gatherers
 * @author Lucian Sirbu
 */
abstract class GathererAbstract
{
	/**
	 * List of filters
	 * @var array
	 */
	protected $filters = null;

	/**
	 * internal flag
	 * @var bool
	 */
	protected $initialized = false;

	/**
	 * Internal stats, accesible via getStats()
	 * @var array
	 */
	protected $stats = [];

	/**
	 * Internal gatherer options
	 * @var array
	 */
	protected $options = [];

	/**
	 * The internal logger
	 * @var \Engine\Logger\GeneralAbstract
	 */
	protected $logger = null;

	/**
	 * Get the list of required filters
	 * @return Array:string
	 */
	abstract public function getRequiredFilters();

	/**
	 * Get the list of accepted filters
	 * @return array
	 */
	abstract public function getAcceptedFilters();

	/**
	 * Internal function for initialize gatherer. This function should never be used outside this class
	 */
	abstract protected function objectInitialize();

	/**
	 * Internal function for destroy gatherer. This function should never be used outside this class
	 */
	abstract protected function objectDestroy();

	/**
	 * The main iterator function
	 * @return Array|"intern:skip"|NULL
	 */
	abstract protected function objectNext();

	/**
	 * Get the internal list of gathered stats
	 * @return array
	 */
	public function getInternalStats()
	{
		return $this->stats;
	}

	/**
	 * Initialize the gatherer
	 */
	public function initialize()
	{
		$this->initialized = true;
		$this->logger = ($this->logger?:new \Engine\Logger\Dummy());	// could also be new \Engine\Debug\Dline();
		$this->objectInitialize();
	}

	/**
	 * Destroy any locally allocated resources
	 */
	public function destroy()
	{
		$this->initialized = false;
		$this->objectDestroy();
	}

	/**
	 * Get the used logger
	 * @return \Engine\Logger\GeneralAbstract
	 */
	public function getLogger()
	{
		return $this->logger;
	}

	/**
	 * Set the internal logger
	 *
	 * @param \Engine\Logger\GeneralAbstract|\Engine\Logger\MultipleLogger $logger
	 * @return $this
	 */
	public function setLogger($logger)
	{
		$this->logger = $logger;

		return $this;
	}

	/**
	 * Advance to the next row
	 * @return Array|null
	 */
	public function next()
	{
		$t1 = microtime(true);

		if (!$this->initialized) {	// start-of-report
			$this->initialized = true;
			$this->initialize();
		}

		$ret = null;
		do {
			$ret = $this->objectNext();
			$this->stats['next:raw']++;
		} while($ret === "intern:skip");
		$this->stats['next:filtered']++;

		$this->stats['next:time']+= microtime(true)-$t1;

		if ($ret===null) {	// end-of-report
			$this->destroy();
			$this->initialized = false;
		}

		return $ret;
	}

	/**
	 * Convert the results list to an iterator
	 * @return \Generator
	 */
	public function asIterator()
	{
		while ($row = $this->next()) {
			yield $row;
		}
	}

	/**
	 * Convert the results list to an array. Be careful about the used memory!!!
	 * @return Array[]
	 */
	public function asArray()
	{
		$ret = [];
		while ($row = $this->next()) {
			$ret[]= $row;
		}

		return $ret;
	}

	/**
	 * Add a filter param
	 * @param string $key
	 * @param mixed $value
	 * @return \ModulesAbstract\PluginReports\Report\Model\Gatherer\GathererAbstract
	 */
	public function addFilter($key, $value)
	{
		$this->filters[$key] = $value;
		return $this;
	}

	/**
	 * Remove all filters
	 * @param string $key
	 * @param mixed $value
	 * @return \ModulesAbstract\PluginReports\Report\Model\Gatherer\GathererAbstract
	 */
	public function resetFilters()
	{
		$this->filters = [];
		return $this;
	}


	/**
	 * Set option for current gatherer
	 * @param string $key
	 * @param string $value
	 * @return \ModulesAbstract\PluginReports\Report\Model\Gatherer\GathererAbstract
	 */
	public function setOption($key, $value)
	{
		$this->options[$key] = $value;
		return $this;
	}

	/**
	 * Get option for a spefic key
	 * @param String $key
	 * @return multitype:string boolean
	 */
	public function getOption($key)
	{
		return $this->options[$key];
	}

}
