using System;
using System.Collections.Generic;
using System.IO.Ports;
using QC.QMSLPhone;

namespace QCRPG.Framework;

public class APIBase : IObserver<PacketBase>, IObserver<OutgoingPacketData>, IObserver<PacketDecodeInfo>
{
	public delegate bool CustomSendPacketHandlerDelegate(PacketBase packet);

	protected PacketListBase packetList;

	protected Logger logger;

	protected PacketReceiveMode packetReceiveMode;

	protected PacketDataSender packetDataSender = new PacketDataSender();

	protected PacketDataReceiver packetDataReceiver = new PacketDataReceiver();

	protected GenericNotifier<PacketBase> sendPacketNotifier = new GenericNotifier<PacketBase>();

	protected GenericNotifier<OutgoingPacketData> sendDataNotifier = new GenericNotifier<OutgoingPacketData>();

	protected GenericNotifier<PacketDecodeInfo> packetDecodeNotifier = new GenericNotifier<PacketDecodeInfo>();

	protected Dictionary<Type, CustomSendPacketHandlerDelegate> sendPacketToHandlerMap = new Dictionary<Type, CustomSendPacketHandlerDelegate>();

	protected GenericNotifier<PacketBase> receivePacketNotifier = new GenericNotifier<PacketBase>();

	protected GenericNotifier<IncomingPacketData> receiveDataNotifier = new GenericNotifier<IncomingPacketData>();

	private List<Type> hybridReceiveModeQueueBypassTypeList = new List<Type>();

	private GenericNotifier<PacketBase> hybridReceiveModeQueuedPacketNotifier = new GenericNotifier<PacketBase>();

	protected GenericObserver<IncomingPacketData> receiveDataObserver;

	private GenericObserver<IncomingPacketData> infoObserver;

	protected ReceivePacketHandlerBase receivePacketHandler;

	protected ProtocolBase protocolTop;

	protected ProtocolBase protocolBottom;

	protected ConnectionBase connection;

	protected GenericObserver<ConnectionStateChangeInfo> connectionStateChangeInfoObserver;

	protected GenericNotifier<ConnectionStateChangeInfo> connectionStateChangeInfoNotifier = new GenericNotifier<ConnectionStateChangeInfo>();

	private bool running;

	private bool packetDecode = true;

	protected static SharedConnectionManager sharedConnectionManager = new SharedConnectionManager();

	protected static Dictionary<string, List<Action>> sharedConnectionClosedMap = new Dictionary<string, List<Action>>();

	public APIBase(PacketListBase packetList, Logger logger, PacketReceiveMode packetReceiveMode)
	{
		infoObserver = new GenericObserver<IncomingPacketData>(NotifyLogMessageObservers);
		receiveDataObserver = new GenericObserver<IncomingPacketData>(NotifyDataObservers);
		connectionStateChangeInfoObserver = new GenericObserver<ConnectionStateChangeInfo>(connectionStateChangeInfoNotifier);
		this.packetList = packetList;
		this.logger = logger;
		this.packetReceiveMode = packetReceiveMode;
	}

	public static void OpenNewSharedSerialConnection(string portName, int baudRate, Handshake handShake = Handshake.None, bool dtrEnable = false)
	{
		ConnectionSerialPort connectionSerialPort = new ConnectionSerialPort();
		connectionSerialPort.Open(portName, baudRate, handShake, dtrEnable);
		sharedConnectionManager.AddConnection(connectionSerialPort, portName);
		if (!sharedConnectionClosedMap.ContainsKey(portName))
		{
			sharedConnectionClosedMap.Add(portName, new List<Action>());
		}
	}

	public static void OpenNewSharedTCPConnection(string ipAddress, int portNumber, bool initializeWillsAndDos, bool addProtocolByte)
	{
		ConnectionTCP connectionTCP = new ConnectionTCP();
		connectionTCP.Open(ipAddress, portNumber, initializeWillsAndDos, addProtocolByte);
		string text = ipAddress + ":" + portNumber;
		sharedConnectionManager.AddConnection(connectionTCP, text);
		sharedConnectionClosedMap.Add(text, new List<Action>());
	}

