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;
}
}