using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; namespace YKC { public class GunData { public List Current { get; set; } = new List(); public List Voltage { get; set; } = new List(); public List Power { get; set; } = new List(); public List Energy { get; set; } = new List(); public List ServiceFee { get; set; } = new List(); public List ElectricityFee { get; set; } = new List(); public List TotalAmount { get; set; } = new List(); public List Status { get; set; } = new List(); public List Timestamps { get; set; } = new List(); public string OrderNo { get; set; } = ""; public double? Soc { get; set; } = null; public double? CumulativeTime { get; set; } = 0; public double? RemainingTime { get; set; } = 0; private const int MaxPoints = 300; private void AddToList(List list, T value) { list.Add(value); if (list.Count > MaxPoints) list.RemoveAt(0); } public void Append(JObject g) { AddToList(Timestamps, DateTime.Now); AddToList(Current, g.Value("current") ?? double.NaN); AddToList(Voltage, g.Value("voltage") ?? double.NaN); AddToList(Power, g.Value("power") ?? double.NaN); AddToList(Energy, g.Value("energy") ?? double.NaN); AddToList(ServiceFee, g.Value("service_fee") ?? double.NaN); AddToList(ElectricityFee, g.Value("electricity_fee") ?? double.NaN); double? total = g.Value("total_amount"); if (total == null) { double? sf = g.Value("service_fee"); double? ef = g.Value("electricity_fee"); if (sf != null && ef != null) total = sf + ef; } AddToList(TotalAmount, total ?? double.NaN); AddToList(Status, g.Value("status") ?? 0); OrderNo = g.Value("order_no") ?? OrderNo; Soc = g.Value("soc") ?? Soc; CumulativeTime = g.Value("cumulative_time") ?? CumulativeTime; RemainingTime = g.Value("remaining_time") ?? RemainingTime; } public double? LatestOrNull(List list) { for (int i = list.Count - 1; i >= 0; i--) if (!double.IsNaN(list[i])) return list[i]; return null; } public int? LatestStatus() { for (int i = Status.Count - 1; i >= 0; i--) return Status[i]; return null; } } public class PileData { public GunData Gun1 { get; set; } = new GunData(); public GunData Gun2 { get; set; } = new GunData(); } public class PilesDataStore { private readonly object _lock = new object(); public Dictionary Piles { get; } = new Dictionary(); private const int PileCount = 6; public PilesDataStore() { for (int i = 1; i <= PileCount; i++) Piles[i] = new PileData(); } public void HandleReport(JObject msg) { var pilesArr = msg["piles"] as JArray ?? msg["data"] as JArray; if (pilesArr == null) return; lock (_lock) { foreach (var p in pilesArr) { int idx = p.Value("index") ?? p.Value("pile_index") ?? p.Value("id") ?? 0; if (idx < 1 || idx > PileCount) continue; var gunsArr = p["guns"] as JArray; if (gunsArr == null) { Piles[idx].Gun1.Append((JObject)p); continue; } foreach (var g in gunsArr) { int gunNum = g.Value("gun") ?? g.Value("gun_no") ?? g.Value("id") ?? 0; if (gunNum == 1) Piles[idx].Gun1.Append((JObject)g); else if (gunNum == 2) Piles[idx].Gun2.Append((JObject)g); } } } } public JObject GetLatest(int pileIndex, int gunNum) { lock (_lock) { if (!Piles.ContainsKey(pileIndex)) return null; var gun = gunNum == 1 ? Piles[pileIndex].Gun1 : Piles[pileIndex].Gun2; return new JObject { ["current"] = gun.LatestOrNull(gun.Current), ["voltage"] = gun.LatestOrNull(gun.Voltage), ["power"] = gun.LatestOrNull(gun.Power), ["energy"] = gun.LatestOrNull(gun.Energy), ["service_fee"] = gun.LatestOrNull(gun.ServiceFee), ["electricity_fee"] = gun.LatestOrNull(gun.ElectricityFee), ["total_amount"] = gun.LatestOrNull(gun.TotalAmount), ["status"] = gun.LatestStatus(), ["order_no"] = gun.OrderNo, ["soc"] = gun.Soc, ["cumulative_time"] = gun.CumulativeTime, ["remaining_time"] = gun.RemainingTime, }; } } public JArray GetChartData(int pileIndex, int gunNum) { lock (_lock) { if (!Piles.ContainsKey(pileIndex)) return null; var gun = gunNum == 1 ? Piles[pileIndex].Gun1 : Piles[pileIndex].Gun2; var arr = new JArray(); for (int i = 0; i < gun.Timestamps.Count; i++) { arr.Add(new JObject { ["t"] = new DateTimeOffset(gun.Timestamps[i]).ToUnixTimeSeconds(), ["current"] = double.IsNaN(gun.Current[i]) ? (JToken)null : gun.Current[i], ["voltage"] = double.IsNaN(gun.Voltage[i]) ? (JToken)null : gun.Voltage[i], ["power"] = double.IsNaN(gun.Power[i]) ? (JToken)null : gun.Power[i], }); } return arr; } } } public static class PilesStoreHolder { public static readonly PilesDataStore Instance = new PilesDataStore(); } }