	public static void CloseSharedSerialConnection(string portName)
	{
		sharedConnectionManager.RemoveAllRoutes(portName);
		sharedConnectionManager.RemoveConnection(portName, close: true);
		if (sharedConnectionClosedMap.ContainsKey(portName))
		{
			Action[] array = sharedConnectionClosedMap[portName].ToArray();
			foreach (Action action in array)
			{
				action();
			}
			sharedConnectionClosedMap[portName].Clear();
			sharedConnectionClosedMap.Remove(portName);
		}
	}

	public static void CloseSharedTCPConnection(string portName)
	{
		sharedConnectionManager.RemoveAllRoutes(portName);
		sharedConnectionManager.RemoveConnection(portName, close: true);
		if (sharedConnectionClosedMap.ContainsKey(portName))
		{
			Action[] array = sharedConnectionClosedMap[portName].ToArray();
			foreach (Action action in array)
			{
				action();
			}
			sharedConnectionClosedMap[portName].Clear();
			sharedConnectionClosedMap.Remove(portName);
		}
	}

	public virtual void AddToSharedSerialConnection(string portName)
	{
		throw new Exception("Adding to a shared connection not supported for this API");
	}

	public virtual void RemoveFromSharedSerialConnection(string portName)
	{
		throw new Exception("Removing from a shared connection not supported for this API");
	}

	public static bool IsSharedConnectionActiveAndOpen(string id)
	{
		ConnectionBase connectionBase;
		try
		{
			connectionBase = sharedConnectionManager.GetConnection(id);
		}
		catch (Exception)
		{
			return false;
		}
		return connectionBase.IsOpen();
	}

	public static void OpenNewSharedDiagConnection(string portName, LibraryModeEnum libraryMode, Phone.TargetType targetType, Phone.DiagType diagType)
	{
		ConnectionDiag connectionDiag = new ConnectionDiag();
		connectionDiag.Open(portName, libraryMode, targetType, diagType);
		sharedConnectionManager.AddConnection(connectionDiag, portName, 10);
		sharedConnectionClosedMap.Add(portName, new List<Action>());
		sharedConnectionManager.AddRoute(portName, 16, null, 6);
		sharedConnectionManager.AddRoute(portName, 19, null, 3);
		sharedConnectionManager.AddRoute(portName, 75, null, 2);
	}

	public static void CloseSharedDiagConnection(string portName)
	{
		sharedConnectionManager.RemoveAllRoutes(portName);
		sharedConnectionManager.RemoveConnection(portName, close: true);
		if (sharedConnectionClosedMap.ContainsKey(portName))
		{
			Action[] array = sharedConnectionClosedMap[portName].ToArray();
			foreach (Action action in array)
			{
				action();
			}
			sharedConnectionClosedMap[portName].Clear();
			sharedConnectionClosedMap.Remove(portName);
		}
	}

	public virtual void AddToSharedDiagConnection(string portName, string diagType)
	{
		throw new Exception("Adding to a shared connection not supported for this API");
	}

	public virtual void RemoveFromSharedDiagConnection(string portName)
	{
		throw new Exception("Removing from a shared connection not supported for this API");
	}

	protected void AddSharedDiagConnectionRoutes(string portName, ushort ftmCommandCode, ushort[] logCodes)
	{
		sharedConnectionManager.AddRoute(portName, ftmCommandCode, protocolBottom);
		foreach (ushort us in logCodes)
		{
			sharedConnectionManager.AddRoute(portName, us, protocolBottom);
		}
	}

	protected void RemoveSharedDiagConnectionRoutes(string portName, ushort ftmCommandCode, ushort[] logCodes)
	{
		sharedConnectionManager.RemoveRoute(portName, ftmCommandCode);
		foreach (ushort us in logCodes)
		{
			sharedConnectionManager.RemoveRoute(portName, us);
		}
	}

