<?php

namespace App\Classes\FTN\Packet;

use Illuminate\Support\Arr;

use App\Classes\FTN\Packet;
use App\Models\Setup;

/**
 * FSC-0048 http://ftsc.org/docs/fsc-0048.002
 *
 * Commonly known as Type 2+ packets, based on FSC-0039 with improved support for FTS-0001
 */
final class FSC48 extends Packet
{
	protected const HEADER = [
		'onode'			=> [0x00,'v',2],	// Orig Node
		'dnode'			=> [0x02,'v',2],	// Dest Node
		'y'				=> [0x04,'v',2],	// Year
		'm'				=> [0x06,'v',2],	// Month
		'd'				=> [0x08,'v',2],	// Day
		'H'				=> [0x0a,'v',2],	// Hour
		'M'				=> [0x0c,'v',2],	// Minute
		'S'				=> [0x0e,'v',2],	// Second
		'baud'			=> [0x10,'v',2],	// Baud
		'type'			=> [0x12,'v',2],	// Packet Version (should be 2)
		'onet'			=> [0x14,'v',2],	// Orig Net (0xFFFF when OrigPoint != 0)
		'dnet'			=> [0x16,'v',2],	// Dest Net
		'prodcode-lo'	=> [0x18,'C',1],	// Product Code Lo
		'prodrev-maj'	=> [0x19,'C',1],	// Product Version Major
		'password'		=> [0x1a,'a8',8],	// Packet Password
		'ozone'			=> [0x22,'v',2],	// Orig Zone
		'dzone'			=> [0x24,'v',2],	// Dest Zone
		'auxnet'		=> [0x26,'v',2],	// Aux Net
		'capvalid'		=> [0x28,'n',2],	// fsc-0039.004 (copy of 0x2c)
		'prodcode-hi'	=> [0x2a,'C',1],	// Product Code Hi
		'prodrev-min'	=> [0x2b,'C',1],	// Product Version Minor
		'capword'		=> [0x2c,'v',2],	// Capability Word
		'dozone'		=> [0x2e,'v',2],	// Orig Zone
		'ddzone'		=> [0x30,'v',2],	// Dest Zone
		'opoint'		=> [0x32,'v',2],	// Orig Point
		'dpoint'		=> [0x34,'v',2],	// Dest Point
		'proddata'		=> [0x36,'a4',4],	// ProdData
	];

	public const TYPE = '2+';

	public function __get($key)
	{
		switch ($key) {
			case 'capability':
				return sprintf('%016b',Arr::get($this->header,'capword'));

			default:
				return parent::__get($key);
		}
	}

	/**
	 * Create our message packet header
	 */
	protected function header(): string
	{
		try {
			return pack(collect(self::HEADER)->pluck(1)->join(''),
				$this->ff,					// Orig Node
				$this->tf,							// Dest Node
				Arr::get($this->header,'y'),	// Year
				Arr::get($this->header,'m'),	// Month
				Arr::get($this->header,'d'),	// Day
				Arr::get($this->header,'H'),	// Hour
				Arr::get($this->header,'M'),	// Minute
				Arr::get($this->header,'S'),	// Second
				0,									// Baud
				2,									// Packet Version (should be 2)
				$this->fp ? 0xffff : $this->fn,		// Orig Net (0xFFFF when OrigPoint != 0)
				$this->tn,							// Dest Net
				(Setup::PRODUCT_ID & 0xff),			// Product Code Lo
				Setup::PRODUCT_VERSION_MAJ,			// Product Version Major
				$this->password,					// Packet Password
				$this->fz,							// Orig Zone
				$this->tz,							// Dest Zone
				$this->fp ? $this->fn : 0x00,		// Aux Net
				Arr::get($this->header,'capvalid',1<<0),	// fsc-0039.004 (copy of 0x2c)
				((Setup::PRODUCT_ID >> 8) & 0xff),	// Product Code Hi
				Setup::PRODUCT_VERSION_MIN,			// Product Version Minor
				Arr::get($this->header,'capword',1<<0),		// Capability Word
				$this->fz,							// Orig Zone
				$this->tz,							// Dest Zone
				$this->fp,							// Orig Point
				$this->tp,							// Dest Point
				strtoupper(hexstr(Setup::PRODUCT_ID)),	// ProdData
			);

		} catch (\Exception $e) {
			return $e->getMessage();
		}
	}

	/**
	 * Determine if this is a fsc-0045 packet
	 *
	 * @param string $header
	 * @return bool
	 * @throws \Exception
	 */
	public static function is_type(string $header): bool
	{
		$head = unpack(self::unpackheader(self::HEADER),$header);

		return (
			(Arr::get($head,'type') === 2)
			&& (Arr::get($head,'capword') === Arr::get($head,'capvalid'))
			&& ((Arr::get($head,'opoint') === 0) || (Arr::get($head,'onet') === 0xffff))
			&& Arr::get($head,'auxnet')
		);
	}
}