<?php

namespace App\Classes\FTN\Packet;

use Illuminate\Support\Arr;
use Illuminate\Support\Collection;

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

/**
 * FSC-0039 http://ftsc.org/docs/fsc-0039.004
 *
 * Commonly known as Type 2e packets, or extended type 2 packets
 * Supports 4D addressing
 */
final class FSC39 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
		'dnet'			=> [0x16,'v',2],	// Dest Net
		'prodcode-lo'	=> [0x18,'C',1],	// Product Code
		'prodrev-maj'	=> [0x19,'C',1],	// Product Version Major
		'password'		=> [0x1a,'a8',8],	// Packet Password - http://ftsc.org/docs/fsc-0039.004 packet passwords are A-Z,0-9
		'ozone'			=> [0x22,'v',2],	// Orig Zone
		'dzone'			=> [0x24,'v',2],	// Dest Zone
		'reserved'		=> [0x26,'a2',2],	// Reserved
		'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 fsc-0039.004/fsc-0048.002
		'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 = '2e';
	public const VERS = self::MSG_TYPE2; //|self::MSG_TYPE4;

	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(Collection $msgs): string
	{
		$oldest = $this->messages->sortBy('date')->last();

		return pack(collect(self::HEADER)->pluck(1)->join(''),
			$this->fftn_p->node_id,				// Orig Node
			$this->tftn_p->node_id,						// Dest Node
			$oldest->datetime->format('Y'),				// Year
			$oldest->datetime->format('m')-1,			// Month
			$oldest->datetime->format('d'),				// Day
			$oldest->datetime->format('H'),				// Hour
			$oldest->datetime->format('i'),				// Minute
			$oldest->datetime->format('s'),				// Second
			0,											// Baud
			2,											// Packet Version (should be 2)
			$this->fftn_p->host_id,						// Orig Net
			$this->tftn_p->host_id,						// Dest Net
			(Setup::PRODUCT_ID & 0xff),					// Product Code Lo
			Setup::PRODUCT_VERSION_MAJ,					// Product Version Major
			$this->pass_p ?: $this->tftn_p->pass_packet,		// Packet Password
			$this->fftn_p->zone->zone_id,				// Orig Zone
			$this->tftn_p->zone->zone_id,				// Dest Zone
			'',											// Reserved
			static::VERS,								// fsc-0039.004 (copy of 0x2c)
			((Setup::PRODUCT_ID >> 8) & 0xff),			// Product Code Hi
			Setup::PRODUCT_VERSION_MIN,					// Product Version Minor
			static::VERS,								// Capability Word
			$this->fftn_p->zone->zone_id,				// Orig Zone
			$this->tftn_p->zone->zone_id,				// Dest Zone
			$this->fftn_p->point_id,					// Orig Point
			$this->tftn_p->point_id,					// Dest Point
			strtoupper(hexstr(Setup::PRODUCT_ID)),	// ProdData
		);
	}

	/**
	 * 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)
			&& (strlen(rtrim(Arr::get($head,'reserved'),"\x00")) === 0)
			&& (Arr::get($head,'capword') === Arr::get($head,'capvalid'))
			&& (Arr::get($head,'ozone') === Arr::get($head,'dozone'))
			&& (Arr::get($head,'dzone') === Arr::get($head,'ddzone'))
		);
	}
}