using System;

namespace LFP_Manager.DataStructure
{
    public class CsDeviceData : IResettable, IDeepCopy<CsDeviceData>
    {
        public DeviceSystemTotalData TotalData;
        public DeviceModuleData[] ModuleData;

        public CsDeviceData()
        {
            TotalData = new DeviceSystemTotalData();
            ModuleData = new DeviceModuleData[csConstData.SystemInfo.MAX_MODULE_SIZE];
            for (int i = 0; i < ModuleData.Length; i++)
            {
                ModuleData[i] = new DeviceModuleData();
            }
        }
        public void Reset()
        {
            TotalData.Reset();
            for (int i = 0; i < ModuleData.Length; i++)
            {
                ResetCopyHelpers.ResetOrRecreate(ref ModuleData[i]);
            }
        }
        public CsDeviceData DeepCopy()
        {
            var copy = (CsDeviceData)MemberwiseClone(); // 스칼라 복사
            copy.TotalData = ResetCopyHelpers.DeepCopyOrNew(TotalData);
            for (int i = 0; i < ModuleData.Length; i++)
            {
                ModuleData[i] = ResetCopyHelpers.DeepCopyOrNew(ModuleData[i]);
            }
            return copy;
        }

        #region TOTAL DATA
        public class DeviceSystemTotalData : IResettable, IDeepCopy<DeviceSystemTotalData>
        {
            public bool CommFail;

            public DeviceSystemIdent IdentData;
            public DeviceValueTotalData ValueData;
            public DeviceStatusTotalData StatusData;

            public DeviceSystemTotalData()
            {
                IdentData = new DeviceSystemIdent();
                ValueData = new DeviceValueTotalData();
                StatusData = new DeviceStatusTotalData();
            }
            public void Reset()
            {
                CommFail = false;
                IdentData.Reset();
                ValueData.Reset();
                StatusData.Reset();
            }
            public DeviceSystemTotalData DeepCopy()
            {
                var copy = (DeviceSystemTotalData)MemberwiseClone(); // 스칼라 복사
                copy.IdentData = IdentData.DeepCopy();
                copy.ValueData = ValueData.DeepCopy();
                copy.StatusData = StatusData.DeepCopy();
                return copy;
            }

            public class DeviceSystemIdent : IResettable, IDeepCopy<DeviceSystemIdent>
            {
                public byte[] fw_ver;
                public string FwVerStr;

                public string Manufacturer;
                public string DeviceModel;
                public int AlarmOutputMode;

                public UInt32 ManufactureDate;
                public string SerialNumber;

                public DeviceSystemIdent()
                {
                    fw_ver = new byte[4];
                    FwVerStr = "";

                    Manufacturer = "";
                    DeviceModel = "";

                    AlarmOutputMode = 0;
                    ManufactureDate = 0;
                    SerialNumber = "";
                }
                public void Reset()
                {
                    Manufacturer = "";
                    DeviceModel = "";

                    Array.Clear(fw_ver, 0, fw_ver.Length);
                    FwVerStr = "";

                    AlarmOutputMode = 0;
                    ManufactureDate = 0;
                    SerialNumber = "";
                }
                public DeviceSystemIdent DeepCopy()
                {
                    var copy = (DeviceSystemIdent)MemberwiseClone(); // 스칼라 복사
                    copy.fw_ver = (byte[])fw_ver.Clone();
                    return copy;
                }
            }

            public class DeviceValueTotalData : IResettable, IDeepCopy<DeviceValueTotalData>
            {
                public short TotalVoltage;
                public short TotalCurrent;
                public short TotalSOC;
                public short TotalSOH;
                public short TotalTemp;

                public DeviceValueTotalData()
                {
                    TotalVoltage = 0;
                    TotalCurrent = 0;
                    TotalSOC = 0;
                    TotalSOH = 0;
                    TotalTemp = 0;
                }

                public void Reset()
                {
                    TotalVoltage = 0;
                    TotalCurrent = 0;
                    TotalSOC = 0;
                    TotalSOH = 0;
                    TotalTemp = 0;
                }
                public DeviceValueTotalData DeepCopy()
                {
                    return (DeviceValueTotalData)MemberwiseClone();
                }
            }

            public class DeviceStatusTotalData : IResettable, IDeepCopy<DeviceStatusTotalData>
            {
                public ushort batteryStatus;
                public ushort warning;
                public ushort protection;
                public ushort status;

                public DeviceStatusTotalData()
                {
                    batteryStatus = 0;
                    warning = 0;
                    protection = 0;
                    status = 0;
                }
                public void Reset()
                {
                    batteryStatus = 0;
                    warning = 0;
                    protection = 0;
                    status = 0;
                }
                public DeviceStatusTotalData DeepCopy()
                {
                    return (DeviceStatusTotalData)MemberwiseClone();
                }
            }

        }

        #endregion

        #region MODULE DATA
        public class DeviceModuleData : IResettable, IDeepCopy<DeviceModuleData>
        {
            public bool active;