	public void Startup()
	{
		if (!running)
		{
			CreateReceivePacketHandler();
			receivePacketHandler.SetQueueRejectTypeList(hybridReceiveModeQueueBypassTypeList);
			protocolTop = new ProtocolBase();
			protocolBottom = new ProtocolBase();
			connection = new ConnectionBase();
			packetDataSender.RegisterSendDataObserver(protocolTop);
			packetDataSender.RegisterReceiveDataObserver(infoObserver);
			protocolTop.RegisterSendDataObserver(protocolBottom);
			protocolBottom.RegisterSendDataObserver(connection);
			connection.RegisterReceiveDataObserver(packetDataReceiver);
			connection.RegisterConnectionStateChangeInfoObserver(connectionStateChangeInfoObserver);
			packetDataReceiver.RegisterReceiveDataObserver(protocolBottom);
			protocolBottom.RegisterReceiveDataObserver(protocolTop);
			protocolTop.RegisterReceiveDataObserver(receivePacketHandler);
			if (packetReceiveMode == PacketReceiveMode.Asynchronous)
			{
				receivePacketHandler.SetReceiveQueueState(enabled: false);
			}
			else
			{
				receivePacketHandler.SetReceiveQueueState(enabled: true);
			}
			if (packetReceiveMode != 0)
			{
				receivePacketHandler.RegisterReceivePacketObserver(this);
			}
			receivePacketHandler.RegisterReceiveInfoObserver(infoObserver);
			protocolBottom.RegisterSendDataObserver(this);
			SetupReceiveDataObservation();
			packetDataSender.Startup();
			packetDataReceiver.Startup();
			running = true;
		}
	}

	protected virtual void CreateReceivePacketHandler()
	{
		receivePacketHandler = new ReceivePacketHandlerBase(packetList);
	}

	protected virtual void ChangeTopProtocol(ProtocolBase protocol)
	{
		packetDataSender.UnregisterSendDataObserver(protocolTop);
		protocolTop.UnregisterSendDataObserver(protocolBottom);
		protocolBottom.UnregisterReceiveDataObserver(protocolTop);
		protocolTop.UnregisterReceiveDataObserver(receivePacketHandler);
		protocolTop = protocol;
		packetDataSender.RegisterSendDataObserver(protocolTop);
		protocolTop.RegisterSendDataObserver(protocolBottom);
		protocolBottom.RegisterReceiveDataObserver(protocolTop);
		protocolTop.RegisterReceiveDataObserver(receivePacketHandler);
	}

	protected virtual void ChangeBottomProtocol(ProtocolBase protocol, bool usePacketDataReceiver = true)
	{
		protocolTop.UnregisterSendDataObserver(protocolBottom);
		protocolBottom.UnregisterSendDataObserver(connection);
		packetDataReceiver.UnregisterReceiveDataObserver(protocolBottom);
		protocolBottom.UnregisterReceiveDataObserver(protocolTop);
		protocolBottom.UnregisterSendDataObserver(this);
		protocolBottom = protocol;
		protocolTop.RegisterSendDataObserver(protocolBottom);
		protocolBottom.RegisterSendDataObserver(connection);
		if (usePacketDataReceiver)
		{
			packetDataReceiver.RegisterReceiveDataObserver(protocolBottom);
		}
		protocolBottom.RegisterReceiveDataObserver(protocolTop);
		protocolBottom.RegisterSendDataObserver(this);
	}

	protected virtual void ChangeConnection(ConnectionBase connection)
	{
		protocolBottom.UnregisterSendDataObserver(this.connection);
		this.connection.UnregisterReceiveDataObserver(packetDataReceiver);
		connectionStateChangeInfoNotifier.UnregisterObserver(connectionStateChangeInfoObserver);
		this.connection = connection;
		protocolBottom.RegisterSendDataObserver(connection);
		connection.RegisterReceiveDataObserver(packetDataReceiver);
		connection.RegisterConnectionStateChangeInfoObserver(connectionStateChangeInfoObserver);
	}

	protected virtual void SetupReceiveDataObservation()
	{
		packetDataReceiver.RegisterReceiveDataObserver(receiveDataObserver);
	}

	protected virtual void ShutdownReceiveDataObservation()
	{
		packetDataReceiver.UnregisterReceiveDataObserver(receiveDataObserver);
	}

