using System; using System.Collections.Generic; using System.Globalization; using System.Web.Script.Serialization; namespace HikvisionAttendanceService; /// Parses UserInfo/Search JSON into rows (best-effort, firmware-tolerant). internal static class UserSyncJsonParser { public static List ParseUserInfoSearchPage(string json) { var list = new List(); if (string.IsNullOrWhiteSpace(json)) return list; try { var ser = new JavaScriptSerializer(); object? root = ser.DeserializeObject(json); if (root == null) return list; var userInfos = FindUserInfoArray(root); if (userInfos == null) return list; foreach (var item in userInfos) { if (item is Dictionary d) { var u = MapUser(d); if (!string.IsNullOrWhiteSpace(u.EmployeeNo)) list.Add(u); } } } catch { // caller logs } return list; } private static object[]? FindUserInfoArray(object root) { var stack = new Stack(); stack.Push(root); while (stack.Count > 0) { var cur = stack.Pop(); if (cur is Dictionary map) { if (map.TryGetValue("UserInfo", out var ui) && ui is object[] arr) return arr; foreach (var kv in map) { if (kv.Value is Dictionary nd) stack.Push(nd); else if (kv.Value is object[] oa) { foreach (var it in oa) if (it != null) stack.Push(it); } } } else if (cur is object[] top) { foreach (var it in top) if (it != null) stack.Push(it); } } return null; } internal static UserDto MapUser(Dictionary d) { var u = new UserDto { EmployeeNo = GetString(d, "employeeNo") ?? "", Name = GetString(d, "name") ?? "", UserType = GetString(d, "userType") ?? "normal", NumOfFace = GetInt(d, "numOfFace"), NumOfFp = GetInt(d, "numOfFP", "numOfFp", "numOfFingerPrint"), Gender = GetString(d, "gender") ?? "", FaceUrl = GetString(d, "faceURL", "faceUrl") ?? "" }; if (d.TryGetValue("Valid", out var vObj) && vObj is Dictionary vd) { u.ValidEnable = GetBool(vd, "enable", defaultValue: true); var b = GetString(vd, "beginTime"); var e = GetString(vd, "endTime"); if (!string.IsNullOrWhiteSpace(b)) u.ValidBeginTime = b!; if (!string.IsNullOrWhiteSpace(e)) u.ValidEndTime = e!; } u.DoorRight = GetString(d, "doorRight") ?? u.DoorRight; if (d.TryGetValue("RightPlan", out var rpObj) && rpObj is object[] rpArr && rpArr.Length > 0 && rpArr[0] is Dictionary rp0) { u.RightPlanDoorNo = GetIntWithDefault(rp0, 1, "doorNo"); u.RightPlanTemplateNo = GetString(rp0, "planTemplateNo") ?? u.RightPlanTemplateNo; } if (string.IsNullOrWhiteSpace(u.UserType)) u.UserType = "normal"; return u; } private static string? GetString(Dictionary d, params string[] keys) { foreach (var k in keys) { if (!d.TryGetValue(k, out var v) || v == null) continue; var s = v.ToString(); if (!string.IsNullOrWhiteSpace(s)) return s.Trim(); } return null; } private static int GetInt(Dictionary d, params string[] keys) { return GetIntWithDefault(d, 0, keys); } private static int GetIntWithDefault(Dictionary d, int defaultValue, params string[] keys) { foreach (var k in keys) { if (!d.TryGetValue(k, out var v) || v == null) continue; switch (v) { case int i: return i; case long l: return l > int.MaxValue ? int.MaxValue : (int)l; case double db: return (int)db; case string s when int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var n): return n; } } return defaultValue; } private static bool GetBool(Dictionary d, string key, bool defaultValue) { if (!d.TryGetValue(key, out var v) || v == null) return defaultValue; if (v is bool b) return b; var s = v.ToString(); if (bool.TryParse(s, out var pb)) return pb; if (string.Equals(s, "1", StringComparison.Ordinal)) return true; if (string.Equals(s, "0", StringComparison.Ordinal)) return false; return defaultValue; } }