            public int mNo;
            public int cellQty;
            public int tempQty;
            public int ntcQty;
            public int ChargeVoltage;
            public int DOD;
            public int MaxChaCurrent;
            public int MaxDchCurrent;

            public int FloatVoltage;
            public int BoostVoltage;

            public int MinChargeTemp;
            public int MaxChargeTemp;

            public UInt32 heatbeat;
            public bool CommFail;
            public bool ShelfCommFail;
            public DateTime LastRxTime;
            public Int32 BmsDateTimeInt;
            public ushort BmsDateTimeShort1;
            public ushort BmsDateTimeShort2;

            public DateTimeStruct BmsDateTime;

            public DeviceValueData ValueData;
            public DeviceAvgData AvgData;
            public DeviceStatusData StatusData;
            public DeviceParamData ParamData;
            public DeviceCalibration CalibrationData;
            public DeviceInforation Information;
            public DeviceEtcStatus EtcStatus;

            public DeviceMaxValue MaxValue;
            public DeviceGyroValue GyroValue;

            public DeviceModuleData()
            {
                active = false;

                mNo = 0;
                cellQty = 15;
                tempQty = 4;
                ChargeVoltage = 0;
                DOD = 0;
                MaxChaCurrent = 0;
                MaxDchCurrent = 0;

                heatbeat = 0;
                CommFail = false;
                ShelfCommFail = false;
                LastRxTime = DateTime.MinValue;
                BmsDateTimeInt = 0;
                BmsDateTimeShort1 = 0;
                BmsDateTimeShort2 = 0;

                BmsDateTime = new DateTimeStruct();

                ValueData = new DeviceValueData();
                AvgData = new DeviceAvgData();
                StatusData = new DeviceStatusData();
                ParamData = new DeviceParamData();
                CalibrationData = new DeviceCalibration();
                Information = new DeviceInforation();
                EtcStatus = new DeviceEtcStatus();

                MaxValue = new DeviceMaxValue();
                GyroValue = new DeviceGyroValue();
            }
            public void Reset()
            {
                active = false;

                mNo = 0;
                cellQty = 15;
                tempQty = 4;
                ChargeVoltage = 0;
                DOD = 0;
                MaxChaCurrent = 0;
                MaxDchCurrent = 0;

                heatbeat = 0;
                CommFail = false;
                ShelfCommFail = false;
                LastRxTime = DateTime.MinValue;
                BmsDateTimeInt = 0;
                BmsDateTimeShort1 = 0;
                BmsDateTimeShort2 = 0;

                ResetCopyHelpers.ResetOrRecreate(ref BmsDateTime);
                ResetCopyHelpers.ResetOrRecreate(ref ValueData);
                ResetCopyHelpers.ResetOrRecreate(ref AvgData);
                ResetCopyHelpers.ResetOrRecreate(ref ParamData);
                ResetCopyHelpers.ResetOrRecreate(ref CalibrationData);
                ResetCopyHelpers.ResetOrRecreate(ref Information);
                ResetCopyHelpers.ResetOrRecreate(ref EtcStatus);
                ResetCopyHelpers.ResetOrRecreate(ref MaxValue);
                ResetCopyHelpers.ResetOrRecreate(ref GyroValue);
            }
            public DeviceModuleData DeepCopy()
            {
                var copy = (DeviceModuleData)MemberwiseClone(); // 스칼라 복사
                BmsDateTime = ResetCopyHelpers.DeepCopyOrNew(BmsDateTime);
                ValueData = ResetCopyHelpers.DeepCopyOrNew(ValueData);
                AvgData = ResetCopyHelpers.DeepCopyOrNew(AvgData);
                StatusData = ResetCopyHelpers.DeepCopyOrNew(StatusData);
                ParamData = ResetCopyHelpers.DeepCopyOrNew(ParamData);
                CalibrationData = ResetCopyHelpers.DeepCopyOrNew(CalibrationData);
                EtcStatus = ResetCopyHelpers.DeepCopyOrNew(EtcStatus);
                MaxValue = ResetCopyHelpers.DeepCopyOrNew(MaxValue);
                GyroValue = ResetCopyHelpers.DeepCopyOrNew(GyroValue);
                return copy;
            }

            public class DateTimeStruct : IResettable, IDeepCopy<DateTimeStruct>
            {
                public int year;
                public int month;
                public int day;
                public int hour;
                public int minute;
                public int second;

                public string DateTimeStr;

                public DateTimeStruct()
                {
                    DateTimeStr = "-";

                }

                public void SetDateTimeStr()
                {
                    DateTimeStr = String.Format("{0:D4}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}", year, month, day, hour, minute, second);
                }

                public DateTime ToDateTime()
                {
                    return new DateTime(year, month, day, hour, minute, second);
                }

