using System;
using System.Collections.Generic;
using System.IO;
using System.Management;
using System.Timers;

namespace QC.QMSCT;

public class UsbToSerialPortDetector : IUnitDetector, IDisposable
{
	public bool CompileLog;

	private DetectionEventMode eventMode = DetectionEventMode.DETECT_MODE_TIMER;

	private DetectionInstance detectionInstance;

	private UDEDetectionMode udeDetectionMode;

	private Dictionary<int, int[]> expectedPorts = new Dictionary<int, int[]>();

	private Dictionary<int, string> expectedPhysicalAddress = new Dictionary<int, string>();

	private string expectedHardwareId = "";

	private Timer timer;

	private ManagementEventWatcher watcher;

	private WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent");

	private FileStream Log;

	private StreamWriter writer;

	private USBEnumerator usbEnumerator = new USBEnumerator();

	public GetUsbPortListChangeEvent USBPortChangeEventCallback;

	private USBEnumerator.USB_PORT_INFO_LIST PortCollection = new USBEnumerator.USB_PORT_INFO_LIST();

	public bool PortKeyWordCaseSensitive
	{
		set
		{
			usbEnumerator.PortKeyWordCaseSensitive = value;
		}
	}

	public List<string> PortKeyWord => usbEnumerator.PortKeyWord;

	public DetectionInstance SetDetectionInstance
	{
		set
		{
			detectionInstance = value;
		}
	}

	public UDEDetectionMode SetUDEDetectionMode
	{
		set
		{
			udeDetectionMode = value;
		}
	}

	public DetectionEventMode SetEventMode
	{
		set
		{
			eventMode = value;
		}
	}

	public Dictionary<int, int[]> ExpectedListOfPorts
	{
		get
		{
			return expectedPorts;
		}
		set
		{
			expectedPorts = value;
			if (CompileLog)
			{
				if (!Directory.Exists("C:\\Log\\"))
				{
					Directory.CreateDirectory("C:\\Log\\");
				}
				string path = "C:\\Log\\Panel" + expectedPorts[0].ToString() + ".txt";
				Log = new FileStream(path, FileMode.Create);
				writer = new StreamWriter(Log);
			}
		}
	}

	public Dictionary<int, string> ExpectedListOfPhysicalAddress
	{
		get
		{
			return expectedPhysicalAddress;
		}
		set
		{
			expectedPhysicalAddress = value;
		}
	}

	public string ExpectedHardwareId
	{
		get
		{
			return expectedHardwareId;
		}
		set
		{
			expectedHardwareId = value;
		}
	}

	public event ActivePositionsChangedGlobal OnChange;

	public event ActivePositionsChangedGlobalGV OnChangeGV;

	public void Stop()
	{
		try
		{
			if (eventMode == DetectionEventMode.DETECT_MODE_TIMER)
			{
				if (timer != null)
				{
					timer.Stop();
				}
			}
			else if (watcher != null)
			{
				watcher.Stop();
			}
			if (Log != null)
			{
				writer.Close();
				writer = null;
				Log.Close();
				Log = null;
			}
		}
		catch
		{
		}
	}

	public void Start()
	{
		DetectAndNotify();
		if (eventMode == DetectionEventMode.DETECT_MODE_TIMER)
		{
			if (timer == null)
			{
				timer = new Timer(2000.0);
				timer.Elapsed += timer_EventArrived;
				timer.AutoReset = true;
				timer.Enabled = true;
			}
			timer.Start();
		}
		else
		{
			if (watcher == null)
			{
				watcher = new ManagementEventWatcher(query);
				watcher.EventArrived += watcher_EventArrived;
			}
			watcher.Start();
		}
	}

	public void SetTimerInterval(double interval)
	{
		if (timer != null && interval >= 1000.0)
		{
			timer.Interval = interval;
		}
	}

	private void timer_EventArrived(object source, ElapsedEventArgs e)
	{
		DetectAndNotify();
	}

	private void watcher_EventArrived(object sender, EventArrivedEventArgs e)
	{
		DetectAndNotify();
	}

	public void DetectAndNotify()
	{
		if (USBPortChangeEventCallback == null)
		{
			if (detectionInstance == DetectionInstance.DETECT_INST_PORT_NO)
			{
				IsReleventPortConnected();
			}
			else
			{
				IsReleventDeviceConnected();
			}
			IsReleventDeviceDisconnected();
		}
		else
		{
			SendAllUSBPort();
		}
	}

	public void IsReleventPortConnected()
	{
		if (expectedPorts.Count == 0)
		{
			throw new Exception("Unit detector is not initialized correctly!");
		}
		List<int> intPortNumberCollection = new List<int>();
		usbEnumerator.GetPortNumberList(ref intPortNumberCollection);
		Dictionary<int, int[]>.KeyCollection keys = expectedPorts.Keys;
		foreach (int item in keys)
		{
			int[] array = expectedPorts[item];
			foreach (int comport in array)
			{
				List<int> list = intPortNumberCollection;
				Predicate<int> match = (int predicate) => predicate.Equals(comport);
				if (!list.Exists(match))
				{
					continue;
				}
				string strDeviceName = "(COM" + Convert.ToString(comport) + ")";
				List<string> strPhysicalAddressCollection = new List<string>();
				usbEnumerator.GetUSBDevicePhysicalAddressByName(strDeviceName, ref strPhysicalAddressCollection);
				if (strPhysicalAddressCollection == null || strPhysicalAddressCollection.Count != 1)
				{
					continue;
				}
				string value = strPhysicalAddressCollection[0];
				if (expectedPhysicalAddress.ContainsKey(item))
				{
					if (expectedPhysicalAddress[item] != strPhysicalAddressCollection[0])
					{
						expectedPhysicalAddress.Remove(item);
						expectedPhysicalAddress.Add(item, value);
					}
				}
				else
				{
					expectedPhysicalAddress.Add(item, value);
				}
				SaveToLog("Unit Connected");
				this.OnChange(item, connected: true, comport);
			}
		}
	}

