using System;
using System.Runtime.InteropServices;

namespace QC.QMSLPhone;

public class LogCGPSMeasurement : LogMessage
{
	[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 28)]
	public struct LogCGPSMeasurementHdrType
	{
		public byte version;

		public uint fcount;

		public ushort gps_week;

		public uint gps_ms;

		public uint time_bias;

		public uint time_unc;

		public uint freq_bias;

		public uint freq_unc;

		public byte number_svs;
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 59)]
	public struct LogCGPSMeasurementType
	{
		public byte sv_id;

		public byte obs_state;

		public byte obs_cnt;

		public byte good_obs_cnt;

		public byte filter_n;

		public short cno;

		public ushort latency;

		public byte pre_int;

		public ushort post_int;

		public int unfilt_ms;

		public int unfilt_sm;

		public int unfilt_time_unc;

		public int unfilt_speed;

		public int unfilt_speed_unc;

		public int meas_status;

		public byte misc_status;

		public int multipath_est;

		public int azi_rad;

		public int elev_rad;

		public int carrier_phase_cycles;

		public ushort carrier_phase_fract;

		public int reserved;
	}

	private const int hdrSize = 28;

	private const int recSize = 59;

	public LogCGPSMeasurementHdrType ds;

	public LogCGPSMeasurementType[] dsSv = new LogCGPSMeasurementType[32];

	private GCHandle pinnedPacket;

	private IntPtr p;

	private IntPtr pCGPSHdr;

	private IntPtr pCGPS;

	public LogCGPSMeasurement(LogMessage msgVal)
		: base(msgVal.msgID, msgVal.message, displayRawVal: false)
	{
		message = msgVal.message;
		pinnedPacket = GCHandle.Alloc(message, GCHandleType.Pinned);
		p = pinnedPacket.AddrOfPinnedObject();
		pCGPSHdr = new IntPtr(p.ToInt64() + 16);
		pCGPS = new IntPtr(pCGPSHdr.ToInt64() + 28);
		ds = (LogCGPSMeasurementHdrType)Marshal.PtrToStructure(pCGPSHdr, typeof(LogCGPSMeasurementHdrType));
		for (int i = 0; i < ds.number_svs; i++)
		{
			IntPtr ptr = new IntPtr(pCGPS.ToInt64() + i * 59);
			ref LogCGPSMeasurementType reference = ref dsSv[i];
			reference = (LogCGPSMeasurementType)Marshal.PtrToStructure(ptr, typeof(LogCGPSMeasurementType));
		}
	}

	public double getCNO()
	{
		return getCNO(0);
	}

	public double getCNO(int svNum)
	{
		if (ds.number_svs > svNum)
		{
			double num = dsSv[svNum].cno;
			return num / 100.0;
		}
		return 0.0;
	}

	public int getSVID(int svNum)
	{
		if (ds.number_svs > svNum)
		{
			return dsSv[svNum].sv_id;
		}
		return 0;
	}

	public byte getGoodObsCnt()
	{
		return getGoodObsCnt(0);
	}

	public byte getGoodObsCnt(int svNum)
	{
		if (ds.number_svs > svNum)
		{
			return dsSv[svNum].good_obs_cnt;
		}
		return 0;
	}

	public override string ToString()
	{
		string text = base.ToString() + $"FCount: {ds.fcount}";
		for (int i = 0; i < ds.number_svs; i++)
		{
			text = text + Environment.NewLine + $" SV: {getSVID(i):00}" + $" CNO: {getCNO(i):0.00} ";
		}
		return text;
	}
}