                public void FromDateTime(DateTime dt)
                {
                    year = dt.Year;
                    month = dt.Month;
                    day = dt.Day;
                    hour = dt.Hour;
                    minute = dt.Minute;
                    second = dt.Second;

                    SetDateTimeStr();
                }

                public void Reset()
                {
                    year = 0;
                    month = 0;
                    day = 0;
                    hour = 0;
                    minute = 0;
                    second = 0;

                    DateTimeStr = "-";
                }

                public DateTimeStruct DeepCopy()
                {
                    return (DateTimeStruct)MemberwiseClone();
                }
            }

            public class DeviceValueData : IResettable, IDeepCopy<DeviceValueData>
            {
                public byte[] fw_ver;
                public ushort[] CellVoltage;
                public short[] CellTemperature;

                public short voltage;
                public short current;
                public short cha_current;
                public short dch_current;
                public short averageCurrent;
                public short SOC;
                public short SOH;

                public short NumOfCells;
                public short NumOfTemps;

                public ushort MaxCellVoltage;            // mV
                public ushort MinCellVoltage;            // mV
                public ushort DiffCellVoltage;            // mV

                public short MosTemperature;
                public short AmbTemperature;
                public short MaxTemperature;            // 1C
                public short MinTemperature;            // 0.1C

                public int RecMaxBattChgCurrLmt;

                public short remainingCapacity;
                public UInt32 cycleCount;
                public UInt32 cycleCount_MSB;
                public UInt32 cycleCount_LSB;
                public UInt32 fullChgCapacity_mAs;
                public UInt32 fullChgCapacity_mAs_MSB;
                public UInt32 fullChgCapacity_mAs_LSB;
                public UInt32 fullChgCapacity_Ah;
                public UInt32 TotalBatCapacity_Ah;
                public int designedCapacity;

                public UInt32 EstBackupTime;            // Minute - Back-up time based on %SoC level and load at 
                                                        // site(In case of Charging Default load at 0.2C)

                public UInt32 MdCumulativeChgTime;      // Hours - Cumulative charge duration
                public UInt32 MdCumulativeChgTimeMSB;
                public UInt32 MdCumulativeChgTimeLSB;
                public UInt32 MdCumulativeDchTime;      // Hours - Cumulative discharge duration
                public UInt32 MdCumulativeDchTimeMSB;
                public UInt32 MdCumulativeDchTimeLSB;

                public ushort ChgCrate;
                public ushort DchCrate;
                public ushort MdACIR;

                public ushort RemainEnergyLife;         // Remaining capacity in battery pack in life cycle
                                                        // (13440 - actual cumulative discharge KWH)
                public ushort RemainCycles;             // Remaining cycle in battery pack in life time
                                                        // (3500 - actual cycle consumed)

                public ushort ChgCutOffVolt;
                public ushort DchCutOffVolt;

                public ushort BatPowerOnDateYear;       // YY
                public ushort BatPowerOnDateMonth;      // MM

                public int TimeLeft;

                public UInt32 Ah_Charged;
                public UInt32 Ah_ChargedMSB;
                public UInt32 Ah_ChargedLSB;
                public UInt32 Ah_Discharged;
                public UInt32 Ah_DischargedMSB;
                public UInt32 Ah_DischargedLSB;

                public UInt32 Wh_Charged;
                public UInt32 Wh_ChargedMSB;
                public UInt32 Wh_ChargedLSB;
                public UInt32 Wh_Discharged;
                public UInt32 Wh_DischargedMSB;
                public UInt32 Wh_DischargedLSB;

                public int NoOfDischargeCycles;
                public int NoOfChargeCycles;

                public int ModuleAlarms;
                public int ModuleWarnings;
                public int ModuleStatus;
                public int ModuleVoltage_int;
                public int ModBusDocVersion;

                public int ParametersChanged;
                public int MaxBattChgCurr;
                public int MaxBattDchCurr;
                public int ShortCircuitCurrent;
                public int ProtectChgCurr;
                public int ProtectDchCurr;

                public int BatteryProdDateYear;
                public int BatteryProdDateMonth;
                public int BatteryProdDateDay;

                public int BatteryModelDescription;
                public int BatteryType;

                public DeviceValueData()
                {
                    fw_ver = new byte[6];
                
                    CellVoltage = new ushort[csConstData.SystemInfo.MAX_MODULE_CELL_SIZE + 1];
                    CellTemperature = new short[csConstData.SystemInfo.MAX_MODULE_TEMP_SIZE];
                }

