<?php
namespace ModulesAbstract\ImportedOrdersFileManager\Model\Sources;

/**
 * This class extended a long time ago Seekable but i dont now why (07.07.2017)
 * @author Oana Stan
 *
 */
class GeneralFilesystemScanner implements \Iterator
{
	/**
	 * Stores the filesystem path
	 * @var String
	 */
	private $path = NULL;

	/**
	 * Stores if the iteration will be performed recursively
	 * @var Boolean
	 */
	private $recurse = NULL;

	/**
	 * Stores the filter callback
	 */
	private $filterCallback = NULL;


	private $iterator = NULL;

	/**
	 * Stores the current element from iterator
	 */
	private $current = NULL;

	/**
	 * Stores the current element index
	 */
	private $currentIndex = -1;

	/**
	 * Flag for determining the iterator has been iterated
	 * @var Boolean
	 */
	private $iterating = false;

	/**
	 * Stores the total number of results
	 * @var int
	 */
	private $totalNumberOfResults = NULL;

	/**
	 * Stores the number of results after the callback has been applied
	 * @var int
	 */
	private $numberOfResults = NULL;

	/**
	 * Stores the layout handler object used for some classes in order to filter recursively
	 * @var \ModulesAbstract\ImportedOrdersFileManager\Model\LayoutHandler
	 */
	protected $layoutHandler = NULL;

	/**
	 * Stores the iterator source
	 */
	protected $source = NULL;

	/**
	 * Internal flag used to stop iterationg
	 * @var bool
	 */
	private $shouldStop = false;

	/**
	 *
	 * @return \ModulesAbstract\ImportedOrdersFileManager\Model\Sources\GeneralFilesystemScanner
	 */
	public function setShouldStop($shouldStop)
	{
		$this->shouldStop = $shouldStop;
		return $this;
	}

	/**
	 * Set layout handler
	 * @param \ModulesAbstract\ImportedOrdersFileManager\Model\LayoutHandler $layoutHandler
	 */
	public function setLayoutHandler(\ModulesAbstract\ImportedOrdersFileManager\Model\LayoutHandler $layoutHandler)
	{
		$this->layoutHandler = $layoutHandler;
		return $this;
	}

	/**
	 * Set source iterator
	 * @param \Iterator $source
	 * @return \ModulesAbstract\ImportedOrdersFileManager\Model\Filters\AbstractFilter
	 */
	public function setSource(\Iterator $source)
	{
		$this->source = $source;
		return $this;
	}

	/**
	 * Returns the source
	 */
	public function getSource()
	{
		return $this->source;
	}

	/**
	 * Set params
	 */
	public function setParams($path, $recurse, $filterCallback)
	{
		$this->path = $path;
		$this->recurse = (bool)$recurse;
		$this->filterCallback = $filterCallback;

		if ($this->recurse) {
			$this->iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->path), \RecursiveIteratorIterator::SELF_FIRST);
		}
		else {
			$this->iterator = new \DirectoryIterator($this->path);
		}

		$this->rewind();

		return $this;
	}

	/**
	 * Returns the path
	 * @return string
	 */
	public function getPath()
	{
		return $this->path;
	}

	/**
	 * Returns the total number results
	 * @return number
	 */
	public function getTotalNumberOfResults()
	{
		return $this->totalNumberOfResults;
	}

	/**
	 * Returns the number of results
	 * @return number
	 */
	public function getNumberOfResults()
	{
		return $this->numberOfResults;
	}

	/**
	 * (non-PHPdoc)
	 * @see \Iterator::current()
	 */
	public function current() :mixed
	{
		return $this->current;
	}

	/**
	 * (non-PHPdoc)
	 * @see \Iterator::key()
	 */
	public function key() :mixed
	{
		return $this->currentIndex;
	}

	/**
	 * (non-PHPdoc)
	 * @see \Iterator::next()
	 */
	public function next() :void
	{
	}

	/**
	 * (non-PHPdoc)
	 * @see \Iterator::rewind()
	 */
	public function rewind() :void
	{
		$this->iterating = false;
		$this->currentIndex = -1;
		if ($this->iterator) {
			$this->iterator->rewind();
		}
	}


	/**
	 * (non-PHPdoc)
	 * @see \Iterator::valid()
	 */
	public function valid() :bool
	{
		if ($this->iterator) {
			if (!$this->iterating) {
				$this->iterator->rewind();
				$this->iterating = true;
				$this->currentIndex = -1;
			}

			while ($this->iterator->valid() && !$this->shouldStop) {
				$file = $this->iterator->current();

				if ($file) {
					$pathinfo = pathinfo($file->getPathname());

					// ignore elements "." and ".." and hidden
					if ($pathinfo['basename'][0] == '.') {
						$this->iterator->next();
						continue;
					}

					/***
					 * The DirectoryIterator iterator generates a LOT of issues because it internally uses the
					 * same object & only updates part of the internal state as needed.
					 * This means that $file->getPathname() will return an actual file name for folders, leading to the reported file being reported twice
					 *
					 * This whole limitation is "masked" when using our own \Dir & \File classes, as they will create a new object starting only from the path
					 */

					if ($file->isDir()) {
						$this->current = new \ModulesAbstract\ImportedOrdersFileManager\Model\DirCached($file->getPathname());
					}
					else {
						$this->current = new \ModulesAbstract\ImportedOrdersFileManager\Model\File($file->getPathname());
					}

					$this->iterator->next();
					$callback = $this->filterCallback;
					if ($callback($this->current->getFullPath(), $this->currentIndex, $this->current)) {
						$this->currentIndex++;
						$this->numberOfResults++;
						return true;
					}
				}
			}
		}

		return false;
	}
}