	public void Shutdown()
	{
		if (running)
		{
			connection.Close();
			packetDataSender.UnregisterSendDataObserver(protocolTop);
			packetDataSender.UnregisterReceiveDataObserver(infoObserver);
			protocolTop.UnregisterSendDataObserver(protocolBottom);
			protocolBottom.UnregisterSendDataObserver(connection);
			connection.UnregisterReceiveDataObserver(packetDataReceiver);
			packetDataReceiver.UnregisterReceiveDataObserver(protocolBottom);
			protocolBottom.UnregisterReceiveDataObserver(protocolTop);
			protocolTop.UnregisterReceiveDataObserver(receivePacketHandler);
			if (packetReceiveMode != 0)
			{
				receivePacketHandler.UnregisterReceivePacketObserver(this);
			}
			receivePacketHandler.UnregisterReceiveInfoObserver(infoObserver);
			protocolBottom.UnregisterSendDataObserver(this);
			ShutdownReceiveDataObservation();
			packetDataSender.Shutdown();
			packetDataReceiver.Shutdown();
			running = false;
		}
	}

	public PacketReceiveMode GetPacketReceiveMode()
	{
		return packetReceiveMode;
	}

	public void RegisterConnectionStateChangeInfoObserver(IObserver<ConnectionStateChangeInfo> observer)
	{
		connectionStateChangeInfoNotifier.RegisterObserver(observer);
	}

	public void UnregisterConnectionStateChangeInfoObserver(IObserver<ConnectionStateChangeInfo> observer)
	{
		connectionStateChangeInfoNotifier.UnregisterObserver(observer);
	}

	public void Send(List<PacketBase> packets)
	{
		foreach (PacketBase packet in packets)
		{
			Send(packet);
		}
	}

	public virtual void Send(PacketBase packet)
	{
		if (!sendPacketToHandlerMap.ContainsKey(packet.GetType()) || !sendPacketToHandlerMap[packet.GetType()](packet))
		{
			Send(packet.ToByteArray());
			packet.Flags |= 2u;
			sendPacketNotifier.NotifyObservers(packet);
		}
	}

	public void Send(byte[] bytes, bool performValidPacketCheck = false)
	{
		Send(bytes, bytes.Length, performValidPacketCheck);
	}

	public virtual void Send(byte[] bytes, int length, bool performValidPacketCheck = false)
	{
		OutgoingPacketData outgoingPacketData = new OutgoingPacketData(bytes, length);
		packetDataSender.SendSync(outgoingPacketData);
		if (performValidPacketCheck)
		{
			try
			{
				PacketBase packetBase = packetList.BytesToPacket(outgoingPacketData.bytes);
				packetBase.Flags |= 2u;
				sendPacketNotifier.NotifyObservers(packetBase);
			}
			catch (Exception)
			{
			}
		}
	}

	public void SendAsync(List<PacketBase> packets)
	{
		foreach (PacketBase packet in packets)
		{
			SendAsync(packet);
		}
	}

	public virtual void SendAsync(PacketBase packet)
	{
		if (!sendPacketToHandlerMap.ContainsKey(packet.GetType()) || sendPacketToHandlerMap[packet.GetType()](packet))
		{
			SendAsync(packet.ToByteArray());
			packet.Flags |= 2u;
			sendPacketNotifier.NotifyObservers(packet);
		}
	}

	public void SendAsync(byte[] bytes)
	{
		SendAsync(bytes, bytes.Length);
	}

	public virtual void SendAsync(byte[] bytes, int length)
	{
		OutgoingPacketData packetData = new OutgoingPacketData(bytes, length);
		packetDataSender.SendAsync(packetData);
	}

	public virtual void RegisterSendPacketObserver(IObserver<PacketBase> observer)
	{
		sendPacketNotifier.RegisterObserver(observer);
	}

	public virtual void UnregisterSendPacketObserver(IObserver<PacketBase> observer)
	{
		sendPacketNotifier.UnregisterObserver(observer);
	}

	public void RegisterSendDataObserver(IObserver<OutgoingPacketData> observer)
	{
		sendDataNotifier.RegisterObserver(observer);
	}

	public void UnregisterSendDataObserver(IObserver<OutgoingPacketData> observer)
	{
		sendDataNotifier.UnregisterObserver(observer);
	}

	public void NotifyObserver(OutgoingPacketData packetData)
	{
		sendDataNotifier.NotifyObservers(packetData);
	}

