using System;
using System.Collections.Generic;
using System.Linq;
using QCRPG.Framework;
using QCRPG.TSL.BT.Packets;

namespace QCRPG.TSL.BT;

public class ProtocolHCI : ProtocolCommon
{
	public enum SleepModeState
	{
		NONE,
		IN_BAND_NORMAL_HANDLING,
		IN_BAND_ALWAYS_AWAKE
	}

	public enum AclLogMode
	{
		FULL,
		SUMMARY,
		NONE
	}

	public struct EnhLog
	{
		public int enhLogId;

		public int payloadLength;

		public int seqNumber;

		public int logsLostProdId;

		public EnhLogDataHeader dataHeader;
	}

	public struct EnhLogDataHeader
	{
		public int logId;

		public byte logLevelFmt;

		public byte rfu;

		public int btClock;

		public int payloadLength;
	}

	private enum ReceiveState
	{
		NEW_PACKET,
		GETTING_PACKET_IDENTIFIER,
		GETTING_PAYLOAD_LENGTH,
		GETTING_PAYLOAD
	}

	private const int SLC_PKT_ID = 0;

	private const int LLM_CM_SM_PKT_ID = 513;

	private const int OVERHEAD_BYTES_FOR_ENHLOGLEN_PKTLOGLEN = 16;

	internal const int ENHLOG_ID = 3804;

	private const int ENHLOG_TOTAL_HEADERLEN_BEFORESPLIT = 21;

	private bool displayAllEnhLog;

	private Dictionary<uint, bool> allowedEnhancedLogIds = new Dictionary<uint, bool>();

	private List<byte> currentPacketReceived = new List<byte>();

	private BTPacketDataType currentPacketTypeReceived;

	private int gotPacketIdentifierLength;

	private int payloadLength;

	private int gotFullHeaderLength;

	private List<byte> incomingDataToSendAfterPostProcessing = new List<byte>();

	private AclData currentAclDataReceived;

	private QCRPG.Framework.IObserver<AclData> aclDataPacketObserver;

	private QCRPG.Framework.IObserver<IncomingPacketData>[] incomingAclDataObservers = new QCRPG.Framework.IObserver<IncomingPacketData>[2];

	private QCRPG.Framework.IObserver<OutgoingPacketData>[] outgoingAclDataObservers = new QCRPG.Framework.IObserver<OutgoingPacketData>[3];

	private SynchronousData currentScoDataReceived;

	private QCRPG.Framework.IObserver<SynchronousData> scoDataPacketObserver;

	private QCRPG.Framework.IObserver<IncomingPacketData>[] incomingScoDataObservers = new QCRPG.Framework.IObserver<IncomingPacketData>[2];

	private QCRPG.Framework.IObserver<OutgoingPacketData>[] outgoingScoDataObservers = new QCRPG.Framework.IObserver<OutgoingPacketData>[3];

	private IsoData currentIsoDataReceived;

	private QCRPG.Framework.IObserver<IsoData> isoDataPacketObserver;

	private QCRPG.Framework.IObserver<IncomingPacketData>[] incomingIsoDataObservers = new QCRPG.Framework.IObserver<IncomingPacketData>[2];

	private QCRPG.Framework.IObserver<OutgoingPacketData>[] outgoingIsoDataObservers = new QCRPG.Framework.IObserver<OutgoingPacketData>[3];

	private PacketDataNotification lastOutgoingModeSwitchNotification;

	private ReceiveState receiveState;

	private bool useUARTProtocolID = true;

	private bool enableSendModeSwitchNotifications;

	private AclLogMode aclMode = AclLogMode.SUMMARY;

	public bool DisplayEnhLogGUI
	{
		get
		{
			return displayAllEnhLog;
		}
		set
		{
			displayAllEnhLog = value;
		}
	}

	public Dictionary<uint, bool> AllowedEnhancedLogIds => allowedEnhancedLogIds;

	public override bool ReceiveStateIsNewPacket => receiveState == ReceiveState.NEW_PACKET;

	public bool UseUARTProtocolID
	{
		get
		{
			return useUARTProtocolID;
		}
		set
		{
			useUARTProtocolID = value;
		}
	}

	public bool EnableSendModeSwitchNotifications
	{
		get
		{
			return enableSendModeSwitchNotifications;
		}
		set
		{
			enableSendModeSwitchNotifications = value;
		}
	}

	public AclLogMode AclMode
	{
		get
		{
			return aclMode;
		}
		set
		{
			aclMode = value;
		}
	}

	public void Reset()
	{
		ClearCurrentPacket(notifyObserversAboutPostProcessingDataFirst: false);
		currentPacketTypeReceived = BTPacketDataType.Raw;
		lastOutgoingModeSwitchNotification = PacketDataNotification.Nop;
		receiveState = ReceiveState.NEW_PACKET;
	}

	public override void Send(OutgoingPacketData packetData)
	{
		LogDebugLine("Got data to send out: " + Conversions.ByteArrayToHexString(packetData.bytes));
		OutgoingPacketData outgoingPacketData = AddUARTProtocolIDByte(packetData);
		lock (sendDataNotifier)
		{
			SendModeSwitchNotification(packetData);
			SetSendRawDataFlag(outgoingPacketData);
			WakeUpDeviceIfNeeded();
			sendDataNotifier.NotifyObservers(outgoingPacketData);
			try
			{
				if (((BTOutgoingPacketData)packetData).btPacketType == BTPacketDataType.Command || ((BTOutgoingPacketData)packetData).btPacketType == BTPacketDataType.Raw)
				{
					PutDeviceToSleepIfNeeded();
				}
			}
			catch (Exception)
			{
			}
		}
	}

