using System;
using QCRPG.Framework;
using QCRPG.TSL.FM.Packets;

namespace QCRPG.TSL.FM;

public class FMScripter : ScripterBase
{
	private FMAPI fmAPI;

	public FMScripter(FMAPI fmAPI)
	{
		this.fmAPI = fmAPI;
		modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this.fmAPI);
		tclCommandMap.Add("I2C_FMOpenComPort", I2C_FMOpenComPort_Handler);
		tclCommandMap.Add("I2C_FmOpenComPort", I2C_FMOpenComPort_Handler);
		tclCommandMap.Add("I2C_FMCloseComPort", I2C_FMCloseComPort_Handler);
		tclCommandMap.Add("I2C_FmCloseComPort", I2C_FMCloseComPort_Handler);
		tclCommandMap.Add("I2C_FMSetSlaveAddress", I2C_FMSetSlaveAddress_Handler);
		tclCommandMap.Add("I2C_FmSetSlaveAddress", I2C_FMSetSlaveAddress_Handler);
		tclCommandMap.Add("I2C_FMWriteCmd", I2C_FMWriteCmd_Handler);
		tclCommandMap.Add("I2C_FmWriteCmd", I2C_FMWriteCmd_Handler);
		tclCommandMap.Add("I2C_FMReadCmd", I2C_FMReadCmd_Handler);
		tclCommandMap.Add("I2C_FmReadCmd", I2C_FMReadCmd_Handler);
		tclCommandMap.Add("I2C_FMMultiPoke", I2C_FMMultiPoke_Handler);
		tclCommandMap.Add("I2C_FmMultiPoke", I2C_FMMultiPoke_Handler);
		tclCommandMap.Add("I2C_FMMultiPeek", I2C_FMMultiPeek_Handler);
		tclCommandMap.Add("I2C_FmMultiPeek", I2C_FMMultiPeek_Handler);
		tclCommandMap.Add("I2C_FMBlockPoke", I2C_FMBlockPoke_Handler);
		tclCommandMap.Add("I2C_FmBlockPoke", I2C_FMBlockPoke_Handler);
		tclCommandMap.Add("I2C_FMBlockPeek", I2C_FMBlockPeek_Handler);
		tclCommandMap.Add("I2C_FmBlockPeek", I2C_FMBlockPeek_Handler);
		tclCommandMap.Add("I2C_FMWaitISR", I2C_FMWaitISR_Handler);
		tclCommandMap.Add("I2C_FmWaitISR", I2C_FMWaitISR_Handler);
	}

	private TclResult I2C_FMOpenComPort_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
		{
			fmAPI.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_FMCloseComPort_Handler(string[] args)
	{
		try
		{
			fmAPI.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_FMSetSlaveAddress_Handler(string[] args)
	{
		byte b = 0;
		if (args.Length != 2)
		{
			TclWrapper.SetResult($"Wrong # of arguments.  Usage: {args[0]} ?i2cSlaveAddress?");
			return TclResult.ERROR;
		}
		if (!fmAPI.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
		{
			fmAPI.SetI2CSlaveAddress(b);
		}
		catch (Exception ex2)
		{
			TclWrapper.SetResult($"Caught exception setting FM slave address\r\nSource: {ex2.Source}\r\nMessage: {ex2.Message}");
			return TclResult.ERROR;
		}
		TclWrapper.SetResult("");
		return TclResult.OK;
	}

	private TclResult I2C_FMWriteCmd_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 (!fmAPI.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
			{
				fmAPI.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
			{
				fmAPI.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_FMReadCmd_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 (!fmAPI.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 = fmAPI.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 = fmAPI.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 I2C_FMMultiPoke_Handler(string[] args)
	{
		if (args.Length < 3 || args.Length > 11 || args.Length % 2 != 1)
		{
			TclWrapper.SetResult($"Wrong # of arguments.  Usage: {args[0]} ?address? ?data? ... (up to 5 address/data pairs)");
			return TclResult.ERROR;
		}
		if (!fmAPI.IsConnectionOpen())
		{
			TclWrapper.SetResult("Connection closed");
			return TclResult.ERROR;
		}
		MultiplePoke multiplePoke = new MultiplePoke();
		multiplePoke.UserFields.Length = (uint)((args.Length - 1) / 2);
		for (int i = 0; i < multiplePoke.UserFields.Length; i++)
		{
			int address;
			try
			{
				address = Conversions.PrefixedStringToInt(args[i * 2 + 1], 16) & 0xFFFF;
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"Error converting address {args[i * 2 + 1]} to an int");
				return TclResult.ERROR;
			}
			byte data;
			try
			{
				data = Conversions.PrefixedStringToByte(args[i * 2 + 2], 16);
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"Error converting value {args[i * 2 + 2]} to a byte");
				return TclResult.ERROR;
			}
			multiplePoke.UserFields.PokeInfoList[i].Address = (uint)address;
			multiplePoke.UserFields.PokeInfoList[i].Data = data;
		}
		try
		{
			fmAPI.Send(multiplePoke);
		}
		catch (Exception ex3)
		{
			TclWrapper.SetResult($"Caught exception trying to do multiple poke.\r\nSource: {ex3.Source}\r\nMessage: {ex3.Message}");
			return TclResult.ERROR;
		}
		TclWrapper.SetResult("");
		return TclResult.OK;
	}

	private TclResult I2C_FMMultiPeek_Handler(string[] args)
	{
		if (args.Length < 2 || args.Length > 9)
		{
			TclWrapper.SetResult($"Wrong # of arguments.  Usage: {args[0]} ?address? ... (up to 8 addresses)");
			return TclResult.ERROR;
		}
		if (!fmAPI.IsConnectionOpen())
		{
			TclWrapper.SetResult("Connection closed");
			return TclResult.ERROR;
		}
		MultiplePeek multiplePeek = new MultiplePeek();
		multiplePeek.UserFields.Length = (uint)(args.Length - 1);
		for (int i = 0; i < multiplePeek.UserFields.Length; i++)
		{
			int address;
			try
			{
				address = Conversions.PrefixedStringToInt(args[i + 1], 16) & 0xFFFF;
			}
			catch (Exception)
			{
				TclWrapper.SetResult($"Error converting address {args[i + 1]} to an int");
				return TclResult.ERROR;
			}
			multiplePeek.UserFields.PeekInfoList[i].Address = (uint)address;
		}
		try
		{
			fmAPI.Send(multiplePeek);
		}
		catch (Exception ex2)
		{
			TclWrapper.SetResult($"Caught exception trying to do multiple peek.\r\nSource: {ex2.Source}\r\nMessage: {ex2.Message}");
			return TclResult.ERROR;
		}
		ReadI2cResponse readI2cResponse;
		try
		{
			readI2cResponse = (ReadI2cResponse)modeAgnosticDataReceiver.Receive(1000);
		}
		catch (TimeoutException)
		{
			TclWrapper.SetResult($"Timeout waiting for multiple peek response");
			return TclResult.ERROR;
		}
		catch (Exception ex4)
		{
			TclWrapper.SetResult($"Caught exception waiting for multiple peek response.\r\nSource: {ex4.Source}\r\nMessage: {ex4.Message}");
			return TclResult.ERROR;
		}
		byte[] byteArray = Conversions.UintListToByteArray(readI2cResponse.UserFields.DataList);
		TclWrapper.SetResult(Conversions.ByteArrayTo0xHexString(byteArray));
		return TclResult.OK;
	}

	private TclResult I2C_FMBlockPoke_Handler(string[] args)
	{
		if (args.Length != 3)
		{
			TclWrapper.SetResult($"Wrong # of arguments.  Usage: {args[0]} ?address? ?data (1-14 bytes)?");
			return TclResult.ERROR;
		}
		if (!fmAPI.IsConnectionOpen())
		{
			TclWrapper.SetResult("Connection closed");
			return TclResult.ERROR;
		}
		int address;
		try
		{
			address = Conversions.PrefixedStringToInt(args[1], 16);
		}
		catch (Exception)
		{
			TclWrapper.SetResult($"Error converting address {args[1]} to an int");
			return TclResult.ERROR;
		}
		string[] array;
		try
		{
			array = TclWrapper.SplitList(args[2]);
		}
		catch (Exception)
		{
			TclWrapper.SetResult($"Error splitting {args[2]}");
			return TclResult.ERROR;
		}
		if (array.Length < 1 || array.Length > 14)
		{
			TclWrapper.SetResult("Invalid data length (must be 1-14)");
			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;
			}
		}
		BlockPoke blockPoke = new BlockPoke();
		blockPoke.UserFields.Length = (uint)array2.Length;
		blockPoke.UserFields.Address = (uint)address;
		for (int j = 0; j < array2.Length; j++)
		{
			blockPoke.UserFields.DataList[j] = array2[j];
		}
		try
		{
			fmAPI.Send(blockPoke);
		}
		catch (Exception ex4)
		{
			TclWrapper.SetResult($"Caught exception trying to do block poke.\r\nSource: {ex4.Source}\r\nMessage: {ex4.Message}");
			return TclResult.ERROR;
		}
		TclWrapper.SetResult(Conversions.ByteArrayTo0xHexString(array2));
		return TclResult.OK;
	}

	private TclResult I2C_FMBlockPeek_Handler(string[] args)
	{
		if (args.Length != 3)
		{
			TclWrapper.SetResult($"Wrong # of arguments.  Usage: {args[0]} ?address? ?length (1-15)?");
			return TclResult.ERROR;
		}
		if (!fmAPI.IsConnectionOpen())
		{
			TclWrapper.SetResult("Connection closed");
			return TclResult.ERROR;
		}
		int address;
		try
		{
			address = Conversions.PrefixedStringToInt(args[1], 16);
		}
		catch (Exception)
		{
			TclWrapper.SetResult($"Error converting address {args[1]} to an int");
			return TclResult.ERROR;
		}
		int num;
		try
		{
			num = Conversions.PrefixedStringToInt(args[2]);
		}
		catch (Exception)
		{
			TclWrapper.SetResult($"Error splitting {args[2]}");
			return TclResult.ERROR;
		}
		if (num < 1 || num > 15)
		{
			TclWrapper.SetResult("Invalid length (must be 1-15)");
			return TclResult.ERROR;
		}
		BlockPeek blockPeek = new BlockPeek();
		blockPeek.UserFields.Address = (uint)address;
		blockPeek.UserFields.Length = (uint)num;
		try
		{
			fmAPI.Send(blockPeek);
		}
		catch (Exception ex3)
		{
			TclWrapper.SetResult($"Caught exception trying to do block peek.\r\nSource: {ex3.Source}\r\nMessage: {ex3.Message}");
			return TclResult.ERROR;
		}
		ReadI2cResponse readI2cResponse;
		try
		{
			readI2cResponse = (ReadI2cResponse)modeAgnosticDataReceiver.Receive(1000);
		}
		catch (TimeoutException)
		{
			TclWrapper.SetResult($"Timeout waiting for multiple peek response");
			return TclResult.ERROR;
		}
		catch (Exception ex5)
		{
			TclWrapper.SetResult($"Caught exception waiting for multiple peek response.\r\nSource: {ex5.Source}\r\nMessage: {ex5.Message}");
			return TclResult.ERROR;
		}
		byte[] byteArray = Conversions.UintListToByteArray(readI2cResponse.UserFields.DataList);
		TclWrapper.SetResult(Conversions.ByteArrayTo0xHexString(byteArray));
		return TclResult.OK;
	}

	private TclResult I2C_FMWaitISR_Handler(string[] args)
	{
		if (args.Length > 2)
		{
			TclWrapper.SetResult($"Wrong # of arguments.  Usage: {args[0]} ?optional_timeout_in_seconds?");
			return TclResult.ERROR;
		}
		int timeoutMs = int.MaxValue;
		if (args.Length == 2)
		{
			int num = Conversions.PrefixedStringToInt(args[1]);
			timeoutMs = ((num > 0) ? (num * 1000) : (-1));
		}
		if (!fmAPI.IsConnectionOpen())
		{
			TclWrapper.SetResult("Connection closed");
			return TclResult.ERROR;
		}
		try
		{
			if (!fmAPI.WaitForInterrupt(timeoutMs))
			{
				TclWrapper.SetResult("");
				return TclResult.OK;
			}
		}
		catch (Exception ex)
		{
			TclWrapper.SetResult($"Caught exception waiting for interrupt.\r\nSource: {ex.Source}\r\nMessage: {ex.Message}");
			return TclResult.ERROR;
		}
		TclWrapper.SetResult("i");
		return TclResult.OK;
	}
}
