using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

using LFP_Manager.DataStructure;
using LFP_Manager.Utils;

namespace LFP_Manager.Function
{
    class csMakeDataFunction
    {
        private static DeviceSystemData MakeAlarmTripData(int id, short ndata, DeviceSystemData rSystemData)
        {
            bool[] aData = csUtils.Int16ToBitArray(ndata);
            short bFault = rSystemData.StatusData.protection;
            short bWarning = rSystemData.StatusData.warning;
            int i = 0;

            switch (id)
            {
                case 0:         // Warning
                    if (aData[i++]) bWarning |= (1 << 2);      // Bit 0 : Over voltage warning 
                    else bWarning &= ~(1 << 2);
                    if (aData[i++]) bWarning |= (1 << 4);      // Bit 1 : Cell Over voltage warning 
                    else bWarning &= ~(1 << 4);
                    if (aData[i++]) bWarning |= (1 << 3);      // Bit 2 : Low voltage warning
                    else bWarning &= ~(1 << 3);
                    if (aData[i++]) bWarning |= (1 << 5);      // Bit 3 : Low cell voltage warning
                    else bWarning &= ~(1 << 5);
                    if (aData[i++]) bWarning |= (1 << 6);      // Bit 4 : Charge over current warning
                    else bWarning &= ~(1 << 6);
                    if (aData[i++]) bWarning |= (1 << 7);      // Bit 5 : Discharge over current warning
                    else bWarning &= ~(1 << 7);
                    i++;                                        // 06  Abnormal balancing current
                    i++;                                        // 07  Reserved
                    if ((aData[8]) || (aData[9])) bWarning |= (1 << 0);      // Bit 8 : Charge over temperature warning, Bit 9 : Discharge over temperature warning
                    else bWarning &= ~(1 << 0);
                    i++;                                        // 08   
                    i++;                                        // 09   
                    if ((aData[10]) || (aData[11])) bWarning |= (1 << 1);      // Bit 10 : Charge low temperature warning, Bit 11 : Discharge low temperature warning
                    else bWarning &= ~(1 << 1);
                    i++;                                        // 10   
                    i++;                                        // 11   
                    if (aData[i++]) bWarning |= (1 << 11);       // 12 : Low capacity warning
                    else bWarning &= ~(1 << 11);
                    i++;                                        // 13
                    if (aData[i++]) bWarning |= (1 << 9);       // 14  Cell Voltage Difference Warning
                    else bWarning &= ~(1 << 9);
                    break;
                case 1:         // Status Code 2
                    if (aData[i++]) bFault |= (1 << 2);      // Bit 0 : Over voltage warning 
                    else bFault &= ~(1 << 2);
                    if (aData[i++]) bFault |= (1 << 4);      // Bit 1 : Cell Over voltage warning 
                    else bFault &= ~(1 << 4);
                    if (aData[i++]) bFault |= (1 << 3);      // Bit 2 : Low voltage warning
                    else bFault &= ~(1 << 3);
                    if (aData[i++]) bFault |= (1 << 5);      // Bit 3 : Low cell voltage warning
                    else bFault &= ~(1 << 5);
                    if (aData[i++]) bFault |= (1 << 6);      // Bit 4 : Charge over current warning
                    else bFault &= ~(1 << 6);
                    if (aData[i++]) bFault |= (1 << 7);      // Bit 5 : Discharge over current warning
                    else bFault &= ~(1 << 7);
                    i++;                                        // 06  Abnormal balancing current
                    i++;                                        // 07  Reserved
                    if ((aData[8]) || (aData[9])) bFault |= (1 << 0);      // Bit 8 : Charge over temperature warning, Bit 9 : Discharge over temperature warning
                    else bFault &= ~(1 << 0);
                    i++;                                        // 08   
                    i++;                                        // 09   
                    if ((aData[10]) || (aData[11])) bFault |= (1 << 1);      // Bit 10 : Charge low temperature warning, Bit 11 : Discharge low temperature warning
                    else bFault &= ~(1 << 1);
                    i++;                                        // 10   
                    i++;                                        // 11   
                    i++;                                        // 12   
                    i++;                                        // 13   
                    if (aData[i++]) bFault |= (1 << 9);      // 14  Cell Voltage Difference Warning
                    else bFault &= ~(1 << 9);
                    break;
            }

            rSystemData.StatusData.protection = bFault;
            rSystemData.StatusData.warning = bWarning;

            return rSystemData;
        }