                /// <summary>
                /// 현재 보유한 버퍼 크기를 유지하면서 모든 값을 0으로 초기화
                /// </summary>
                public void Reset()
                {
                    // 배열/버퍼는 전부 0으로
                    fw_ver.AsSpan().Clear();
                    CellVoltage.AsSpan().Clear();
                    CellTemperature.AsSpan().Clear();

                    // 스칼라 필드 전부 0/기본값
                    voltage = 0;
                    current = cha_current = dch_current = averageCurrent = 0;
                    SOC = SOH = 0;

                    NumOfCells = 0;
                    NumOfTemps = 0;

                    MaxCellVoltage = MinCellVoltage = DiffCellVoltage = 0;

                    MosTemperature = AmbTemperature = 0;
                    MaxTemperature = MinTemperature = 0;

                    RecMaxBattChgCurrLmt = 0;

                    remainingCapacity = 0;
                    cycleCount = cycleCount_MSB = cycleCount_LSB = 0;
                    fullChgCapacity_mAs = fullChgCapacity_mAs_MSB = fullChgCapacity_mAs_LSB = 0;
                    fullChgCapacity_Ah = TotalBatCapacity_Ah = 0;
                    designedCapacity = 0;

                    EstBackupTime = 0;

                    MdCumulativeChgTime = MdCumulativeChgTimeMSB = MdCumulativeChgTimeLSB = 0;
                    MdCumulativeDchTime = MdCumulativeDchTimeMSB = MdCumulativeDchTimeLSB = 0;

                    ChgCrate = DchCrate = MdACIR = 0;

                    RemainEnergyLife = RemainCycles = 0;

                    ChgCutOffVolt = DchCutOffVolt = 0;

                    BatPowerOnDateYear = BatPowerOnDateMonth = 0;

                    TimeLeft = 0;

                    Ah_Charged = Ah_ChargedMSB = Ah_ChargedLSB = 0;
                    Ah_Discharged = Ah_DischargedMSB = Ah_DischargedLSB = 0;

                    Wh_Charged = Wh_ChargedMSB = Wh_ChargedLSB = 0;
                    Wh_Discharged = Wh_DischargedMSB = Wh_DischargedLSB = 0;

                    NoOfDischargeCycles = NoOfChargeCycles = 0;

                    ModuleAlarms = ModuleWarnings = ModuleStatus = 0;
                    ModuleVoltage_int = ModBusDocVersion = 0;

                    ParametersChanged = 0;
                    MaxBattChgCurr = MaxBattDchCurr = ShortCircuitCurrent = 0;
                    ProtectChgCurr = ProtectDchCurr = 0;

                    BatteryProdDateYear = BatteryProdDateMonth = BatteryProdDateDay = 0;

                    BatteryModelDescription = 0;
                    BatteryType = 0;
                }
                public DeviceValueData DeepCopy()
                {
                    var copy = (DeviceValueData)MemberwiseClone(); // 스칼라 복사
                    copy.fw_ver = (byte[])fw_ver.Clone();
                    copy.CellVoltage = (ushort[])CellVoltage.Clone();
                    copy.CellTemperature = (short[])CellTemperature.Clone();
                    return copy;
                }
            }

            public class DeviceAvgData : IResettable, IDeepCopy<DeviceAvgData>
            {
                public short maxCellVoltage;
                public short minCellVoltage;
                public short avgCellVoltage;
                public short diffCellVoltage;
                public short maxCellNum;
                public short minCellNum;
                public short maxTemp;
                public short minTemp;
                public short avgTemp;
                public short diffTemp;
                public short maxTempNum;
                public short minTempNum;

                public DeviceAvgData()
                {

                }

                public void Reset()
                {
                    maxCellVoltage = 0;
                    minCellVoltage = 0;
                    avgCellVoltage = 0;
                    diffCellVoltage = 0;
                    maxCellNum = 0;
                    minCellNum = 0;

                    maxTemp = 0;
                    minTemp = 0;
                    avgTemp = 0;
                    diffTemp = 0;
                    maxTempNum = 0;
                    minTempNum = 0;
                }
                public DeviceAvgData DeepCopy()
                {
                    return (DeviceAvgData)MemberwiseClone();
                }
            }

            public class DeviceStatusData : IResettable, IDeepCopy<DeviceStatusData>
            {
                public ushort batteryStatus;
                public ushort batteryStatus1;
                public ushort warning;
                public ushort protect;
                public ushort protection1;
                public ushort status;
                public ushort faultAndStatus;
                public ushort relayStatus;
                public ushort errorCode;
                public ushort specialAlarm;          // 1: Commfail, 2. Gyro, 3, Breaker

                public ushort faultstatus;           // Only for RS-485

                public ushort cellBallanceStatus;
                public ushort cellBalanceValue;
                public ushort cellBalanceFlag;

                public DeviceStatusData()
                {

                }
                public void Reset()
                {
                    batteryStatus = 0;
                    batteryStatus1 = 0;
                    warning = 0;
                    protect = 0;
                    protection1 = 0;
                    status = 0;
                    faultAndStatus = 0;
                    relayStatus = 0;
                    errorCode = 0;
                    specialAlarm = 0;

                    faultstatus = 0;

                    cellBallanceStatus = 0;
                    cellBalanceValue = 0;
                    cellBalanceFlag = 0;
                }
                public DeviceStatusData DeepCopy()
                {
                    return (DeviceStatusData)MemberwiseClone();
                }
            }