	private OutgoingPacketData AddUARTProtocolIDByte(OutgoingPacketData packetData)
	{
		byte b = 0;
		if (!useUARTProtocolID)
		{
			return packetData;
		}
		if (!(packetData is BTOutgoingPacketData))
		{
			IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, "Got non-BTOutgoingPacketData, protocol byte may or may not be added based on implementation");
			receiveDataNotifier.NotifyObservers(arg);
			return packetData;
		}
		BTOutgoingPacketData bTOutgoingPacketData = (BTOutgoingPacketData)packetData;
		if (bTOutgoingPacketData.btPacketType == BTPacketDataType.Raw)
		{
			return packetData;
		}
		if (bTOutgoingPacketData.btPacketType == BTPacketDataType.Command)
		{
			b = 1;
		}
		else if (bTOutgoingPacketData.btPacketType == BTPacketDataType.AclDataPacket)
		{
			b = 2;
		}
		else if (bTOutgoingPacketData.btPacketType == BTPacketDataType.SynchronousDataPacket)
		{
			b = 3;
		}
		else if (bTOutgoingPacketData.btPacketType == BTPacketDataType.Event)
		{
			b = 4;
		}
		else
		{
			if (bTOutgoingPacketData.btPacketType != BTPacketDataType.IsoDataPacket)
			{
				throw new Exception("Unsupported BT packet type: " + bTOutgoingPacketData.btPacketType);
			}
			b = 5;
		}
		List<byte> list = new List<byte>();
		list.Add(b);
		list.AddRange(packetData.bytes);
		return new OutgoingPacketData(list.ToArray());
	}

	private void SendModeSwitchNotification(OutgoingPacketData packetData)
	{
		if (!enableSendModeSwitchNotifications)
		{
			return;
		}
		if (!(packetData is BTOutgoingPacketData))
		{
			IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, "Got non-BTOutgoingPacketData, not performing mode switch notification check");
			receiveDataNotifier.NotifyObservers(arg);
			return;
		}
		BTOutgoingPacketData bTOutgoingPacketData = (BTOutgoingPacketData)packetData;
		PacketDataNotification packetDataNotification = PacketDataNotification.Nop;
		if (bTOutgoingPacketData.btPacketType == BTPacketDataType.Raw)
		{
			packetDataNotification = PacketDataNotification.SwitchToSendModeA;
		}
		else if (bTOutgoingPacketData.btPacketType == BTPacketDataType.Command)
		{
			packetDataNotification = PacketDataNotification.SwitchToSendModeA;
		}
		else
		{
			if (bTOutgoingPacketData.btPacketType != BTPacketDataType.AclDataPacket)
			{
				if (bTOutgoingPacketData.btPacketType == BTPacketDataType.SynchronousDataPacket)
				{
					packetDataNotification = PacketDataNotification.SwitchToSendModeC;
					lock (outgoingScoDataObservers)
					{
						foreach (QCRPG.Framework.IObserver<OutgoingPacketData> item in outgoingScoDataObservers.Where((QCRPG.Framework.IObserver<OutgoingPacketData> o) => o != null))
						{
							item.NotifyObserver(bTOutgoingPacketData);
						}
						return;
					}
				}
				throw new Exception("Unsupported BT packet type: " + bTOutgoingPacketData.btPacketType);
			}
			packetDataNotification = PacketDataNotification.SwitchToSendModeB;
		}
		if (lastOutgoingModeSwitchNotification != packetDataNotification)
		{
			lastOutgoingModeSwitchNotification = packetDataNotification;
			OutgoingPacketData arg2 = new OutgoingPacketData(PacketDataType.Notification, new byte[1] { (byte)packetDataNotification });
			sendDataNotifier.NotifyObservers(arg2);
		}
	}

	public void Send(AclData aclData)
	{
		uint dataLength = aclData._UserFields.DataLength;
		uint num = (uint)(dataLength + (useUARTProtocolID ? 5 : 4));
		byte[] array = new byte[num];
		int num2 = 0;
		if (useUARTProtocolID)
		{
			array[num2++] = 2;
		}
		array[num2++] = (byte)aclData._UserFields.Handle;
		array[num2++] = (byte)aclData._UserFields.Flags;
		array[num2++] = (byte)(dataLength & 0xFFu);
		array[num2++] = (byte)(dataLength >> 8);
		List<uint> dataList = aclData._UserFields.DataList;
		for (int i = 0; i < dataLength; i++)
		{
			array[num2 + i] = (byte)dataList[i];
		}
		BTOutgoingPacketData bTOutgoingPacketData = new BTOutgoingPacketData(null);
		bTOutgoingPacketData.bytes = array;
		bTOutgoingPacketData.btPacketType = BTPacketDataType.AclDataPacket;
		lock (sendDataNotifier)
		{
			if (enableSendModeSwitchNotifications && lastOutgoingModeSwitchNotification != PacketDataNotification.SwitchToSendModeB)
			{
				lastOutgoingModeSwitchNotification = PacketDataNotification.SwitchToSendModeB;
				OutgoingPacketData arg = new OutgoingPacketData(PacketDataType.Notification, new byte[1] { 6 });
				sendDataNotifier.NotifyObservers(arg);
			}
			SetSendRawDataFlag(bTOutgoingPacketData);
			WakeUpDeviceIfNeeded();
			lock (outgoingAclDataObservers)
			{
				foreach (QCRPG.Framework.IObserver<OutgoingPacketData> item in outgoingAclDataObservers.Where((QCRPG.Framework.IObserver<OutgoingPacketData> o) => o != null))
				{
					item.NotifyObserver(bTOutgoingPacketData);
				}
			}
		}
	}

	public void Send(SynchronousData scoData)
	{
		uint dataLength = scoData._UserFields.DataLength;
		uint num = (uint)(dataLength + (useUARTProtocolID ? 4 : 3));
		byte[] array = new byte[num];
		int num2 = 0;
		if (useUARTProtocolID)
		{
			array[num2++] = 3;
		}
		array[num2++] = (byte)scoData._UserFields.Handle;
		array[num2++] = (byte)scoData._UserFields.Flags;
		array[num2++] = (byte)(dataLength & 0xFFu);
		List<uint> dataList = scoData._UserFields.DataList;
		for (int i = 0; i < dataLength; i++)
		{
			array[num2 + i] = (byte)dataList[i];
		}
		BTOutgoingPacketData bTOutgoingPacketData = new BTOutgoingPacketData(null);
		bTOutgoingPacketData.bytes = array;
		bTOutgoingPacketData.btPacketType = BTPacketDataType.SynchronousDataPacket;
		lock (sendDataNotifier)
		{
			lock (outgoingScoDataObservers)
			{
				foreach (QCRPG.Framework.IObserver<OutgoingPacketData> item in outgoingScoDataObservers.Where((QCRPG.Framework.IObserver<OutgoingPacketData> o) => o != null))
				{
					item.NotifyObserver(bTOutgoingPacketData);
				}
			}
		}
	}

	public void Send(IsoData isoData)
	{
		List<byte> list = new List<byte>();
		if (useUARTProtocolID)
		{
			list.Add(5);
		}
		list.AddRange(isoData.ToByteArray().ToArray());
		byte[] array = list.ToArray();
		BTOutgoingPacketData bTOutgoingPacketData = new BTOutgoingPacketData(array);
		bTOutgoingPacketData.btPacketType = BTPacketDataType.IsoDataPacket;
		IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, $"Sent Bytes: {BitConverter.ToString(array).Replace('-', ' ')}");
		receiveDataNotifier.NotifyObservers(arg);
		lock (sendDataNotifier)
		{
			lock (outgoingIsoDataObservers)
			{
				foreach (QCRPG.Framework.IObserver<OutgoingPacketData> item in outgoingIsoDataObservers.Where((QCRPG.Framework.IObserver<OutgoingPacketData> o) => o != null))
				{
					item.NotifyObserver(bTOutgoingPacketData);
				}
			}
		}
	}

	public override void NotifyObserver(IncomingPacketData packetData)
	{
		LogDebugLine("Got incoming packet data: " + Conversions.ByteArrayToHexString(packetData.bytes) + " receiveState: " + receiveState);
		if (packetData.type == PacketDataType.Notification)
		{
			if (packetData.bytes[0] == 8)
			{
				currentPacketTypeReceived = BTPacketDataType.Event;
			}
			else if (packetData.bytes[0] == 9)
			{
				currentPacketTypeReceived = BTPacketDataType.AclDataPacket;
				if (aclDataPacketObserver != null)
				{
					currentAclDataReceived = new AclData();
				}
			}
			else
			{
				if (packetData.bytes[0] != 10)
				{
					SetSendRawDataFlag(packetData);
					receiveDataNotifier.NotifyObservers(packetData);
					return;
				}
				currentPacketTypeReceived = BTPacketDataType.SynchronousDataPacket;
				if (scoDataPacketObserver != null)
				{
					currentScoDataReceived = new SynchronousData();
				}
			}
			if (useUARTProtocolID)
			{
				IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, "Got switch receive mode notification when configured to use UART protocol ID byte");
				receiveDataNotifier.NotifyObservers(arg);
			}
			ClearCurrentPacket(notifyObserversAboutPostProcessingDataFirst: true);
			UpdatePacketParsingInfoAndReceiveState();
		}
		else if (packetData.type != 0)
		{
			receiveDataNotifier.NotifyObservers(packetData);
		}
		else if (useUARTProtocolID)
		{
			ReceiveWithProtocolIDCheck(packetData);
		}
		else
		{
			ReceiveWithoutProtocolIDCheck(packetData);
		}
	}

	private void ReceiveWithProtocolIDCheck(IncomingPacketData packetData)
	{
		int currentByteIndex = 0;
		while (currentByteIndex < packetData.bytes.Length)
		{
			if (receiveState == ReceiveState.NEW_PACKET)
			{
				if (ProcessSleepProtocolBytes(packetData, ref currentByteIndex))
				{
					continue;
				}
				incomingDataToSendAfterPostProcessing.Add(packetData.bytes[currentByteIndex]);
				if (packetData.bytes[currentByteIndex] == 5)
				{
					currentPacketTypeReceived = BTPacketDataType.IsoDataPacket;
					UpdatePacketParsingInfoAndReceiveState();
					if (isoDataPacketObserver != null)
					{
						currentIsoDataReceived = new IsoData();
					}
				}
				else if (packetData.bytes[currentByteIndex] == 4)
				{
					currentPacketTypeReceived = BTPacketDataType.Event;
					UpdatePacketParsingInfoAndReceiveState();
				}
				else if (packetData.bytes[currentByteIndex] == 3)
				{
					currentPacketTypeReceived = BTPacketDataType.SynchronousDataPacket;
					UpdatePacketParsingInfoAndReceiveState();
					if (scoDataPacketObserver != null)
					{
						currentScoDataReceived = new SynchronousData();
					}
				}
				else if (packetData.bytes[currentByteIndex] == 2)
				{
					currentPacketTypeReceived = BTPacketDataType.AclDataPacket;
					UpdatePacketParsingInfoAndReceiveState();
					if (aclDataPacketObserver != null)
					{
						currentAclDataReceived = new AclData();
					}
				}
				else if (packetData.bytes[currentByteIndex] == 1)
				{
					currentPacketTypeReceived = BTPacketDataType.Command;
					UpdatePacketParsingInfoAndReceiveState();
				}
				else
				{
					IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, "Unexpected protocol ID byte: 0x" + packetData.bytes[currentByteIndex].ToString("X2"));
					receiveDataNotifier.NotifyObservers(arg);
					LogDebugLine("ReceiveWithProtocolIDCheck: unexpected [" + currentByteIndex + "] " + Conversions.ByteArrayToHexString(packetData.bytes));
					ClearCurrentPacket(notifyObserversAboutPostProcessingDataFirst: true);
				}
			}
			else if (receiveState == ReceiveState.GETTING_PACKET_IDENTIFIER)
			{
				currentPacketReceived.Add(packetData.bytes[currentByteIndex]);
				incomingDataToSendAfterPostProcessing.Add(packetData.bytes[currentByteIndex]);
				if (currentPacketReceived.Count == gotPacketIdentifierLength)
				{
					if (currentPacketTypeReceived == BTPacketDataType.AclDataPacket && aclDataPacketObserver != null)
					{
						currentAclDataReceived._UserFields.Handle = currentPacketReceived[0];
						currentAclDataReceived._UserFields.Flags = currentPacketReceived[1];
					}
					else if (currentPacketTypeReceived == BTPacketDataType.SynchronousDataPacket && scoDataPacketObserver != null)
					{
						currentScoDataReceived._UserFields.Handle = currentPacketReceived[0];
						currentScoDataReceived._UserFields.Flags = currentPacketReceived[1];
					}
					else if (currentPacketTypeReceived == BTPacketDataType.IsoDataPacket)
					{
						_ = isoDataPacketObserver;
					}
					receiveState = ReceiveState.GETTING_PAYLOAD_LENGTH;
				}
			}
			else if (receiveState == ReceiveState.GETTING_PAYLOAD_LENGTH)
			{
				currentPacketReceived.Add(packetData.bytes[currentByteIndex]);
				incomingDataToSendAfterPostProcessing.Add(packetData.bytes[currentByteIndex]);
				if (currentPacketReceived.Count == gotFullHeaderLength)
				{
					if (currentPacketTypeReceived == BTPacketDataType.AclDataPacket || currentPacketTypeReceived == BTPacketDataType.IsoDataPacket)
					{
						payloadLength = currentPacketReceived[gotFullHeaderLength - 2];
						payloadLength += currentPacketReceived[gotFullHeaderLength - 1] * 256;
					}
					else
					{
						payloadLength = currentPacketReceived[gotFullHeaderLength - 1];
					}
					receiveState = ReceiveState.GETTING_PAYLOAD;
					if (payloadLength == 0)
					{
						HandleCompletePacket();
						receiveState = ReceiveState.NEW_PACKET;
					}
				}
			}
			else
			{
				if (receiveState != ReceiveState.GETTING_PAYLOAD)
				{
					throw new Exception("Unsupported receive state: " + receiveState);
				}
				bool flag;
				if (currentPacketTypeReceived == BTPacketDataType.AclDataPacket && aclDataPacketObserver != null)
				{
					currentAclDataReceived._UserFields.DataList.Add(packetData.bytes[currentByteIndex]);
					flag = currentAclDataReceived._UserFields.DataList.Count == payloadLength;
				}
				else if (currentPacketTypeReceived == BTPacketDataType.SynchronousDataPacket && scoDataPacketObserver != null)
				{
					currentScoDataReceived._UserFields.DataList.Add(packetData.bytes[currentByteIndex]);
					flag = currentScoDataReceived._UserFields.DataList.Count == payloadLength;
				}
				else if (currentPacketTypeReceived == BTPacketDataType.IsoDataPacket && isoDataPacketObserver != null)
				{
					currentPacketReceived.Add(packetData.bytes[currentByteIndex]);
					flag = currentPacketReceived.Count == gotFullHeaderLength + payloadLength;
				}
				else
				{
					currentPacketReceived.Add(packetData.bytes[currentByteIndex]);
					flag = currentPacketReceived.Count == gotFullHeaderLength + payloadLength;
				}
				incomingDataToSendAfterPostProcessing.Add(packetData.bytes[currentByteIndex]);
				if (flag)
				{
					HandleCompletePacket();
					receiveState = ReceiveState.NEW_PACKET;
				}
			}
			currentByteIndex++;
		}
	}

	private void ReceiveWithoutProtocolIDCheck(IncomingPacketData packetData)
	{
		for (int i = 0; i < packetData.bytes.Length; i++)
		{
			if (receiveState == ReceiveState.NEW_PACKET)
			{
				currentPacketReceived.Add(packetData.bytes[i]);
				incomingDataToSendAfterPostProcessing.Add(packetData.bytes[i]);
				if (currentPacketReceived.Count == gotPacketIdentifierLength)
				{
					if (currentPacketTypeReceived == BTPacketDataType.AclDataPacket && aclDataPacketObserver != null)
					{
						currentAclDataReceived = new AclData();
						currentAclDataReceived._UserFields.Handle = currentPacketReceived[0];
						currentAclDataReceived._UserFields.Flags = currentPacketReceived[1];
					}
					else if (currentPacketTypeReceived == BTPacketDataType.SynchronousDataPacket && scoDataPacketObserver != null)
					{
						currentScoDataReceived = new SynchronousData();
						currentScoDataReceived._UserFields.Handle = currentPacketReceived[0];
						currentScoDataReceived._UserFields.Flags = currentPacketReceived[1];
					}
					receiveState = ReceiveState.GETTING_PAYLOAD_LENGTH;
				}
				continue;
			}
			if (receiveState == ReceiveState.GETTING_PAYLOAD_LENGTH)
			{
				currentPacketReceived.Add(packetData.bytes[i]);
				incomingDataToSendAfterPostProcessing.Add(packetData.bytes[i]);
				if (currentPacketReceived.Count == gotFullHeaderLength)
				{
					if (currentPacketTypeReceived == BTPacketDataType.AclDataPacket)
					{
						payloadLength = currentPacketReceived[gotFullHeaderLength - 2];
						payloadLength += currentPacketReceived[gotFullHeaderLength - 1] * 256;
					}
					else
					{
						payloadLength = currentPacketReceived[gotFullHeaderLength - 1];
					}
					receiveState = ReceiveState.GETTING_PAYLOAD;
					if (payloadLength == 0)
					{
						HandleCompletePacket();
						receiveState = ReceiveState.NEW_PACKET;
					}
				}
				continue;
			}
			if (receiveState == ReceiveState.GETTING_PAYLOAD)
			{
				bool flag;
				if (currentPacketTypeReceived == BTPacketDataType.AclDataPacket && aclDataPacketObserver != null)
				{
					currentAclDataReceived._UserFields.DataList.Add(packetData.bytes[i]);
					flag = currentAclDataReceived._UserFields.DataList.Count == payloadLength;
				}
				else if (currentPacketTypeReceived == BTPacketDataType.SynchronousDataPacket && scoDataPacketObserver != null)
				{
					currentScoDataReceived._UserFields.DataList.Add(packetData.bytes[i]);
					flag = currentScoDataReceived._UserFields.DataList.Count == payloadLength;
				}
				else
				{
					currentPacketReceived.Add(packetData.bytes[i]);
					incomingDataToSendAfterPostProcessing.Add(packetData.bytes[i]);
					flag = currentPacketReceived.Count == gotFullHeaderLength + payloadLength;
				}
				if (flag)
				{
					HandleCompletePacket();
					receiveState = ReceiveState.NEW_PACKET;
				}
				continue;
			}
			throw new Exception("Unsupported receive state: " + receiveState);
		}
	}

	private void UpdatePacketParsingInfoAndReceiveState()
	{
		if (useUARTProtocolID)
		{
			receiveState = ReceiveState.GETTING_PACKET_IDENTIFIER;
		}
		else
		{
			receiveState = ReceiveState.NEW_PACKET;
		}
		if (currentPacketTypeReceived == BTPacketDataType.Event)
		{
			gotPacketIdentifierLength = 1;
			gotFullHeaderLength = 2;
			return;
		}
		if (currentPacketTypeReceived == BTPacketDataType.IsoDataPacket)
		{
			gotPacketIdentifierLength = 2;
			gotFullHeaderLength = 4;
			return;
		}
		if (currentPacketTypeReceived == BTPacketDataType.SynchronousDataPacket)
		{
			gotPacketIdentifierLength = 2;
			gotFullHeaderLength = 3;
			return;
		}
		if (currentPacketTypeReceived == BTPacketDataType.AclDataPacket)
		{
			gotPacketIdentifierLength = 2;
			gotFullHeaderLength = 4;
			return;
		}
		if (currentPacketTypeReceived == BTPacketDataType.Command && useUARTProtocolID)
		{
			gotPacketIdentifierLength = 2;
			gotFullHeaderLength = 3;
			return;
		}
		IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, "Unexpected packet type: " + currentPacketTypeReceived);
		receiveDataNotifier.NotifyObservers(arg);
		ClearCurrentPacket(notifyObserversAboutPostProcessingDataFirst: true);
		receiveState = ReceiveState.NEW_PACKET;
	}

	public new void RegisterReceiveDataObserverPostProcessing(QCRPG.Framework.IObserver<IncomingPacketData> observer)
	{
		receiveDataNotifierPostProcessing.RegisterObserver(observer);
	}

	public new void UnregisterReceiveDataObserverPostProcessing(QCRPG.Framework.IObserver<IncomingPacketData> observer)
	{
		receiveDataNotifierPostProcessing.UnregisterObserver(observer);
	}

	public void RegisterReceiveSCODataPacketObserver(QCRPG.Framework.IObserver<SynchronousData> observer)
	{
		if (scoDataPacketObserver != observer)
		{
			scoDataPacketObserver = observer;
		}
	}

	public void UnregisterReceiveSCODataPacketObserver(QCRPG.Framework.IObserver<SynchronousData> observer)
	{
		if (scoDataPacketObserver == observer)
		{
			scoDataPacketObserver = null;
		}
	}

	public void RegisterSendSCODataObserver(QCRPG.Framework.IObserver<OutgoingPacketData> observer)
	{
		lock (outgoingScoDataObservers)
		{
			if (outgoingScoDataObservers.Contains(observer))
			{
				return;
			}
			for (int i = 0; i < outgoingScoDataObservers.Length; i++)
			{
				if (outgoingScoDataObservers[i] == null)
				{
					outgoingScoDataObservers[i] = observer;
					return;
				}
			}
		}
		IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, $"Max. no. of SCO data observers added, {observer} not added to list");
		receiveDataNotifier.NotifyObservers(arg);
	}

	public void UnregisterSendSCODataObserver(QCRPG.Framework.IObserver<OutgoingPacketData> observer)
	{
		lock (outgoingScoDataObservers)
		{
			for (int i = 0; i < outgoingScoDataObservers.Length; i++)
			{
				if (outgoingScoDataObservers[i] == observer)
				{
					outgoingScoDataObservers[i] = null;
					break;
				}
			}
		}
	}

	public void RegisterReceiveSCODataObserver(QCRPG.Framework.IObserver<IncomingPacketData> observer)
	{
		lock (incomingScoDataObservers)
		{
			if (incomingScoDataObservers.Contains(observer))
			{
				return;
			}
			for (int i = 0; i < incomingScoDataObservers.Length; i++)
			{
				if (incomingScoDataObservers[i] == null)
				{
					incomingScoDataObservers[i] = observer;
					return;
				}
			}
		}
		IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, $"Max. no. of SCO data observers added, {observer} not added to list");
		receiveDataNotifier.NotifyObservers(arg);
	}

	public void UnregisterReceiveSCODataObserver(QCRPG.Framework.IObserver<IncomingPacketData> observer)
	{
		lock (incomingScoDataObservers)
		{
			for (int i = 0; i < incomingScoDataObservers.Length; i++)
			{
				if (incomingScoDataObservers[i] == observer)
				{
					incomingScoDataObservers[i] = null;
					break;
				}
			}
		}
	}

	public void RegisterReceiveACLDataPacketObserver(QCRPG.Framework.IObserver<AclData> observer)
	{
		if (aclDataPacketObserver != observer)
		{
			aclDataPacketObserver = observer;
		}
	}

	public void UnregisterReceiveACLDataPacketObserver(QCRPG.Framework.IObserver<AclData> observer)
	{
		if (aclDataPacketObserver == observer)
		{
			aclDataPacketObserver = null;
		}
	}

	public void RegisterSendACLDataObserver(QCRPG.Framework.IObserver<OutgoingPacketData> observer)
	{
		lock (outgoingAclDataObservers)
		{
			if (outgoingAclDataObservers.Contains(observer))
			{
				return;
			}
			for (int i = 0; i < outgoingAclDataObservers.Length; i++)
			{
				if (outgoingAclDataObservers[i] == null)
				{
					outgoingAclDataObservers[i] = observer;
					return;
				}
			}
		}
		IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, $"Max. no. of ACL data observers added, {observer} not added to list");
		receiveDataNotifier.NotifyObservers(arg);
	}

	public void UnregisterSendACLDataObserver(QCRPG.Framework.IObserver<OutgoingPacketData> observer)
	{
		lock (outgoingAclDataObservers)
		{
			for (int i = 0; i < outgoingAclDataObservers.Length; i++)
			{
				if (outgoingAclDataObservers[i] == observer)
				{
					outgoingAclDataObservers[i] = null;
					break;
				}
			}
		}
	}

	public void RegisterReceiveACLDataObserver(QCRPG.Framework.IObserver<IncomingPacketData> observer)
	{
		lock (incomingAclDataObservers)
		{
			if (incomingAclDataObservers.Contains(observer))
			{
				return;
			}
			for (int i = 0; i < incomingAclDataObservers.Length; i++)
			{
				if (incomingAclDataObservers[i] == null)
				{
					incomingAclDataObservers[i] = observer;
					return;
				}
			}
		}
		IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, $"Max. no. of ACL data observers added, {observer} not added to list");
		receiveDataNotifier.NotifyObservers(arg);
	}

	public void UnregisterReceiveACLDataObserver(QCRPG.Framework.IObserver<IncomingPacketData> observer)
	{
		lock (incomingAclDataObservers)
		{
			for (int i = 0; i < incomingAclDataObservers.Length; i++)
			{
				if (incomingAclDataObservers[i] == observer)
				{
					incomingAclDataObservers[i] = null;
					break;
				}
			}
		}
	}

	public void RegisterReceiveISODataPacketObserver(QCRPG.Framework.IObserver<IsoData> observer)
	{
		if (isoDataPacketObserver != observer)
		{
			isoDataPacketObserver = observer;
		}
	}

	public void UnregisterReceiveISODataPacketObserver(QCRPG.Framework.IObserver<IsoData> observer)
	{
		if (isoDataPacketObserver == observer)
		{
			isoDataPacketObserver = null;
		}
	}

	public void RegisterSendISODataObserver(QCRPG.Framework.IObserver<OutgoingPacketData> observer)
	{
		lock (outgoingIsoDataObservers)
		{
			if (outgoingIsoDataObservers.Contains(observer))
			{
				return;
			}
			for (int i = 0; i < outgoingIsoDataObservers.Length; i++)
			{
				if (outgoingIsoDataObservers[i] == null)
				{
					outgoingIsoDataObservers[i] = observer;
					return;
				}
			}
		}
		IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, $"Max. no. of ISO data observers added, {observer} not added to list");
		receiveDataNotifier.NotifyObservers(arg);
	}

	public void UnregisterSendISODataObserver(QCRPG.Framework.IObserver<OutgoingPacketData> observer)
	{
		lock (outgoingIsoDataObservers)
		{
			for (int i = 0; i < outgoingIsoDataObservers.Length; i++)
			{
				if (outgoingIsoDataObservers[i] == observer)
				{
					outgoingIsoDataObservers[i] = null;
					break;
				}
			}
		}
	}

	public void RegisterReceiveISODataObserver(QCRPG.Framework.IObserver<IncomingPacketData> observer)
	{
		lock (incomingIsoDataObservers)
		{
			if (incomingIsoDataObservers.Contains(observer))
			{
				return;
			}
			for (int i = 0; i < incomingIsoDataObservers.Length; i++)
			{
				if (incomingIsoDataObservers[i] == null)
				{
					incomingIsoDataObservers[i] = observer;
					return;
				}
			}
		}
		IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, $"Max. no. of ISO data observers added, {observer} not added to list");
		receiveDataNotifier.NotifyObservers(arg);
	}

	public void UnregisterReceiveISODataObserver(QCRPG.Framework.IObserver<IncomingPacketData> observer)
	{
		lock (incomingIsoDataObservers)
		{
			for (int i = 0; i < incomingIsoDataObservers.Length; i++)
			{
				if (incomingIsoDataObservers[i] == observer)
				{
					incomingIsoDataObservers[i] = null;
					break;
				}
			}
		}
	}

	private void HandleCompletePacket()
	{
		LogDebugLine("HandleCompletePacket()");
		if (currentPacketTypeReceived == BTPacketDataType.IsoDataPacket && isoDataPacketObserver != null)
		{
			currentIsoDataReceived.IsoDataLoadLength = (uint)payloadLength;
			currentIsoDataReceived.Flags |= 4u;
			try
			{
				currentIsoDataReceived.FromByteArray(currentPacketReceived.ToArray());
				isoDataPacketObserver.NotifyObserver(currentIsoDataReceived);
			}
			catch (Exception)
			{
				IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, "Invalid ISO data: " + BitConverter.ToString(currentPacketReceived.ToArray()).Replace('-', ' '));
				receiveDataNotifier.NotifyObservers(arg);
			}
		}
		else if (currentPacketTypeReceived == BTPacketDataType.SynchronousDataPacket && scoDataPacketObserver != null)
		{
			currentScoDataReceived._UserFields.DataLength = (uint)payloadLength;
			currentScoDataReceived.Flags |= 4u;
			scoDataPacketObserver.NotifyObserver(currentScoDataReceived);
		}
		else if (currentPacketTypeReceived == BTPacketDataType.AclDataPacket && aclDataPacketObserver != null && currentPacketReceived[0] == 220 && (currentPacketReceived[1] & 0xF) == 14)
		{
			currentPacketTypeReceived = BTPacketDataType.EnhancedLog;
			try
			{
				SplitAndParseEnhancedLogPackets(incomingDataToSendAfterPostProcessing);
			}
			catch (Exception)
			{
				IncomingPacketData arg2 = new IncomingPacketData(PacketDataType.WarningMessage, "Invalid enhanced log bytes: " + BitConverter.ToString(currentPacketReceived.ToArray()).Replace('-', ' '));
				receiveDataNotifier.NotifyObservers(arg2);
			}
		}
		else if (currentPacketTypeReceived == BTPacketDataType.AclDataPacket && aclDataPacketObserver != null)
		{
			lock (incomingAclDataObservers)
			{
				IncomingPacketData incomingPacketData = new IncomingPacketData((Exception)null);
				QCRPG.Framework.IObserver<IncomingPacketData>[] array = incomingAclDataObservers;
				foreach (QCRPG.Framework.IObserver<IncomingPacketData> observer in array)
				{
					if (observer != null)
					{
						if (incomingPacketData.bytes == null || incomingPacketData.bytes.Length == 0)
						{
							incomingPacketData.bytes = incomingDataToSendAfterPostProcessing.ToArray();
							SetSendRawDataFlag(incomingPacketData, currentPacketTypeReceived);
						}
						observer.NotifyObserver(incomingPacketData);
					}
				}
			}
			currentAclDataReceived._UserFields.DataLength = (uint)payloadLength;
			currentAclDataReceived.Flags |= 4u;
			aclDataPacketObserver.NotifyObserver(currentAclDataReceived);
			if (aclMode == AclLogMode.FULL)
			{
				IncomingPacketData incomingPacketData2 = new IncomingPacketData(incomingDataToSendAfterPostProcessing.ToArray());
				SetSendRawDataFlag(incomingPacketData2, currentPacketTypeReceived);
				receiveDataNotifierPostProcessing.NotifyObservers(incomingPacketData2);
			}
		}
		else
		{
			IncomingPacketData incomingPacketData3 = new IncomingPacketData(incomingDataToSendAfterPostProcessing.ToArray());
			SetSendRawDataFlag(incomingPacketData3, currentPacketTypeReceived);
			receiveDataNotifierPostProcessing.NotifyObservers(incomingPacketData3);
			BTIncomingPacketData bTIncomingPacketData = new BTIncomingPacketData(currentPacketReceived.ToArray());
			bTIncomingPacketData.btPacketType = currentPacketTypeReceived;
			SetSendRawDataFlag(bTIncomingPacketData);
			receiveDataNotifier.NotifyObservers(bTIncomingPacketData);
		}
		ClearCurrentPacket(notifyObserversAboutPostProcessingDataFirst: false);
		sendDataNotifier.NotifyObservers(new OutgoingPacketData(PacketDataType.Notification, 11));
	}

	private void ClearCurrentPacket(bool notifyObserversAboutPostProcessingDataFirst)
	{
		if (notifyObserversAboutPostProcessingDataFirst)
		{
			IncomingPacketData incomingPacketData = new IncomingPacketData(incomingDataToSendAfterPostProcessing.ToArray());
			SetSendRawDataFlag(incomingPacketData, currentPacketTypeReceived);
			receiveDataNotifierPostProcessing.NotifyObservers(incomingPacketData);
		}
		incomingDataToSendAfterPostProcessing.Clear();
		currentPacketReceived.Clear();
	}

	private void SetSendRawDataFlag(PacketData packetData)
	{
		if (packetData is BTIncomingPacketData)
		{
			SetSendRawDataFlag(packetData, ((BTIncomingPacketData)packetData).btPacketType);
		}
		else if (packetData is BTOutgoingPacketData)
		{
			SetSendRawDataFlag(packetData, ((BTOutgoingPacketData)packetData).btPacketType);
		}
	}

	private void SetSendRawDataFlag(PacketData packetData, BTPacketDataType btPacketDataType)
	{
		switch (btPacketDataType)
		{
		case BTPacketDataType.AclDataPacket:
			packetData.suppressRawByteLogging = aclMode != AclLogMode.FULL;
			break;
		case BTPacketDataType.SynchronousDataPacket:
			break;
		case BTPacketDataType.EnhancedLog:
			packetData.suppressRawByteLogging = true;
			break;
		case BTPacketDataType.IsoDataPacket:
			packetData.suppressRawByteLogging = aclMode != AclLogMode.FULL;
			break;
		default:
			packetData.suppressRawByteLogging = false;
			break;
		}
	}

	private void SplitAndParseEnhancedLogPackets(List<byte> packet)
	{
		if (packet.Count < 21)
		{
			IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, "SLC packet with unexpectedly short header");
			receiveDataNotifier.NotifyObservers(arg);
			return;
		}
		EnhLog enhLogHeader = default(EnhLog);
		List<byte> list = new List<byte>();
		int num = 0;
		int protocolByte = packet[num++];
		int num2 = 0;
		enhLogHeader.enhLogId = packet[num++];
		enhLogHeader.enhLogId += packet[num++] << 8;
		enhLogHeader.payloadLength = packet[num++];
		enhLogHeader.payloadLength += packet[num++] << 8;
		enhLogHeader.seqNumber = packet[num++];
		enhLogHeader.seqNumber += packet[num++] << 8;
		enhLogHeader.logsLostProdId = packet[num++];
		enhLogHeader.logsLostProdId += packet[num++] << 8;
		enhLogHeader.logsLostProdId += packet[num++] << 16;
		enhLogHeader.logsLostProdId += packet[num++] << 24;
		num2 = enhLogHeader.payloadLength;
		while (num < num2)
		{
			enhLogHeader.dataHeader.logId = packet[num++];
			enhLogHeader.dataHeader.logId += packet[num++] << 8;
			enhLogHeader.dataHeader.logLevelFmt = packet[num++];
			enhLogHeader.dataHeader.rfu = packet[num++];
			enhLogHeader.dataHeader.btClock = packet[num++];
			enhLogHeader.dataHeader.btClock += packet[num++] << 8;
			enhLogHeader.dataHeader.btClock += packet[num++] << 16;
			enhLogHeader.dataHeader.btClock += packet[num++] << 24;
			enhLogHeader.dataHeader.payloadLength = packet[num++];
			enhLogHeader.dataHeader.payloadLength += packet[num++] << 8;
			if (enhLogHeader.dataHeader.logId == 0)
			{
				int num3 = 0;
				int num4 = 0;
				while (num < packet.Count)
				{
					list.Clear();
					switch (packet[num] >> 6)
					{
					case 0:
						num3 = 2;
						break;
					case 1:
						num3 = 3;
						break;
					case 2:
						num3 = 5;
						break;
					case 3:
					{
						if (num + 1 < payloadLength && packet[num + 1] < 128)
						{
							num3 = packet[num + 1] + 2;
							break;
						}
						if (num + 1 < payloadLength)
						{
							num3 = (packet[num + 2] << 8) + (packet[num + 1] & 0x7F);
							break;
						}
						IncomingPacketData arg3 = new IncomingPacketData(PacketDataType.WarningMessage, "Invalid SLC packet length");
						receiveDataNotifier.NotifyObservers(arg3);
						return;
					}
					default:
					{
						IncomingPacketData arg2 = new IncomingPacketData(PacketDataType.WarningMessage, "Invalid SLC packet");
						receiveDataNotifier.NotifyObservers(arg2);
						return;
					}
					}
					for (int i = num; i < num + num3; i++)
					{
						list.Add(packet[i]);
					}
					num += num3;
					enhLogHeader.dataHeader.payloadLength = num3;
					enhLogHeader.dataHeader.payloadLength += num3 >> 8;
					num4 = (enhLogHeader.payloadLength = num3 + 16);
					enhLogHeader.payloadLength += num4 >> 8;
					enhLogHeader.seqNumber = num4 - 4;
					enhLogHeader.seqNumber += num4 - 4 >> 8;
					EnhLoggingWriteSendPacket(enhLogHeader, list, protocolByte);
				}
			}
			else
			{
				int num4 = (enhLogHeader.payloadLength = enhLogHeader.dataHeader.payloadLength + 16);
				enhLogHeader.payloadLength += num4 >> 8;
				enhLogHeader.seqNumber = num4 - 4;
				enhLogHeader.seqNumber += num4 - 4 >> 8;
				list.Clear();
				for (int j = num; j < num + enhLogHeader.dataHeader.payloadLength; j++)
				{
					list.Add(packet[j]);
				}
				num += enhLogHeader.dataHeader.payloadLength;
				EnhLoggingWriteSendPacket(enhLogHeader, list, protocolByte);
			}
		}
	}

	private void EnhLoggingWriteSendPacket(EnhLog enhLogHeader, List<byte> dataBytes, int protocolByte)
	{
		List<byte> list = new List<byte>();
		list.Clear();
		list.Add((byte)protocolByte);
		list.Add((byte)enhLogHeader.enhLogId);
		list.Add((byte)(enhLogHeader.enhLogId >> 8));
		list.Add((byte)enhLogHeader.payloadLength);
		list.Add((byte)(enhLogHeader.payloadLength >> 8));
		list.Add((byte)enhLogHeader.seqNumber);
		list.Add((byte)(enhLogHeader.seqNumber >> 8));
		list.Add((byte)enhLogHeader.logsLostProdId);
		list.Add((byte)(enhLogHeader.logsLostProdId >> 8));
		list.Add((byte)(enhLogHeader.logsLostProdId >> 16));
		list.Add((byte)(enhLogHeader.logsLostProdId >> 24));
		list.Add((byte)enhLogHeader.dataHeader.logId);
		list.Add((byte)(enhLogHeader.dataHeader.logId >> 8));
		list.Add(enhLogHeader.dataHeader.logLevelFmt);
		list.Add(enhLogHeader.dataHeader.rfu);
		list.Add((byte)enhLogHeader.dataHeader.btClock);
		list.Add((byte)(enhLogHeader.dataHeader.btClock >> 8));
		list.Add((byte)(enhLogHeader.dataHeader.btClock >> 16));
		list.Add((byte)(enhLogHeader.dataHeader.btClock >> 24));
		list.Add((byte)enhLogHeader.dataHeader.payloadLength);
		list.Add((byte)(enhLogHeader.dataHeader.payloadLength >> 8));
		IEnumerable<byte> source = list.Concat(dataBytes);
		IncomingPacketData incomingPacketData = new IncomingPacketData((Exception)null);
		incomingPacketData.bytes = source.ToArray();
		SetSendRawDataFlag(incomingPacketData);
		receiveDataNotifierPostProcessing.NotifyObservers(incomingPacketData);
		bool value = false;
		allowedEnhancedLogIds.TryGetValue((uint)enhLogHeader.dataHeader.logId, out value);
		if (displayAllEnhLog || value)
		{
			BTIncomingPacketData bTIncomingPacketData = new BTIncomingPacketData(source.Skip(1).ToArray());
			bTIncomingPacketData.btPacketType = currentPacketTypeReceived;
			SetSendRawDataFlag(bTIncomingPacketData);
			receiveDataNotifier.NotifyObservers(bTIncomingPacketData);
		}
	}

	private void LogDebugLine(string line)
	{
	}
}