        public static void SetData(int index, double sdata, ref DeviceSystemData aSystemData)
        {
            switch (index)
            {
                case 0: aSystemData.ValueData.voltageOfPack = (short)(sdata / 100); break;          // voltageOfPack
                case 1: aSystemData.ValueData.current = (short)(sdata / 10); break;                 // current
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                case 10:
                case 11:
                case 12:
                case 13:
                case 14:
                case 15:
                case 16: aSystemData.ValueData.CellVoltage[index - 2] = (ushort)(sdata / 1); break;          // CellVoltage14
                case 17: aSystemData.ValueData.CellTemperature[0] = (short)(sdata / 1); break;       // CellTemperature0
                case 18: aSystemData.ValueData.CellTemperature[1] = (short)(sdata / 1); break;       // CellTemperature1
                case 19: aSystemData.ValueData.CellTemperature[2] = (short)(sdata / 1); break;       // CellTemperature2
                case 20: aSystemData.ValueData.CellTemperature[3] = (short)(sdata / 1); break;       // CellTemperature3
                case 21: aSystemData.ValueData.rSOC = (short)(sdata / 1); break;                     // Relatvie State Of Charge
                case 22: aSystemData.ValueData.remainingCapacity = (short)(sdata / 1); break;        // Remaining Capacity
                case 23: aSystemData.ValueData.stateOfHealth = (short)(sdata / 1); break;           // stateOfHealth
                case 24: aSystemData.ValueData.cycleCount = (short)(sdata / 1); break;              // cycleCount

                case 25: aSystemData.AvgData.maxCellVoltage = (short)(sdata / 1); break;        // maxCellVoltage
                case 26: aSystemData.AvgData.minCellVoltage = (short)(sdata / 1); break;        // minCellVoltage
                case 27: aSystemData.AvgData.avgCellVoltage = (short)(sdata / 1); break;        // avgCellVoltage
                case 28: aSystemData.AvgData.diffCellVoltage = (short)(sdata / 1); break;        // diffCellVoltage
                case 29: aSystemData.StatusData.batteryStatus = (short)(sdata / 1); break;       // batteryStatus
                //case 37: aSystemData.StatusData.warning = (short)(sdata / 1); break;       // warning
                case 30: aSystemData = MakeAlarmTripData(0, (short)(sdata / 1), aSystemData); break;       // warning
                //case 38: aSystemData.StatusData.protection = (short)(sdata / 1); break;       // OID-44 protection
                case 31: aSystemData = MakeAlarmTripData(1, (short)(sdata / 1), aSystemData); break;      // OID-44 protection
                case 32: aSystemData.StatusData.status = (short)(sdata / 1); break;       // status
                case 33: aSystemData.StatusData.relayStatus = (short)(sdata / 1); break;       // relayStatus
                case 34: aSystemData.StatusData.cellBallanceStatus = (short)(sdata / 1); break;       // cellBallanceStatus
                case 35: aSystemData.StatusData.cellBalanceValue = (short)(sdata / 1); break;       // cellBalanceValue
                case 36: aSystemData.StatusData.cellBalanceFlag = (short)(sdata / 1); break;       // cellBalanceFlag
                case 37: aSystemData.AvgData.maxCellNum = (short)(sdata / 1); break;       // maxCellNum
                case 38: aSystemData.AvgData.minCellNum = (short)(sdata / 1); break;       // minCellNum
                //case 46: aSystemData.AvgData.maxTemp = (short)(sdata / 1); break;       // maxTemp
                //case 47: aSystemData.AvgData.minTemp = (short)(sdata / 1); break;       // minTemp
                //case 48: aSystemData.AvgData.maxTempNum = (short)(sdata / 1); break;       // maxTempNum
                //case 49: aSystemData.AvgData.minTempNum = (short)(sdata / 1); break;       // minTempNum
            }
        }