            public class DeviceParamData : IResettable, IDeepCopy<DeviceParamData>
            {
                public short CellOverVoltageTrip;
                public short CellOverVoltageWarning;
                public short CellOverVoltageRelease;
                public short CellUnderVoltageTrip;
                public short CellUnderVoltageWarning;
                public short CellUnderVoltageRelease;

                public short SysOverVoltageTrip;
                public short SysOverVoltageWarning;
                public short SysOverVoltageRelease;
                public short SysUnderVoltageTrip;
                public short SysUnderVoltageWarning;
                public short SysUnderVoltageRelease;

                public short ChaHighTempTrip;
                public short ChaHighTempWarning;
                public short ChaHighTempRelease;
                public short ChaLowTempTrip;
                public short ChaLowTempWarning;
                public short ChaLowTempRelease;
                public short DchHighTempTrip;
                public short DchHighTempWarning;
                public short DchHighTempRelease;
                public short DchLowTempTrip;
                public short DchLowTempWarning;
                public short DchLowTempRelease;

                public short ChaOverCurrentTrip1;
                public short ChaOverCurrentTrip2;
                public short ChaOverCurrentWarning;
                public short ChaOverCurrentReleaseTime;
                public short ChaOverCurrentTimes;
                public short ChaOverCurrentDelay1;
                public short ChaOverCurrentDelay2;

                public short DchOverCurrentTrip1;
                public short DchOverCurrentTrip2;
                public short DchOverCurrentWarning;
                public short DchOverCurrentReleaseTime;
                public short DchOverCurrentTimes;
                public short DchOverCurrentDelay1;
                public short DchOverCurrentDelay2;

                public short MosHighTempTrip;
                public short MosHighTempWarning;
                public short MosHighTempRelease;

                public short PcbHighTempTrip;
                public short PcbHighTempWarning;
                public short PcbHighTempRelease;

                public short EnvHighTempTrip;
                public short EnvHighTempWarning;
                public short EnvHighTempRelease;

                public short EnvLowTempTrip;
                public short EnvLowTempWarning;
                public short EnvLowTempRelease;

                public short ShortCircuit;

                public short LowSocTrip;
                public short LowSocWarning;
                public short LowSocRelease;

                public short CellVoltageDifferenceTrip;
                public short CellVoltageDifferenceWarning;
                public short CellVoltageDifferenceRelease;
                public short CellVoltageDifferenceTime;

                public short DefalutParamOption;
                public short DefalutParamAll;
                public ushort ReadParamAll;

                /// <summary>
                /// 모든 필드를 0(또는 기본값)으로 초기화합니다.
                /// </summary>
                public void Reset()
                {
                    CellOverVoltageTrip = CellOverVoltageWarning = CellOverVoltageRelease = 0;
                    CellUnderVoltageTrip = CellUnderVoltageWarning = CellUnderVoltageRelease = 0;

                    SysOverVoltageTrip = SysOverVoltageWarning = SysOverVoltageRelease = 0;
                    SysUnderVoltageTrip = SysUnderVoltageWarning = SysUnderVoltageRelease = 0;

                    ChaHighTempTrip = ChaHighTempWarning = ChaHighTempRelease = 0;
                    ChaLowTempTrip = ChaLowTempWarning = ChaLowTempRelease = 0;
                    DchHighTempTrip = DchHighTempWarning = DchHighTempRelease = 0;
                    DchLowTempTrip = DchLowTempWarning = DchLowTempRelease = 0;

                    ChaOverCurrentTrip1 = ChaOverCurrentTrip2 = ChaOverCurrentWarning = 0;
                    ChaOverCurrentReleaseTime = 0;
                    ChaOverCurrentTimes = 0;
                    ChaOverCurrentDelay1 = ChaOverCurrentDelay2 = 0;

                    DchOverCurrentTrip1 = DchOverCurrentTrip2 = DchOverCurrentWarning = 0;
                    DchOverCurrentReleaseTime = 0;
                    DchOverCurrentTimes = 0;
                    DchOverCurrentDelay1 = DchOverCurrentDelay2 = 0;

                    MosHighTempTrip = MosHighTempWarning = MosHighTempRelease = 0;
                    PcbHighTempTrip = PcbHighTempWarning = PcbHighTempRelease = 0;

                    ShortCircuit = 0;

                    LowSocTrip = LowSocWarning = LowSocRelease = 0;

                    CellVoltageDifferenceTrip = CellVoltageDifferenceWarning = 0;
                    CellVoltageDifferenceRelease = CellVoltageDifferenceTime = 0;

                    DefalutParamOption = 0;
                    DefalutParamAll = 0;
                    ReadParamAll = 0;
                }

                public DeviceParamData DeepCopy()
                {
                    return (DeviceParamData)MemberwiseClone();
                }
            }

