using System;
using System.Collections.Generic;
using QCRPG.Framework;
using QCRPG.TSL.NFC.Packets;

namespace QCRPG.TSL.NFC;

public class NFCScripter : ScripterBase
{
	protected NFCAPI nfcAPI;

	protected NFCPacketList nfcPacketList;

	protected Logger logger;

	protected NFCPacketHelper nfcPacketHelper;

	public NFCScripter(NFCAPI nfcAPI, NFCPacketList nfcPacketList, Logger logger)
	{
		this.nfcAPI = nfcAPI;
		this.nfcPacketList = nfcPacketList;
		this.logger = logger;
		nfcPacketHelper = new NFCPacketHelper(this.nfcPacketList);
		modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this.nfcAPI);
		tclCommandMap.Add("I2C_NFCOpenComPort", I2C_NFCOpenComPort_Handler);
		tclCommandMap.Add("I2C_NfcOpenComPort", I2C_NFCOpenComPort_Handler);
		tclCommandMap.Add("I2C_NFCCloseComPort", I2C_NFCCloseComPort_Handler);
		tclCommandMap.Add("I2C_NfcCloseComPort", I2C_NFCCloseComPort_Handler);
		tclCommandMap.Add("I2C_NFCSetSlaveAddress", I2C_NFCSetSlaveAddress_Handler);
		tclCommandMap.Add("I2C_NfcSetSlaveAddress", I2C_NFCSetSlaveAddress_Handler);
		tclCommandMap.Add("I2C_NFCWriteCmd", I2C_NFCWriteCmd_Handler);
		tclCommandMap.Add("I2C_NfcWriteCmd", I2C_NFCWriteCmd_Handler);
		tclCommandMap.Add("I2C_NFCReadCmd", I2C_NFCReadCmd_Handler);
		tclCommandMap.Add("I2C_NfcReadCmd", I2C_NFCReadCmd_Handler);
		tclCommandMap.Add("HCI_WaitNFCEvent", HCI_WaitNFCEvent_Handler);
		tclCommandMap.Add("HCI_WaitNfcEvent", HCI_WaitNFCEvent_Handler);
		tclCommandMap.Add("HCI_SendNFCRawCmd", HCI_SendNFCRawCmd_Handler);
		tclCommandMap.Add("HCI_SendNfcRawCmd", HCI_SendNFCRawCmd_Handler);
	}

	private TclResult I2C_NFCOpenComPort_Handler(string[] args)
	{
		int num = 0;
		string text = "";
		int num2 = 0;
		byte b = 0;
		if (args.Length != 4)
		{
			TclWrapper.SetResult($"Wrong # of arguments.  Usage: {args[0]} ?port? ?baudRate? ?i2cSlaveAddress?");
			return TclResult.ERROR;
		}
		try
		{
			text = "COM" + Conversions.PrefixedStringToInt(args[1]);
		}
		catch (Exception)
		{
			text = args[1];
		}
		try
		{
			num2 = Conversions.PrefixedStringToInt(args[2]);
		}
		catch (Exception)
		{
			TclWrapper.SetResult($"Error converting baudRate {args[2]} to an int");
			return TclResult.ERROR;
		}
		try
		{
			b = Conversions.PrefixedStringToByte(args[3]);
		}
		catch (Exception)
		{
			TclWrapper.SetResult($"Error converting i2cSlaveAddress {args[3]} to a byte");
			return TclResult.ERROR;
		}
		try
		{
			nfcAPI.OpenConnection(b, text, num2);
		}
		catch (Exception ex4)
		{
			TclWrapper.SetResult($"Caught exception opening connection.\r\nSource: {ex4.Source}\r\nMessage: {ex4.Message}");
			return TclResult.ERROR;
		}
		TclWrapper.SetResult("");
		return TclResult.OK;
	}

	private TclResult I2C_NFCCloseComPort_Handler(string[] args)
	{
		try
		{
			nfcAPI.CloseConnection();
		}
		catch (Exception ex)
		{
			TclWrapper.SetResult($"Caught exception closing connection.\r\nSource: {ex.Source}\r\nMessage: {ex.Message}");
			return TclResult.ERROR;
		}
		TclWrapper.SetResult("");
		return TclResult.OK;
	}

	private TclResult I2C_NFCSetSlaveAddress_Handler(string[] args)
	{
		byte b = 0;
		if (args.Length != 2)
		{
			TclWrapper.SetResult($"Wrong # of arguments.  Usage: {args[0]} ?i2cSlaveAddress?");
			return TclResult.ERROR;
		}
		if (!nfcAPI.IsConnectionOpen())
		{
			TclWrapper.SetResult("Connection closed");
			return TclResult.ERROR;
		}
		try
		{
			b = Conversions.PrefixedStringToByte(args[1]);
		}
		catch (Exception)
		{
			TclWrapper.SetResult($"Error converting i2cSlaveAddress {args[1]} to a byte");
			return TclResult.ERROR;
		}
		try
		{
			nfcAPI.SetI2CSlaveAddress(b);
		}
		catch (Exception ex2)
		{
			TclWrapper.SetResult($"Caught exception setting NFC slave address\r\nSource: {ex2.Source}\r\nMessage: {ex2.Message}");
			return TclResult.ERROR;
		}
		TclWrapper.SetResult("");
		return TclResult.OK;
	}

	private TclResult I2C_NFCWriteCmd_Handler(string[] args)
	{
		if (args.Length != 2 && args.Length != 3)
		{
			TclWrapper.SetResult(string.Format("Wrong # of arguments.  Usage: {0} ?data? or {0} ?registerAddress? ?data?", args[0]));
			return TclResult.ERROR;
		}
		if (!nfcAPI.IsConnectionOpen())
		{
			TclWrapper.SetResult("Connection closed");
			return TclResult.ERROR;
		}
		if (args.Length == 2)
		{
			string[] array;
			try
			{
				array = TclWrapper.SplitList(args[1]);
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"Error splitting {args[1]}");
				return TclResult.ERROR;
			}
			if (array.Length < 1 || array.Length > 255)
			{
				TclWrapper.SetResult("Invalid packet length (must be 1-255)");
				return TclResult.ERROR;
			}
			byte[] array2 = new byte[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				try
				{
					array2[i] = Conversions.PrefixedStringToByte(array[i], 16);
				}
				catch (Exception)
				{
					TclWrapper.SetResult($"Error converting {array[i]} to a byte");
					return TclResult.ERROR;
				}
			}
			try
			{
				nfcAPI.I2CWrite(array2);
			}
			catch (Exception ex3)
			{
				TclWrapper.SetResult($"Caught exception trying to do I2C write.\r\nSource: {ex3.Source}\r\nMessage: {ex3.Message}");
				return TclResult.ERROR;
			}
		}
		else
		{
			byte registerAddress;
			try
			{
				registerAddress = Conversions.PrefixedStringToByte(args[1], 16);
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"Error converting registerAddress {args[1]} to a byte");
				return TclResult.ERROR;
			}
			string[] array3;
			try
			{
				array3 = TclWrapper.SplitList(args[2]);
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"Error splitting {args[1]}");
				return TclResult.ERROR;
			}
			if (array3.Length < 1 || array3.Length > 255)
			{
				TclWrapper.SetResult("Invalid packet length (must be 1-255)");
				return TclResult.ERROR;
			}
			byte[] array4 = new byte[array3.Length];
			for (int j = 0; j < array3.Length; j++)
			{
				try
				{
					array4[j] = Conversions.PrefixedStringToByte(array3[j], 16);
				}
				catch (Exception)
				{
					TclWrapper.SetResult($"Error converting {array3[j]} to a byte");
					return TclResult.ERROR;
				}
			}
			try
			{
				nfcAPI.I2CWrite(registerAddress, array4);
			}
			catch (Exception ex7)
			{
				TclWrapper.SetResult($"Caught exception trying to do I2C write.\r\nSource: {ex7.Source}\r\nMessage: {ex7.Message}");
				return TclResult.ERROR;
			}
		}
		TclWrapper.SetResult("");
		return TclResult.OK;
	}

	private TclResult I2C_NFCReadCmd_Handler(string[] args)
	{
		if (args.Length != 2 && args.Length != 3)
		{
			TclWrapper.SetResult(string.Format("Wrong # of arguments.  Usage: {0} ?numberOfBytes? or {0} ?registerAddress? ?numberOfBytes?", args[0]));
			return TclResult.ERROR;
		}
		if (!nfcAPI.IsConnectionOpen())
		{
			TclWrapper.SetResult("Connection closed");
			return TclResult.ERROR;
		}
		byte[] byteArray;
		if (args.Length == 2)
		{
			byte length;
			try
			{
				length = Conversions.PrefixedStringToByte(args[1], 16);
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"Error converting numberOfBytes {args[1]} to a byte");
				return TclResult.ERROR;
			}
			try
			{
				byteArray = nfcAPI.I2CRead(length);
			}
			catch (TimeoutException)
			{
				TclWrapper.SetResult("Timeout waiting for I2C data");
				return TclResult.ERROR;
			}
			catch (Exception ex3)
			{
				TclWrapper.SetResult($"Caught exception trying to do I2C read.\r\nSource: {ex3.Source}\r\nMessage: {ex3.Message}");
				return TclResult.ERROR;
			}
		}
		else
		{
			byte length2;
			try
			{
				length2 = Conversions.PrefixedStringToByte(args[2], 16);
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"Error converting numberOfBytes {args[2]} to a byte");
				return TclResult.ERROR;
			}
			byte registerAddress;
			try
			{
				registerAddress = Conversions.PrefixedStringToByte(args[1], 16);
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"Error converting registerAddress {args[1]} to a byte");
				return TclResult.ERROR;
			}
			try
			{
				byteArray = nfcAPI.I2CRead(registerAddress, length2);
			}
			catch (TimeoutException)
			{
				TclWrapper.SetResult("Timeout waiting for I2C data");
				return TclResult.ERROR;
			}
			catch (Exception ex7)
			{
				TclWrapper.SetResult($"Caught exception trying to do I2C read.\r\nSource: {ex7.Source}\r\nMessage: {ex7.Message}");
				return TclResult.ERROR;
			}
		}
		TclWrapper.SetResult(Conversions.ByteArrayTo0xHexString(byteArray));
		return TclResult.OK;
	}

	private TclResult HCI_WaitNFCEvent_Handler(string[] args)
	{
		uint num = 0u;
		int num2 = 0;
		if (args.Length != 3)
		{
			TclWrapper.SetResult($"Wrong # of arguments.  Usage: {args[0]} ?opCode? ?timeoutSeconds?");
			return TclResult.ERROR;
		}
		try
		{
			int num3 = Convert.ToInt32(args[2]);
			num2 = ((num3 > 0) ? (num3 * 1000) : (-1));
		}
		catch (Exception)
		{
			TclWrapper.SetResult($"Error converting timeoutSeconds {args[2]} to an int");
			return TclResult.ERROR;
		}
		if (!nfcAPI.IsConnectionOpen())
		{
			TclWrapper.SetResult("Connection closed");
			return TclResult.ERROR;
		}
		PacketBase packetBase;
		if (args[1] == "ANY_EVENT")
		{
			try
			{
				List<Type> list = new List<Type>();
				list.AddRange(nfcPacketList.GetResponsePacketTypes());
				list.AddRange(nfcPacketList.GetNotificationPacketTypes());
				list.Add(typeof(Data));
				packetBase = modeAgnosticDataReceiver.Receive(list.ToArray(), num2);
			}
			catch (TimeoutException)
			{
				TclWrapper.SetResult("Timeout waiting for any NFC event");
				return TclResult.ERROR;
			}
			catch (Exception ex3)
			{
				TclWrapper.SetResult($"Caught exception waiting for any NFC event.\r\nSource: {ex3.Source}\r\nMessage: {ex3.Message}");
				return TclResult.ERROR;
			}
		}
		else
		{
			try
			{
				num = Convert.ToUInt32(args[1], 16);
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"Error converting opCode {args[1]} to a uint");
				return TclResult.ERROR;
			}
			if (num > 65535)
			{
				TclWrapper.SetResult($"Invalid opCode value (must be 0000-FFFF): {num}");
				return TclResult.ERROR;
			}
			List<Type> packetTypesMatchingOpCode;
			try
			{
				packetTypesMatchingOpCode = nfcPacketHelper.GetPacketTypesMatchingOpCode(num);
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"No known packet type matches the specified event, {args[1]}");
				return TclResult.ERROR;
			}
			try
			{
				packetBase = modeAgnosticDataReceiver.Receive(packetTypesMatchingOpCode.ToArray(), num2);
			}
			catch (TimeoutException)
			{
				TclWrapper.SetResult($"Timeout waiting for specific NFC event, {args[1]}");
				return TclResult.ERROR;
			}
			catch (Exception ex7)
			{
				TclWrapper.SetResult($"Caught exception waiting for specific NFC event, {args[1]}.\r\nSource: {ex7.Source}\r\nMessage: {ex7.Message}");
				return TclResult.ERROR;
			}
		}
		TclWrapper.SetResult(Conversions.ByteArrayToSpacedHexString(packetBase.ToByteArray()));
		return TclResult.OK;
	}

	private TclResult HCI_SendNFCRawCmd_Handler(string[] args)
	{
		if (args.Length != 2)
		{
			TclWrapper.SetResult($"Wrong # of arguments.  Usage: {args[0]} ?commandPacket? ");
			return TclResult.ERROR;
		}
		if (!nfcAPI.IsConnectionOpen())
		{
			TclWrapper.SetResult("Connection closed");
			return TclResult.ERROR;
		}
		string[] array;
		try
		{
			array = TclWrapper.SplitList(args[1]);
		}
		catch (Exception)
		{
			TclWrapper.SetResult($"Error splitting {args[1]}");
			return TclResult.ERROR;
		}
		if (array.Length < 3 || array.Length > 258)
		{
			TclWrapper.SetResult("Invalid packet length (must be 3-258)");
			return TclResult.ERROR;
		}
		byte[] array2 = new byte[array.Length];
		for (int i = 0; i < array.Length; i++)
		{
			try
			{
				array2[i] = Conversions.HexStringToByte(array[i]);
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"Error converting {array[i]} to a byte");
				return TclResult.ERROR;
			}
		}
		try
		{
			nfcAPI.Send(array2, performValidPacketCheck: true);
		}
		catch (Exception ex3)
		{
			TclWrapper.SetResult($"Caught exception sending data, {args[1]}.\r\nSource: {ex3.Source}\r\nMessage: {ex3.Message}");
			return TclResult.ERROR;
		}
		TclWrapper.SetResult("");
		return TclResult.OK;
	}
}
