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
    {
        //0x0001: Over voltage warning
        //0x0002: Cell Over voltage warning
        //0x0004: Low voltage warning
        //0x0008: Low cell voltage warning
        //0x0010: Charge over current warning
        //0x0020: Discharge over current warning
        //0x0040: ambient temp warning
        //0x0080: MOSFET over temp warning
        //0x0100: Charge over temperature warning
        //0x0200: Discharge over temperature warning
        //0x0400: Charge low temperature warning 
        //0x0800: Discharge low temperature warning
        //0x1000: Low capacity warning
        //0x2000: Low SOH warning

        private static ushort MakeAlarmTripData(int id, short ndata, CsDeviceData.DeviceModuleData mData)
        {
            bool[] aData = csUtils.Int16ToBitArray(ndata);
            int bFault = mData.StatusData.protect;
            int bWarning = mData.StatusData.warning;
            int i = 0;

            if (id == 0)
            {
                // Warning
                if (aData[i++]) bWarning |= (1 << 1);      // Bit 0 : Cell Over voltage warning --> Bit 1
                else bWarning &= ~(1 << 1);
                if (aData[i++]) bWarning |= (1 << 3);      // Bit 1 : Cell Under voltage warning --> Bit 3
                else bWarning &= ~(1 << 3);
                if (aData[i++]) bWarning |= (1 << 0);      // Bit 2 : Pack Over voltage warning --> Bit 0
                else bWarning &= ~(1 << 0);
                if (aData[i++]) bWarning |= (1 << 2);      // Bit 3 : Pack Under voltage warning --> Bit 2
                else bWarning &= ~(1 << 2);
                if (aData[i++]) bWarning |= (1 << 4);      // Bit 4 : Charge over current warning --> Bit 4
                else bWarning &= ~(1 << 4);
                if (aData[i++]) bWarning |= (1 << 5);      // Bit 5 : Discharge over current warning --> Bit 5
                else bWarning &= ~(1 << 5);
                if (aData[i++]) bWarning |= (1 << 6);      // Bit 6 : Env over temperature warning --> Bit 6
                else bWarning &= ~(1 << 6);
                //if (aData[i++]) bWarning |= (1 << 7);      // Bit 7 : Env under temperature warning --> Bit 7
                //else bWarning &= ~(1 << 7);
                i++;                                        // 07  Reserved
                if (aData[i++]) bWarning |= (1 << 8);      // Bit 8 : Charge over temperature warning --> Bit 8
                else bWarning &= ~(1 << 8);
                if (aData[i++]) bWarning |= (1 << 10);     // Bit 9 : Charge under temperature warning --> Bit 10
                else bWarning &= ~(1 << 10);
                if (aData[i++]) bWarning |= (1 << 9);      // Bit 10 : Discharge over temperature warning --> Bit 9
                else bWarning &= ~(1 << 9);
                if (aData[i++]) bWarning |= (1 << 11);     // Bit 11 : Discharge under temperature warning --> Bit 11
                else bWarning &= ~(1 << 11);

                if (aData[i++]) bWarning |= (1 << 12);      // Bit 12 : Low capacity warning --> Bit 12
                else bWarning &= ~(1 << 12);
                i++;                                        // 13

                return (ushort)bWarning;
            }
            else
            {
                // Protection
                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);
                return (ushort)bFault;
            }
        }

        public static void SetSnmpData(int index, object sdata, ref CsDeviceData.DeviceModuleData aModuleData)
        {
            switch (index)
            {
                case 1: aModuleData.ValueData.voltage = (short)(Convert.ToDouble(sdata) / 10); break;           // voltageOfPack - 0.01V
                case 2: aModuleData.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:
                    aModuleData.ValueData.CellVoltage[index - 3] = (ushort)(Convert.ToDouble(sdata) / 1);
                    csSerialCommFunction.MakeMaxAvgMinCellVoltage(ref aModuleData);
                    break;          // Cell Voltage #16

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

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

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

                case 26: aModuleData.StatusData.status = (ushort)(Convert.ToDouble(sdata) / 1); break;                 // Status
                case 27: aModuleData.StatusData.warning = (ushort)CsAlarmDefine.DevWarningToGui(Convert.ToInt32(sdata)); break;         // warning
                case 28: aModuleData.StatusData.protect = (ushort)CsAlarmDefine.DevProtectToGui(Convert.ToInt32(sdata)); break;         // protection
                case 29:               // FaultAndStatus
                    aModuleData.StatusData.faultAndStatus = (ushort)(Convert.ToDouble(sdata) / 1);
                    //aModuleData.StatusData.status = (short)(((short)Convert.ToDouble(sdata) >> 8) & 0x0003);
                    MakeAlarm(ref aModuleData);
                    break;
                case 30: aModuleData.ValueData.cycleCount = (ushort)(Convert.ToDouble(sdata) / 1); break;              // cycleCount

                case 31: // Temperature #1
                case 32: // Temperature #2
                case 33: // Temperature #3
                case 34: aModuleData.ValueData.CellTemperature[index - 31] = (short)(Convert.ToDouble(sdata) * 10); break;       // Temperature #4

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

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

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

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

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

                default:
                    break;
            }
        }
        public static void MakeAlarm(ref CsDeviceData.DeviceModuleData aModuleData)
        {
            if (((aModuleData.StatusData.faultAndStatus >> 14) & 0x0001) == 0x0001)
            {
                aModuleData.StatusData.batteryStatus = 4;       // Anti-theft Gyroscope
            }
            else if (((aModuleData.StatusData.faultAndStatus >> 15) & 0x0001) == 0x0001)
            {
                aModuleData.StatusData.batteryStatus = 5;       // Anti-theft Comm.
            }
            else if (aModuleData.StatusData.protect != 0x0000)
            {
                aModuleData.StatusData.batteryStatus = 2;
            }
            else if (aModuleData.StatusData.warning != 0x0000)
            {
                aModuleData.StatusData.batteryStatus = 1;
            }
            else
            {
                aModuleData.StatusData.batteryStatus = 0;
            }
        }
    }
}