            public class DeviceCalibration : IResettable, IDeepCopy<DeviceCalibration>
            {
                public BatteryParameter Battery;
                public CurrentCalib Current;
                public CapCalibration CapCalib;
                public FetCalibration FetCalib;
                public ChargeMode ChaMode;
                public TAntiTheft AntiTheft;
                public TBmsDateTime BmsDateTime;

                public TAntiTheftComm AntiTheftComm;
                public TAntiTheftGyro AntiTheftGyro;

                public DeviceCalibration()
                {
                    Battery = new BatteryParameter();
                    Current = new CurrentCalib();
                    CapCalib = new CapCalibration();
                    FetCalib = new FetCalibration();
                    ChaMode = new ChargeMode();
                    AntiTheft = new TAntiTheft();
                    BmsDateTime = new TBmsDateTime();

                    AntiTheftComm = new TAntiTheftComm();
                    AntiTheftGyro = new TAntiTheftGyro();
                }

                /// <summary>
                /// 모든 하위 객체를 기본값으로 리셋합니다.
                /// - 하위 타입이 IResettable이면 Reset() 호출
                /// - 아니면 새 인스턴스로 교체(참조 재바인딩 허용 시)
                /// </summary>
                public void Reset()
                {
                    ResetCopyHelpers.ResetOrRecreate(ref Battery);
                    ResetCopyHelpers.ResetOrRecreate(ref Current);
                    ResetCopyHelpers.ResetOrRecreate(ref CapCalib);
                    ResetCopyHelpers.ResetOrRecreate(ref FetCalib);
                    ResetCopyHelpers.ResetOrRecreate(ref ChaMode);
                    ResetCopyHelpers.ResetOrRecreate(ref AntiTheft);
                    ResetCopyHelpers.ResetOrRecreate(ref BmsDateTime);
                    ResetCopyHelpers.ResetOrRecreate(ref AntiTheftComm);
                    ResetCopyHelpers.ResetOrRecreate(ref AntiTheftGyro);
                }
                /// <summary>
                /// 깊은 복사. 가능한 경우 하위 객체의 DeepCopy() 사용, 없으면 새 인스턴스 생성(얕은 복사 회피).
                /// </summary>
                public DeviceCalibration DeepCopy()
                {
                    return new DeviceCalibration
                    {
                        Battery = ResetCopyHelpers.DeepCopyOrNew(Battery),
                        Current = ResetCopyHelpers.DeepCopyOrNew(Current),

                        // 기존 코드에선 CapCalib/AntiTheft/ChaMode만 깊은 복사를 하고
                        // 나머지는 얕은 복사를 했습니다. 전부 통일합니다.
                        CapCalib = ResetCopyHelpers.DeepCopyOrNew(CapCalib),
                        FetCalib = ResetCopyHelpers.DeepCopyOrNew(FetCalib),
                        ChaMode = ResetCopyHelpers.DeepCopyOrNew(ChaMode),
                        AntiTheft = ResetCopyHelpers.DeepCopyOrNew(AntiTheft),
                        BmsDateTime = ResetCopyHelpers.DeepCopyOrNew(BmsDateTime),

                        AntiTheftComm = ResetCopyHelpers.DeepCopyOrNew(AntiTheftComm),
                        AntiTheftGyro = ResetCopyHelpers.DeepCopyOrNew(AntiTheftGyro),
                    };
                }

                public class BatteryParameter
                {
                    public short CellQty;
                    public short TempQty;
                    public UInt32 Capacity;

                    public BatteryParameter()
                    {
                        CellQty = 0;
                        TempQty = 0;
                        Capacity = 0;
                    }
                }

                public class CurrentCalib
                {
                    public short ChargeOption;

                    public CurrentCalib()
                    {
                        ChargeOption = 0;
                    }
                }

                public class CapCalibration : IResettable, IDeepCopy<CapCalibration>
                {
                    public int DesignCapacity;
                    public int SocValue;
                    public int CycleCount;

                    public CapCalibration()
                    {
                        DesignCapacity = 0;
                        SocValue = 0;
                        CycleCount = 0;
                    }
                    public void Reset()
                    {
                        DesignCapacity = 0;
                        SocValue = 0;
                        CycleCount = 0;
                    }
                    public CapCalibration DeepCopy()
                    {
                        return (CapCalibration)MemberwiseClone();
                    }
                }

                public class FetCalibration
                {
                    public short FetStatus;
                    public short DchFetOff;             // 6010
                    public short ChaFetOff;             // 6011
                    public short LmtChaFetOff;          // 6012
                    public short PreChaFetOn;           // 6013
                    public short HeaterFetOn;           // 6014
                    public short ChaFetOn;              // 6015

                    public FetCalibration()
                    {
                        FetStatus = 0;
                        DchFetOff = 0;
                        ChaFetOff = 0;
                        LmtChaFetOff = 0;
                        PreChaFetOn = 0;
                        HeaterFetOn = 0;
                        ChaFetOn = 0;
                    }
                }

                public class ChargeMode : IResettable, IDeepCopy<ChargeMode>
                {
                    public int Mode;
                    public int Value;