	public void SetCustomSendPacketHandler(Type packetType, CustomSendPacketHandlerDelegate handler)
	{
		if (!sendPacketToHandlerMap.ContainsKey(packetType))
		{
			sendPacketToHandlerMap.Add(packetType, handler);
		}
		else
		{
			sendPacketToHandlerMap[packetType] = handler;
		}
	}

	public void RemoveCustomSendPacketHandler(Type packetType)
	{
		if (sendPacketToHandlerMap.ContainsKey(packetType))
		{
			sendPacketToHandlerMap.Remove(packetType);
		}
	}

	public PacketBase Receive(int timeoutMilliseconds, bool skipNotify = false)
	{
		if (packetReceiveMode == PacketReceiveMode.Asynchronous)
		{
			throw new Exception("Synchronous receive is disabled.  To enable synchronous receive, the API object must be instantiated with packetReceiveMode set to Synchronous or Hybrid");
		}
		try
		{
			return receivePacketHandler.Receive(new TimeSpan(0, 0, 0, 0, timeoutMilliseconds));
		}
		finally
		{
			if (!skipNotify)
			{
				foreach (PacketBase dequeuedPacket in receivePacketHandler.GetDequeuedPackets())
				{
					dequeuedPacket.Flags |= 4u;
					receivePacketNotifier.NotifyObservers(dequeuedPacket);
				}
			}
		}
	}

	public PacketBase Receive(Type packetType, int timeoutMilliseconds)
	{
		if (packetReceiveMode == PacketReceiveMode.Asynchronous)
		{
			throw new Exception("Synchronous receive is disabled.  To enable synchronous receive, the API object must be instantiated with packetReceiveMode set to Synchronous or Hybrid");
		}
		try
		{
			return receivePacketHandler.ReceiveOneType(packetType, new TimeSpan(0, 0, 0, 0, timeoutMilliseconds));
		}
		finally
		{
			foreach (PacketBase dequeuedPacket in receivePacketHandler.GetDequeuedPackets())
			{
				dequeuedPacket.Flags |= 4u;
				receivePacketNotifier.NotifyObservers(dequeuedPacket);
			}
		}
	}

	public PacketBase Receive(List<Type> packetTypes, int timeoutMilliseconds)
	{
		return Receive(packetTypes.ToArray(), timeoutMilliseconds);
	}

	public PacketBase Receive(Type[] packetTypes, int timeoutMilliseconds)
	{
		if (packetReceiveMode == PacketReceiveMode.Asynchronous)
		{
			throw new Exception("Synchronous receive is disabled.  To enable synchronous receive, the API object must be instantiated with packetReceiveMode set to Synchronous or Hybrid");
		}
		try
		{
			return receivePacketHandler.ReceiveOneTypeInList(packetTypes, new TimeSpan(0, 0, 0, 0, timeoutMilliseconds));
		}
		finally
		{
			foreach (PacketBase dequeuedPacket in receivePacketHandler.GetDequeuedPackets())
			{
				dequeuedPacket.Flags |= 4u;
				receivePacketNotifier.NotifyObservers(dequeuedPacket);
			}
		}
	}

	public List<PacketBase> ReceiveAll(List<Type> packetTypes, int timeoutMilliseconds)
	{
		return ReceiveAll(packetTypes.ToArray(), timeoutMilliseconds);
	}

	public List<PacketBase> ReceiveAll(Type[] packetTypes, int timeoutMilliseconds)
	{
		if (packetReceiveMode == PacketReceiveMode.Asynchronous)
		{
			throw new Exception("Synchronous receive is disabled.  To enable synchronous receive, the API object must be instantiated with packetReceiveMode set to Synchronous or Hybrid");
		}
		try
		{
			return receivePacketHandler.ReceiveAllTypesInList(packetTypes, new TimeSpan(0, 0, 0, 0, timeoutMilliseconds));
		}
		finally
		{
			foreach (PacketBase dequeuedPacket in receivePacketHandler.GetDequeuedPackets())
			{
				dequeuedPacket.Flags |= 4u;
				receivePacketNotifier.NotifyObservers(dequeuedPacket);
			}
		}
	}