	public void IsReleventDeviceConnected()
	{
		if (expectedPhysicalAddress.Count == 0)
		{
			throw new Exception("Unit detector is not initialized correctly!");
		}
		USBEnumerator.USB_PORT_INFO_LIST lstUSBPortInformationCollection = new USBEnumerator.USB_PORT_INFO_LIST();
		usbEnumerator.GetPortNumberListWithInformation(ref lstUSBPortInformationCollection);
		Dictionary<int, string>.KeyCollection keys = expectedPhysicalAddress.Keys;
		foreach (int item in keys)
		{
			int num = lstUSBPortInformationCollection.FirstCOMNumberByPortDetails(new USBEnumerator.USBPortDetails(null, expectedPhysicalAddress[item]));
			if (num > 0)
			{
				SaveToLog("Unit Connected");
				this.OnChange(item, connected: true, num);
			}
		}
	}

	public void IsReleventDeviceDisconnected()
	{
		if (expectedPhysicalAddress.Count == 0)
		{
			return;
		}
		List<string> strPhysicalAddressCollection = new List<string>();
		List<string> list = new List<string>();
		new List<int>();
		list.Add("{4D36E978-E325-11CE-BFC1-08002BE10318}");
		list.Add("{3f966bd9-fa04-4ec5-991c-d326973b5128}");
		List<List<int>> intPortNumberCollection = null;
		usbEnumerator.GetUSBDevicePhysicalAddressByGuid(list, ref strPhysicalAddressCollection, ref intPortNumberCollection);
		Dictionary<int, string>.KeyCollection keys = expectedPhysicalAddress.Keys;
		foreach (int panelIndex in keys)
		{
			List<string> list2 = strPhysicalAddressCollection;
			Predicate<string> match = (string r) => r.Equals(expectedPhysicalAddress[panelIndex]);
			if (!list2.Exists(match))
			{
				SaveToLog("Unit Disconnected");
				this.OnChange(panelIndex, connected: false, 0);
			}
		}
	}

	private void SaveToLog(string log)
	{
		try
		{
			if (CompileLog && writer != null)
			{
				writer.WriteLine(log);
			}
		}
		catch
		{
		}
	}

	public void CompileDetectionLog(USBEnumerator.UpdateUSBDetectionLogEvent callback)
	{
		usbEnumerator.UpdateUSBDetectionLogCallback = callback;
	}

	internal bool DiffUsbPort(USBEnumerator.USB_PORT_INFO_LIST portCollection)
	{
		if (portCollection.IsSameAs(PortCollection))
		{
			return false;
		}
		return true;
	}

	public void SendAllUSBPort()
	{
		USBEnumerator.USB_PORT_INFO_LIST portCollection = new USBEnumerator.USB_PORT_INFO_LIST();
		GetSpecficUSBPorts(ref portCollection);
		if (DiffUsbPort(portCollection))
		{
			PortCollection = portCollection;
			USBPortChangeEventCallback(portCollection);
		}
	}

	public void GetSpecficUSBPorts(ref USBEnumerator.USB_PORT_INFO_LIST portCollection)
	{
		USBEnumerator.USB_PORT_INFO_LIST lstUSBPortInformationCollection = new USBEnumerator.USB_PORT_INFO_LIST();
		usbEnumerator.GetPortNumberListWithInformation(ref lstUSBPortInformationCollection);
		portCollection.Clear();
		foreach (int portNumber in lstUSBPortInformationCollection.PortNumbers)
		{
			if (lstUSBPortInformationCollection[portNumber] != null && lstUSBPortInformationCollection[portNumber].PortDescription != null && lstUSBPortInformationCollection[portNumber].PortPhysicalAddress != null && lstUSBPortInformationCollection[portNumber].UDEDevice != null)
			{
				if (udeDetectionMode == UDEDetectionMode.UDE_DETECT_NONE && lstUSBPortInformationCollection[portNumber].UDEDevice == "")
				{
					portCollection.Add(lstUSBPortInformationCollection, portNumber);
				}
				else if (udeDetectionMode == UDEDetectionMode.UDE_DETECT_ONLY && lstUSBPortInformationCollection[portNumber].UDEDevice != "")
				{
					portCollection.Add(lstUSBPortInformationCollection, portNumber);
				}
				else if (udeDetectionMode == UDEDetectionMode.UDE_DETECT_ALL)
				{
					portCollection.Add(lstUSBPortInformationCollection, portNumber);
				}
			}
		}
	}

	public void GetPortNumberByUSBDevicePhysicalAddress(string physicalAddress, ref List<int> portNumberCollection)
	{
		usbEnumerator.GetPortNumberByUSBDevicePhysicalAddress(physicalAddress, ref portNumberCollection);
	}

	public void Dispose()
	{
		Stop();
	}
}
