<?php
/**
 * Scan state value object.
 *
 * @package LocalGuardScanner
 */

namespace LocalGuardScanner\Domain\Scan;

use DomainException;

/**
 * Defines valid scan states and transitions.
 */
final class ScanState {
	const QUEUED            = 'queued';
	const DISCOVERING       = 'discovering';
	const SCANNING_FILES    = 'scanning_files';
	const SCANNING_DATABASE = 'scanning_database';
	const CLASSIFYING       = 'classifying';
	const COMPLETED         = 'completed';
	const PARTIAL           = 'partial';
	const CANCELLED         = 'cancelled';
	const FAILED            = 'failed';

	/** @var string */
	private $value;

	/**
	 * @param string $value State value.
	 */
	public function __construct( $value ) {
		if ( ! in_array( $value, self::all(), true ) ) {
			throw new DomainException( 'Unknown scan state.' );
		}
		$this->value = $value;
	}

	/**
	 * @return string
	 */
	public function value() {
		return $this->value;
	}

	/**
	 * Whether this state can transition to the target state.
	 *
	 * @param string $target Target state.
	 * @return bool
	 */
	public function can_transition_to( $target ) {
		$transitions = array(
			self::QUEUED            => array( self::DISCOVERING, self::CANCELLED, self::FAILED ),
			self::DISCOVERING       => array( self::SCANNING_FILES, self::PARTIAL, self::CANCELLED, self::FAILED ),
			self::SCANNING_FILES    => array( self::SCANNING_DATABASE, self::PARTIAL, self::CANCELLED, self::FAILED ),
			self::SCANNING_DATABASE => array( self::CLASSIFYING, self::PARTIAL, self::CANCELLED, self::FAILED ),
			self::CLASSIFYING       => array( self::COMPLETED, self::PARTIAL, self::CANCELLED, self::FAILED ),
			self::COMPLETED         => array(),
			self::PARTIAL           => array(),
			self::CANCELLED         => array(),
			self::FAILED            => array(),
		);

		return isset( $transitions[ $this->value ] ) && in_array( $target, $transitions[ $this->value ], true );
	}

	/**
	 * @return string[]
	 */
	public static function all() {
		return array(
			self::QUEUED,
			self::DISCOVERING,
			self::SCANNING_FILES,
			self::SCANNING_DATABASE,
			self::CLASSIFYING,
			self::COMPLETED,
			self::PARTIAL,
			self::CANCELLED,
			self::FAILED,
		);
	}
}