	public PacketBase Receive(List<PacketMatchPattern> packetMatchPatterns, int timeoutMilliseconds)
	{
		return Receive(packetMatchPatterns.ToArray(), timeoutMilliseconds);
	}

	public PacketBase Receive(PacketMatchPattern[] packetMatchPatterns, int timeoutMilliseconds)
	{
		if (packetReceiveMode == PacketReceiveMode.Asynchronous)
		{
			throw new Exception("Synchronous receive is disabled.  To enable synchronous receive, the API object must be instantiated with packetReceiveMode set to Synchronous or Hybrid");
		}
		try
		{
			return receivePacketHandler.ReceiveOnePatternInList(packetMatchPatterns, new TimeSpan(0, 0, 0, 0, timeoutMilliseconds));
		}
		finally
		{
			foreach (PacketBase dequeuedPacket in receivePacketHandler.GetDequeuedPackets())
			{
				dequeuedPacket.Flags |= 4u;
				receivePacketNotifier.NotifyObservers(dequeuedPacket);
			}
		}
	}

	public void ClearReceiveQueue()
	{
		if (packetReceiveMode == PacketReceiveMode.Asynchronous)
		{
			throw new Exception("Synchronous receive is disabled.  To enable synchronous receive, the API object must be instantiated with packetReceiveMode set to Synchronous or Hybrid");
		}
		receivePacketHandler.ClearReceiveQueue();
	}

	public virtual void RegisterReceivePacketObserver(IObserver<PacketBase> observer)
	{
		receivePacketNotifier.RegisterObserver(observer);
	}

	public virtual void UnregisterReceivePacketObserver(IObserver<PacketBase> observer)
	{
		receivePacketNotifier.UnregisterObserver(observer);
	}

	public void RegisterReceiveDataObserver(IObserver<IncomingPacketData> observer)
	{
		receiveDataNotifier.RegisterObserver(observer);
	}

	public void UnregisterReceiveDataObserver(IObserver<IncomingPacketData> observer)
	{
		receiveDataNotifier.UnregisterObserver(observer);
	}

	public void SetHybridReceiveModeQueueBypassTypeList(List<Type> typeList)
	{
		if (packetReceiveMode != PacketReceiveMode.Hybrid)
		{
			throw new Exception("The queue bypass type list is only valid in hybrid receive mode");
		}
		if (typeList == null)
		{
			throw new Exception("Type list cannot be null");
		}
		hybridReceiveModeQueueBypassTypeList = typeList;
		if (receivePacketHandler != null)
		{
			receivePacketHandler.SetQueueRejectTypeList(typeList);
		}
	}

	public void RegisterHybridReceiveModeQueuedPacketObserver(IObserver<PacketBase> observer)
	{
		if (packetReceiveMode != PacketReceiveMode.Hybrid)
		{
			throw new Exception("A hybrid receive mode queued packet observer is only valid in hybrid receive mode");
		}
		hybridReceiveModeQueuedPacketNotifier.RegisterObserver(observer);
	}

	public void UnregisterHybridReceiveModeQueuedPacketObserver(IObserver<PacketBase> observer)
	{
		if (packetReceiveMode != PacketReceiveMode.Hybrid)
		{
			throw new Exception("A hybrid receive mode queued packet observer is only valid in hybrid receive mode");
		}
		hybridReceiveModeQueuedPacketNotifier.UnregisterObserver(observer);
	}

	private void NotifyLogMessageObservers(IncomingPacketData packetData)
	{
		if (packetData.type == PacketDataType.Data)
		{
			return;
		}
		if (packetData.type == PacketDataType.WarningMessage)
		{
			LogMessage logMessage = new LogMessage(LogMessageType.Warning, Conversions.ByteArrayToString(packetData.bytes));
			logger.NotifyObserver(logMessage);
			return;
		}
		if (packetData.type == PacketDataType.Exception)
		{
			Exception ex = (Exception)Conversions.ByteArrayToObject(packetData.bytes);
			LogMessage logMessage2 = new LogMessage(LogMessageType.Error, ex);
			logger.NotifyObserver(logMessage2);
			return;
		}
		try
		{
			throw new Exception("Unhandled packet data type: " + packetData.type);
		}
		catch (Exception ex2)
		{
			LogMessage logMessage3 = new LogMessage(LogMessageType.Error, ex2);
			logger.NotifyObserver(logMessage3);
		}
	}