        public static void SetSnmpData(int index, object sdata, ref DeviceSystemData aSystemData)
        {
            switch (index)
            {
                case 1: aSystemData.ValueData.voltageOfPack = (short)(Convert.ToDouble(sdata) / 10); break;           // voltageOfPack - 0.01V
                case 2: aSystemData.ValueData.current = (short)(Convert.ToDouble(sdata) - 10000); break;              // current       - 0.1A, Offset: 10000
                case 3: // Cell Voltage #1
                case 4: // Cell Voltage #2
                case 5: // Cell Voltage #3
                case 6: // Cell Voltage #4
                case 7: // Cell Voltage #5
                case 8: // Cell Voltage #6
                case 9: // Cell Voltage #7
                case 10: // Cell Voltage #8
                case 11: // Cell Voltage #9
                case 12: // Cell Voltage #10
                case 13: // Cell Voltage #11
                case 14: // Cell Voltage #12
                case 15: // Cell Voltage #13
                case 16: // Cell Voltage #14
                case 17: aSystemData.ValueData.CellVoltage[index - 3] = (ushort)(Convert.ToDouble(sdata) / 1);
                    csUtils.MakeMaxAvgMinCellVoltage(ref aSystemData, 15);
                    break;          // Cell Voltage #16

                case 19: aSystemData.ValueData.Ext1Temperature = (short)(Convert.ToDouble(sdata) * 10); break;         // Temp of PCB - C
                case 20: aSystemData.ValueData.Ext2Temperature = (short)(Convert.ToDouble(sdata) * 10); break;         // Temp of Ambient - C
                case 21: aSystemData.AvgData.maxTemp = (short)(Convert.ToDouble(sdata) * 10); break;                  // Max. Temp

                case 22: aSystemData.ValueData.remainingCapacity = (short)(Convert.ToDouble(sdata) * 1); break;                  // Remaining Capacity

                case 24: aSystemData.ValueData.stateOfHealth = (short)(Convert.ToDouble(sdata) / 10); break;          // stateOfHealth
                case 25: aSystemData.ValueData.rSOC = (short)(Convert.ToDouble(sdata) / 10); break;                   // Relatvie State Of Charge

                case 26: aSystemData.StatusData.status = (short)(Convert.ToDouble(sdata) / 1); break;                 // Status
                case 27: aSystemData.StatusData.warning = MakeSnmpWarningData((short)Convert.ToDouble(sdata)); break;       // warning
                case 28: aSystemData.StatusData.protection = MakeSnmpTripData((short)Convert.ToDouble(sdata)); break;       // Protection
                case 29:               // FaultAndStatus
                    aSystemData.StatusData.faultAndStatus = (short)(Convert.ToDouble(sdata) / 1);
                    //aSystemData.StatusData.status = (short)(((short)Convert.ToDouble(sdata) >> 8) & 0x0003);
                    MakeAlarm(ref aSystemData);
                    break;
                case 30: aSystemData.ValueData.cycleCount = (short)(Convert.ToDouble(sdata) / 1); break;              // cycleCount

                case 31: // Temperature #1
                case 32: // Temperature #2
                case 33: // Temperature #3
                case 34: // Temperature #4
                    csUtils.MakeMaxAvgMinCellVoltage(ref aSystemData, 4);
                    break;       

                case 37: aSystemData.cellQty = (short)(Convert.ToDouble(sdata) * 1); break;       // Cell Number
                case 38: aSystemData.ValueData.designedCapacity = (short)(Convert.ToDouble(sdata) * 1); break;       // Cell Number
                case 40: aSystemData.ValueData.MaxBattChargeCurr = (short)(Convert.ToDouble(sdata) * 1); break;                  // Max. Charge Current - A
                case 41: aSystemData.ntcQty = (short)(Convert.ToDouble(sdata) * 1); break;       // NTC Number

                case 42: aSystemData.BmsDateTime.year = (short)(Convert.ToDouble(sdata) * 1); break;                  // BMS DateTime - Year
                case 43: aSystemData.BmsDateTime.month = (short)(Convert.ToDouble(sdata) * 1); break;                 // BMS DateTime - Month
                case 44: aSystemData.BmsDateTime.day = (short)(Convert.ToDouble(sdata) * 1); break;                   // BMS DateTime - Day
                case 45: aSystemData.BmsDateTime.hour = (short)(Convert.ToDouble(sdata) * 1); break;                  // BMS DateTime - Hour
                case 46: aSystemData.BmsDateTime.minute = (short)(Convert.ToDouble(sdata) * 1); break;                // BMS DateTime - Minute
                case 47: aSystemData.BmsDateTime.second = (short)(Convert.ToDouble(sdata) * 1);                       // BMS DateTime - Second
                    aSystemData.BmsDateTime.DateTimeStr = string.Format("{0:0000}-{1:00}-{2:00} {3:00}:{4:00}:{5:00}"
                        , aSystemData.BmsDateTime.year
                        , aSystemData.BmsDateTime.month
                        , aSystemData.BmsDateTime.day
                        , aSystemData.BmsDateTime.hour
                        , aSystemData.BmsDateTime.minute
                        , aSystemData.BmsDateTime.second
                        );
                    break;

                case 48: aSystemData.FloatVoltage = (int)Convert.ToDouble(sdata); break;                              // Float Voltage - 0.01V
                case 49: aSystemData.BoostVoltage = (int)Convert.ToDouble(sdata); break;                              // Boost Voltage - 0.01V

                case 50: aSystemData.MinChargeTemp = (int)Convert.ToDouble(sdata); break;                             // Min. Charge Temp - C
                case 51: aSystemData.MaxChargeTemp = (int)Convert.ToDouble(sdata); break;                             // Max. Charge Temp - C

                case 60: aSystemData.Information.ModelName = (string)sdata; break;                                      // Model - string
                case 61: aSystemData.Information.SwProductRev = (string)sdata; break;                                   // BMS Fw Version - string
                case 62: aSystemData.Information.HwSerialNumber = (string)sdata; break;                                 // Pack Serial Number - string
                case 63: aSystemData.Information.VendorName = (string)sdata; break;                                     // Vendor Name - string
                case 64: aSystemData.Information.ProductCode = (string)sdata; break;                                    // Product Code - string
                case 65: aSystemData.Information.MajorMinorRev = (string)sdata; break;                                  // Major Minor Revision - string
                case 66: aSystemData.Information.HwProductRev = (string)sdata; break;                                   // Hardware Product Revision - string
                case 67: aSystemData.Information.ManufacturingDate = (string)sdata; break;                              // Manufacturing Date - string

                default:
                    break;
            }
        }
        public static void MakeAlarm(ref DeviceSystemData rSystemData)
        {
            if (((rSystemData.StatusData.faultAndStatus >> 14) & 0x0001) == 0x0001)
            {
                rSystemData.StatusData.batteryStatus = 4;       // Anti-theft Gyroscope
            }
            else if (((rSystemData.StatusData.faultAndStatus >> 15) & 0x0001) == 0x0001)
            {
                rSystemData.StatusData.batteryStatus = 5;       // Anti-theft Comm.
            }
            else if (rSystemData.StatusData.protection != 0x0000)
            {
                rSystemData.StatusData.batteryStatus = 2;
            }
            else if (rSystemData.StatusData.warning != 0x0000)
            {
                rSystemData.StatusData.batteryStatus = 1;
            }
            else
            {
                rSystemData.StatusData.batteryStatus = 0;
            }
        }
        public static short MakeSnmpTripData(short rdata)
        {
            short result = 0;
            bool[] bAlarm = csUtils.Int16ToBitArray(rdata);

            if (bAlarm[0] == true) result |= (short)(1 << 4);       // 0x0001：Cell OV
            if (bAlarm[1] == true) result |= (short)(1 << 2);       // 0x0002：Pack OV
            if (bAlarm[2] == true) result |= (short)(1 << 5);       // 0x0004：Cell UV
            if (bAlarm[3] == true) result |= (short)(1 << 3);       // 0x0008：Pack UV

            if (bAlarm[4] == true) result |= (short)(1 << 6);       // 0x0010：Charging OC1
            if (bAlarm[5] == true) result |= (short)(1 << 6);       // 0x0020：Charging OC2
            if (bAlarm[6] == true) result |= (short)(1 << 7);       // 0x0010：Discharging OC1
            if (bAlarm[7] == true) result |= (short)(1 << 7);       // 0x0020：Discharging OC2

            if (bAlarm[8] == true) result |= (short)(1 << 9);       // 0x0200：Short Circuit Protection

            if (bAlarm[9] == true) result |= (short)(1 << 0);       // 0x0080: Charging Over Tempratuer
            if (bAlarm[10] == true) result |= (short)(1 << 1);       // 0x0080: Charging Under Tempratuer
            if (bAlarm[11] == true) result |= (short)(1 << 0);      // 0x0040: Discharging Over Tempratuer
            if (bAlarm[12] == true) result |= (short)(1 << 1);      // 0x0040: Discharging Under Tempratuer

            return result;
        }
        public static short MakeSnmpWarningData(short rdata)
        {
            short result = 0;
            bool[] bAlarm = csUtils.Int16ToBitArray(rdata);

            if (bAlarm[0] == true) result |= (short)(1 << 4);       // 0x0001：Cell OV
            if (bAlarm[1] == true) result |= (short)(1 << 5);       // 0x0002：Cell UV
            if (bAlarm[2] == true) result |= (short)(1 << 2);       // 0x0004：Pack OV
            if (bAlarm[3] == true) result |= (short)(1 << 3);       // 0x0008：Pack UV

            if (bAlarm[4] == true) result |= (short)(1 << 6);       // 0x0010：Charging OC
            if (bAlarm[5] == true) result |= (short)(1 << 7);       // 0x0020：Discharging OC

            if (bAlarm[6] == true) result |= (short)(1 << 8);       // 0x0040：ENV OT
            if (bAlarm[7] == true) result |= (short)(1 << 9);       // 0x0080：ENV UT

            if (bAlarm[8] == true) result |= (short)(1 << 0);       // 0x0100: Charging Over Temprature
            if (bAlarm[9] == true) result |= (short)(1 << 1);       // 0x0200: Charging Under Temprature
            if (bAlarm[10] == true) result |= (short)(1 << 0);      // 0x0400: Discharging Over Temprature
            if (bAlarm[11] == true) result |= (short)(1 << 1);      // 0x0800: Discharging Under Temprature

            if (bAlarm[12] == true) result |= (short)(1 << 11);       // 0x1000：SOC Low

            if (bAlarm[13] == true) result |= (short)(1 << 13);       // 0x2000：Diff Volt
            if (bAlarm[14] == true) result |= (short)(1 << 14);       // 0x4000：CB Off

            return result;
        }
    }
}
