<?php

namespace App\Classes\File;

use Exception;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use League\Flysystem\UnreadableFileException;

/**
 * A file we are sending or receiving
 *
 * @property string $name
 * @property string $recvas
 * @property int $size
 */
class Item
{
	protected const IS_PKT			= (1<<1);
	protected const IS_ARC			= (1<<2);
	protected const IS_FILE			= (1<<3);
	protected const IS_FLO			= (1<<4);
	protected const IS_REQ			= (1<<5);

	protected const I_RECV			= (1<<6);
	protected const I_SEND			= (1<<7);

	protected string $file_name = '';
	protected int $file_size = 0;
	protected int $file_mtime = 0;
	protected int $file_type = 0;
	protected int $action = 0;

	public bool $sent = FALSE;
	public bool $received = FALSE;
	public bool $incomplete = FALSE;

	/**
	 * @throws FileNotFoundException
	 * @throws UnreadableFileException
	 * @throws Exception
	 */
	public function __construct($file,int $action)
	{
		$this->action |= $action;

		switch ($action) {
			case self::I_SEND:
				if (! is_string($file))
					throw new Exception('Invalid object creation - file should be a string');

				if (! file_exists($file))
					throw new FileNotFoundException('Item doesnt exist: '.$file);

				if (! is_readable($file))
					throw new UnreadableFileException('Item cannot be read: '.$file);

				$this->file_name = $file;
				$x = stat($file);
				$this->file_size = $x['size'];
				$this->file_mtime = $x['mtime'];

				break;

			case self::I_RECV;
				$keys = ['name','mtime','size'];

				if (! is_array($file) || array_diff(array_keys($file),$keys))
					throw new Exception('Invalid object creation - file is not a valid array :'.serialize(array_diff(array_keys($file),$keys)));

				$this->file_name = $file['name'];
				$this->file_size = $file['size'];
				$this->file_mtime = $file['mtime'];

				break;

			default:
				throw new Exception('Unknown action: '.$action);
		}

		$this->file_type |= $this->whatType();
	}

	/**
	 * @throws Exception
	 */
	public function __get($key)
	{
		switch($key) {
			case 'mtime':
			case 'name':
			case 'size':
				if ($this->action & self::I_RECV)
					return $this->{'file_'.$key};

				throw new Exception('Invalid request for key: '.$key);

			case 'recvas':
				return $this->file_name;

			case 'sendas':
				return basename($this->file_name);

			default:
				throw new Exception('Unknown key: '.$key);
		}
	}

	protected function isType(int $type): bool
	{
		return $this->file_type & $type;
	}

	private function whatType(): int
	{
		static $ext = ['su','mo','tu','we','th','fr','sa','req'];

		$x = strrchr($this->file_name,'.');

		if (! $x || (strlen(substr($x,1)) != 3))
			return self::IS_FILE;

		if (strcasecmp(substr($x,2),'lo') == 0)
			return self::IS_FLO;

		if (strcasecmp(substr($x,1),'pkt') == 0)
			return self::IS_PKT;

		if (strcasecmp(substr($x,1),'req') == 0)
			return self::IS_REQ;

		for ($i=0;$i<count($ext);$i++)
			if (! strncasecmp($x,'.'.$ext[$i],strlen($ext[$i])) && (preg_match('/^[0-9a-z]/',strtolower(substr($x,3,1)))))
				return self::IS_ARC;

		return self::IS_FILE;
	}
}