	protected void NotifyLogMessageObservers(LogMessage logMessage)
	{
		logger.NotifyObserver(logMessage);
	}

	private void NotifyDataObservers(IncomingPacketData packetData)
	{
		if (packetData.type == PacketDataType.Data)
		{
			receiveDataNotifier.NotifyObservers(packetData);
		}
	}

	public List<PacketBase> SendAndWaitForExpectedResponses(PacketBase packet, int timeoutMilliseconds)
	{
		List<PacketBase> result = new List<PacketBase>();
		Send(packet);
		if (packet.ExpectedResponseTypes == null || packet.ExpectedResponseTypes.Length == 0)
		{
			return result;
		}
		if (packetReceiveMode == PacketReceiveMode.Asynchronous)
		{
			throw new Exception("Synchronous receive is disabled.  To enable synchronous receive, the API object must be instantiated with packetReceiveMode set to Synchronous or Hybrid");
		}
		try
		{
			return receivePacketHandler.ReceiveAllTypesInList(packet.ExpectedResponseTypes, new TimeSpan(0, 0, 0, 0, timeoutMilliseconds));
		}
		finally
		{
			foreach (PacketBase dequeuedPacket in receivePacketHandler.GetDequeuedPackets())
			{
				dequeuedPacket.Flags |= 4u;
				receivePacketNotifier.NotifyObservers(dequeuedPacket);
			}
		}
	}

	public PacketBase SendAndWaitForOneResponseInList(PacketBase packet, Type[] expectedResponseTypes, int timeoutMilliseconds)
	{
		PacketBase result = null;
		Send(packet);
		if (expectedResponseTypes == null || expectedResponseTypes.Length == 0)
		{
			return result;
		}
		if (packetReceiveMode == PacketReceiveMode.Asynchronous)
		{
			throw new Exception("Synchronous receive is disabled.  To enable synchronous receive, the API object must be instantiated with packetReceiveMode set to Synchronous or Hybrid");
		}
		try
		{
			return receivePacketHandler.ReceiveOneTypeInList(expectedResponseTypes, new TimeSpan(0, 0, 0, 0, timeoutMilliseconds));
		}
		finally
		{
			foreach (PacketBase dequeuedPacket in receivePacketHandler.GetDequeuedPackets())
			{
				dequeuedPacket.Flags |= 4u;
				receivePacketNotifier.NotifyObservers(dequeuedPacket);
			}
		}
	}

	public void NotifyObserver(PacketBase packet)
	{
		if (packetReceiveMode == PacketReceiveMode.Hybrid)
		{
			if (hybridReceiveModeQueueBypassTypeList.Contains(packet.GetType()))
			{
				packet.Flags |= 4u;
				receivePacketNotifier.NotifyObservers(packet);
			}
			else
			{
				packet.Flags |= 1u;
				hybridReceiveModeQueuedPacketNotifier.NotifyObservers(packet);
			}
		}
		else
		{
			packet.Flags |= 4u;
			receivePacketNotifier.NotifyObservers(packet);
		}
	}

	public virtual void Decode(PacketBase packet)
	{
		if (!sendPacketToHandlerMap.ContainsKey(packet.GetType()) || !sendPacketToHandlerMap[packet.GetType()](packet))
		{
			packet.Flags |= 2u;
			sendPacketNotifier.NotifyObservers(packet);
		}
	}

	public void NotifyObserver(PacketDecodeInfo packetDecodeInfo)
	{
		packetDecode = packetDecodeInfo.PacketDecode;
		packetDecodeNotifier.NotifyObservers(packetDecodeInfo);
	}

	public void RegisterDecodePacketObserver(IObserver<PacketDecodeInfo> observer)
	{
		packetDecodeNotifier.RegisterObserver(observer);
	}

	public void UnregisterDecodePacketObserver(IObserver<PacketDecodeInfo> observer)
	{
		packetDecodeNotifier.UnregisterObserver(observer);
	}

	public PacketBase Translate(string packetString)
	{
		return packetList.StringToPacket(packetString);
	}
}