                    public ChargeMode()
                    {
                        Mode = 0;
                        Value = 0;
                    }
                    public void Reset()
                    {
                        Mode = 0;
                        Value = 0;
                    }
                    public ChargeMode DeepCopy()
                    {
                        return (ChargeMode)MemberwiseClone();
                    }
                }

                public class TAntiTheft : IResettable, IDeepCopy<TAntiTheft>
                {
                    public int Comm;
                    public int GyroScope;

                    public TAntiTheft()
                    {
                        Comm = 0;
                        GyroScope = 0;
                    }
                    public void Reset()
                    {
                        Comm = 0;
                        GyroScope = 0;
                    }
                    public TAntiTheft DeepCopy()
                    {
                        return (TAntiTheft)MemberwiseClone();
                    }
                }

                public class TBmsDateTime : IResettable, IDeepCopy<TBmsDateTime>
                {
                    public string Str;
                    public int lValue;
                    public short[] sValue;

                    public TBmsDateTime()
                    {
                        Str = "";
                        lValue = 0;
                        sValue = new short[2];
                    }
                    public void Reset()
                    {
                        Str = "";
                        lValue = 0;
                        sValue[0] = 0;
                        sValue[1] = 0;
                    }
                    public TBmsDateTime DeepCopy()
                    {
                        var copy = (TBmsDateTime)MemberwiseClone();
                        copy.sValue = (short[])sValue.Clone();
                        return copy;
                    }
                }

                public class TAntiTheftComm : IResettable, IDeepCopy<TAntiTheftComm>
                {
                    public int TimeOut;
                    public int FuncSwitch;
                    public int Unlock;

                    public TAntiTheftComm()
                    {
                        TimeOut = 0;
                        FuncSwitch = 0;
                        Unlock = 0;
                    }
                    public void Reset()
                    {
                        TimeOut = 0;
                        FuncSwitch = 0;
                        Unlock = 0;
                    }
                    public TAntiTheftComm DeepCopy()
                    {
                        return (TAntiTheftComm)MemberwiseClone();
                    }
                }

                public class TAntiTheftGyro : IResettable, IDeepCopy<TAntiTheftGyro>
                {
                    public int XAxis;
                    public int YAxis;
                    public int ZAxis;
                    public int GyroPolicySel;
                    public int GyroFuncSwitch;
                    public int GyroState;
                    public int Unlock;

                    public TAntiTheftGyro()
                    {
                        XAxis = 0;
                        YAxis = 0;
                        ZAxis = 0;
                        GyroPolicySel = 0;
                        GyroFuncSwitch = 0;
                        GyroState = 0;
                        Unlock = 0;
                    }
                    public void Reset()
                    {
                        XAxis = 0;
                        YAxis = 0;
                        ZAxis = 0;
                        GyroPolicySel = 0;
                        GyroFuncSwitch = 0;
                        GyroState = 0;
                        Unlock = 0;
                    }
                    public TAntiTheftGyro DeepCopy()
                    {
                        return (TAntiTheftGyro)MemberwiseClone();
                    }
                }
            }

            public class DeviceInforation : IResettable, IDeepCopy<DeviceInforation>
            {
                public UInt32 ManufactureDate;
                public byte[] Model_Byte;
                public byte[] FwVer_Byte;
                public string Model_Str;
                public string FwVer_Str;
                public byte[] BMS_SN;
                public string BMS_SN_Str;
                public byte[] Module_SN;

                public byte[] ManufactureName;
                public string ManufactureName_Str;

                public byte[] ManuDate_Byte;

                public string VendorName;
                public string ProductCode;
                public string MajorMinorRev;
                public string ModelName;
                public string HwSerialNumber;
                public string HwProductRev;
                public string ManufacturingDate;
                public string SwProductRev;

                public DeviceInforation()
                {
                    Model_Byte = new byte[24];
                    FwVer_Byte = new byte[6];
                    Model_Str = " ";
                    FwVer_Str = " ";
                    BMS_SN = new byte[32];
                    BMS_SN_Str = " ";
                    Module_SN = new byte[32];

                    ManufactureName_Str = " ";
                    ManufactureName = new byte[10];

                    ManuDate_Byte = new byte[16];

                    VendorName = "-";
                    ProductCode = "-";
                    MajorMinorRev = "-";
                    ModelName = "-";
                    HwSerialNumber = "-";
                    HwProductRev = "-";
                    ManufacturingDate = "-";
                    SwProductRev = "-";
                }
                public void Reset()
                {
                    ManufactureDate = 0;

                    Array.Clear(Model_Byte, 0, Model_Byte.Length);
                    Array.Clear(FwVer_Byte, 0, FwVer_Byte.Length);
                    Model_Str = " ";
                    FwVer_Str = " ";

                    Array.Clear(BMS_SN, 0, BMS_SN.Length);
                    BMS_SN_Str = " ";
                    Array.Clear(Module_SN, 0, Module_SN.Length);

                    Array.Clear(ManufactureName, 0, ManufactureName.Length);
                    ManufactureName_Str = " ";

                    Array.Clear(ManuDate_Byte, 0, ManuDate_Byte.Length);

                    VendorName = "-";
                    ProductCode = "-";
                    MajorMinorRev = "-";
                    ModelName = "-";
                    HwSerialNumber = "-";
                    HwProductRev = "-";
                    ManufacturingDate = "-";
                    SwProductRev = "-";
                }
                public DeviceInforation DeepCopy()
                {
                    var copy = (DeviceInforation)MemberwiseClone();
                    copy.Model_Byte = (byte[])Model_Byte.Clone();
                    copy.Model_Byte = (byte[])FwVer_Byte.Clone();
                    copy.Model_Byte = (byte[])BMS_SN.Clone();
                    copy.Model_Byte = (byte[])Module_SN.Clone();
                    copy.Model_Byte = (byte[])ManufactureName.Clone();
                    copy.Model_Byte = (byte[])ManuDate_Byte.Clone();
                    return copy;
                }
            }

            public class DeviceEtcStatus : IResettable
            {
                public short SwitchHW;
                public short SwitchWarning;
                public short SwitchProtect;
                public ushort LogDurationIdle;      // min
                public ushort LogDurationActive;    // min
                public UInt32 DataAndTime;
                public ushort ChgOCPModel;          /* 充电限流
                                                    0：不限流保护
                                                    1：始终限流充电
                                                    2：预充保护
                                                    4：充电过流后限流
                                                    8：预充+充电过流后限流 */
                public short ChgLmtVoltage;         // mv
                public short SOC_StopFloat;         // % 暂停浮充Soc
                public short SOC_RecvFloat;         // % 恢复浮充电压
                public short DurationFloat;         // sec
                public short DurationIdle;          // sec
                public short VoltageStopFloat;      // 0.1V
                public short VoltageRecvFloat;      // 0.1V
                public short FloatMode;             /*  0000: 持续浮充
                                                    0001：检测电压
                                                    0002：定时浮充
                                                    0003：检测SOC */
                public short BalanceVoltage;        // mV 均衡启动电压
                public short BalanceDeltaV;         // mV 均衡启动压差
                public short WarnLowCapacity;       // 低容量告警
                public short HistroyDelete;         // 删除数据记录

                public DeviceEtcStatus()
                {

                }
                public void Reset()
                {
                    SwitchHW = 0;
                    SwitchWarning = 0;
                    SwitchProtect = 0;
                    LogDurationIdle = 0;
                    LogDurationActive = 0;
                    DataAndTime = 0;
                    ChgOCPModel = 0;
                    ChgLmtVoltage = 0;
                    SOC_StopFloat = 0;
                    SOC_RecvFloat = 0;
                    DurationFloat = 0;
                    DurationIdle = 0;
                    VoltageStopFloat = 0;
                    VoltageRecvFloat = 0;
                    FloatMode = 0;
                    BalanceVoltage = 0;
                    BalanceDeltaV = 0;
                    WarnLowCapacity = 0;
                    HistroyDelete = 0;
                }
            }

            public class DeviceMaxValue : IResettable
            {
                public short MaxChgCurrent;
                public short MaxChgTemperature;
                public short MinChgTemperature;
                public short FloatChgVolt;
                public short BoostChgVolt;

                public DeviceMaxValue()
                {
                }

                public void Reset()
                {
                    MaxChgCurrent = 0;
                    MaxChgTemperature = 0;
                    MinChgTemperature = 0;
                    FloatChgVolt = 0;
                    BoostChgVolt = 0;
                }
            }

            public class DeviceGyroValue : IResettable
            {
                public short X_axis;
                public short Y_axis;
                public short Z_axis;
                public short Gyro_policy_sel;
                public short Gyro_func_sw;
                public short Gyro_state;

                public DeviceGyroValue()
                {

                }
                public void Reset()
                {
                    X_axis = 0;
                    Y_axis = 0;
                    Z_axis = 0;
                    Gyro_policy_sel = 0;
                    Gyro_func_sw = 0;
                    Gyro_state = 0;
                }
            }
        }
        #endregion
    }
    public interface IResettable
    {
        void Reset();
    }
    public interface IDeepCopy<T>
    {
        T DeepCopy();
    }

    public static class ResetCopyHelpers
    {
        // IResettable이면 Reset 호출, 아니면 new()
        public static void ResetOrRecreate<T>(ref T obj) where T : class, new()
        {
            if (obj is IResettable r) r.Reset();
            else obj = new T();
        }

        // IDeepCopy<T> 우선, ICloneable 차선, 없으면 new()
        public static T DeepCopyOrNew<T>(T obj) where T : class, new()
        {
            if (obj is IDeepCopy<T> dc) return dc.DeepCopy();
            if (obj is ICloneable cl) return (T)cl.Clone();
            return new T();
        }
    }

}
