import sys
import numpy as np
import pandas as pd
import string
import os
from pandas import Series
from matplotlib import pyplot as plt
from pandas.core.frame import DataFrame
from pandas.core.indexes.base import Index
from LIB.BACKEND import DBManager
import datetime
import time
import string


class SamplingSafty:
    def __init__(self):
        pass
    def main(sn,param,bms_info,df_Diag_Ram_in):
        df_Diag_Ram_Update_inside=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
        df_Diag_Ram_Update_inside=df_Diag_Ram_Update_inside.append(df_Diag_Ram_in)
        global QuitErrCount 
        FltInfo=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
        VolStarkCount=[0 for i in range(param.CellVoltNums)]
        VolCount=[0 for i in range(param.CellVoltNums)]
        QuitErrCount=[0 for i in range(param.FaultCount)]

        #--------------该电池的所有当前故障-------------



        for i in range(0,len(bms_info)):
            if i==0:
                bms_infoP=bms_info.loc[i]
            elif len(bms_info)>=1:
                    bms_infoP=bms_info.loc[i-1]
            df_Diag_Ram,VolStarkCount,VolCount=SamplingSafty.VoltSamplingDiag(sn,bms_info.loc[i],bms_infoP,param,VolStarkCount,VolCount,df_Diag_Ram_Update_inside)   
            df_Diag_Ram=SamplingSafty.TempSamplingDiag(sn,bms_info.loc[i],bms_infoP,param,df_Diag_Ram)
                # FltInfo=SamplingSafty.CrntSamplingDiag(sn,bms_info.loc[i],FltInfo,param)
        return df_Diag_Ram



    def VoltSamplingDiag(sn,bms_infoN,bms_infoP,param,VolStarkCount,VolCount,df_Diag_Ram):
        InVMaxBatNo=[]
        InVMinBatNo=[]
        StackVolNo=[]
        OutlierVolNo=[]
        maxVolt=0
        minVolt=5
        ErrorFlg=0
        TotalVol=0
        #——————————————————————取最高最低电压————————————————————————————————
        for t in range(0,param.CellVoltNums):
            BatNo=['单体电压'+str(t+1)]
            maxVol=max(maxVolt,float(bms_infoN[BatNo])/1000)
            if maxVol>maxVolt:
                MaxBatNo=t+1
                maxVolt=maxVol
            if float(bms_infoN[BatNo])/1000>param.CellOVlmt:
                InVMaxBatNo.append(t+1)  
            else:
                pass
            minVol=min(minVolt,float(bms_infoN[BatNo])/1000)
            if minVol<minVolt:
                MinBatNo=t+1
                minVolt=minVol
            if float(bms_infoN[BatNo])/1000<param.CellUVlmt:
                InVMinBatNo.append(t+1)
            else:
                pass
            TotalVol=TotalVol+float(bms_infoN[BatNo]/1000)
        AvgVol=(TotalVol-maxVol-minVol)/float(param.CellVoltNums-2)


        #—————————————————————————————电压无效和断线判断———————————————————————
        if maxVol>param.CellOVlmt:
            if minVol<param.CellUVlmt:
                QuitErrCount[10]=0
                if not 10 in df_Diag_Ram['code'].values.tolist():#如果故障发生当前故障中没有该故障，则压入该故障
                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,10,3,'电池电压采样断线,最高电压为{:.2f}V,电池编号为{}，最低电压为{:.2f}V,电池编号为{}'.format(maxVol,MaxBatNo,minVol,MinBatNo),'返厂维修']
                    ErrorFlg=1            
                else:#如果故障发生当前故障中有该故障，则不进行操作
                    pass 
            else:#如果没有故障，并且当前故障表中有该故障，则判断故障是否结束
                QuitErrCount[50]=0
                if 10 in df_Diag_Ram['code'].values.tolist():
                    QuitErrCount[10]=QuitErrCount[10]+1
                    if QuitErrCount[10]>6:
                        end_time=datetime.datetime.now()
                        end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                        df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==10].index,['end_time']]=end_time
                    else:
                        pass
                else:
                    pass
                if not 50 in df_Diag_Ram['code'].values.tolist():
                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,50,3,str(InVMaxBatNo)+'号电压大于{:.2f}V,采样无效'.format(param.CellOVlmt),'返厂维修']
                    
                    ErrorFlg=1
                else:
                    pass
        elif minVol<param.CellUVlmt:
            QuitErrCount[50]=0
            if not 50 in df_Diag_Ram['code'].values.tolist():
                df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,50,3,str(InVMinBatNo)+'号电压小于{:.2f}V,采样无效'.format(param.CellUVlmt),'返厂维修']
                
                ErrorFlg=1
            else:
                pass
        else:
            if 50 in df_Diag_Ram['code'].values.tolist():
                QuitErrCount[50]=QuitErrCount[50]+1
                if QuitErrCount[50]>6:
                    end_time=datetime.datetime.now()
                    end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                    df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==50].index,['end_time']]=end_time
                    
                else:
                    pass
            else:
                pass
       #——————————————————————————————————电压卡滞判断—————————————————————————
        if ErrorFlg==0:
            for t in range(0,param.CellVoltNums):
                BatNo=['单体电压'+str(t+1)]
                AvgVolGap=abs((float(bms_infoN[BatNo]/1000))-AvgVol)
                if AvgVolGap>param.AvgVolGap and float(bms_infoN[BatNo]/1000)>param.BLVol and float(bms_infoN[BatNo]/1000)<param.CellFullChrgVolt and not 51 in df_Diag_Ram['code']:
                    if abs(bms_infoN['总电流[A]'])<2:
                        VolCount[t]=VolCount[t]+1
                    else:
                        VolCount[t]=0
                    if VolCount[t]>10:
                        OutlierVolNo.append(t+1)
                    else:
                        pass
                if abs(float(bms_infoN[BatNo])-float(bms_infoP[BatNo]))<=0.0001 and not 52 in df_Diag_Ram['code']:
                    if abs(float(bms_infoN['总电流[A]']))>=10 and not 'PK504' in sn:
                        VolStarkCount[t]=VolStarkCount[t]+1
                    elif abs(float(bms_infoN['总电流[A]']))>=15 and 'PK504' in sn:
                        VolStarkCount[t]=VolStarkCount[t]+1
                else:
                    VolStarkCount[t]=0
                if VolStarkCount[t]>10:
                    StackVolNo.append(t+1)
                else:
                    pass
            if len(OutlierVolNo)>0:
                QuitErrCount[51]=0
                if not 51 in df_Diag_Ram['code'].values.tolist():#如果故障发生当前故障中没有该故障，则压入该故障
                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,51,2,str(OutlierVolNo)+'号电池电压离群','技术介入诊断']
                    
                    ErrorFlg=1            
                else:#如果故障发生当前故障中有该故障，则不进行操作
                    pass
            else:
                if 51 in df_Diag_Ram['code'].values.tolist():
                    QuitErrCount[51]=QuitErrCount[51]+1
                    if QuitErrCount[51]>6:
                        end_time=datetime.datetime.now()
                        end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                        df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==51].index,['end_time']]=end_time
                        
                    else:
                        pass
                else:
                    pass
            if len(StackVolNo)>0:
                QuitErrCount[52]=0
                if not 52 in df_Diag_Ram['code'].values.tolist():#如果故障发生当前故障中没有该故障，则压入该故障
                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,52,2,str(StackVolNo)+'号电池电压卡滞','技术介入诊断']
                    
                    ErrorFlg=1            
                else:#如果故障发生当前故障中有该故障，则不进行操作
                    pass
            else:
                if 51 in df_Diag_Ram['code'].values.tolist():
                    QuitErrCount[52]=QuitErrCount[52]+1
                    if QuitErrCount[52]>6:
                        end_time=datetime.datetime.now()
                        end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                        df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==52].index,['end_time']]=end_time
                        
                    else:
                        pass
                else:
                    pass
        return df_Diag_Ram,VolStarkCount,VolCount
    def TempSamplingDiag(sn,bms_infoN,bms_infoP,param,df_Diag_Ram):
        #——————————————————————————————————CellTemp————————————————————————————————————
        InVMaxBatNo=[]
        InVMinBatNo=[]
        OutlierTempNo=[]
        maxCellTempt=-40
        minCellTempt=55
        ErrorFlg=0
        TotalCellTemp=0
        for t in range(0,param.CellTempNums):
            BatNo=['单体温度'+str(t+1)]
            maxCellTemp=max(maxCellTempt,float(bms_infoN[BatNo]))
            if maxCellTemp>maxCellTempt:
                MaxBatNo=t+1
                maxCellTempt=maxCellTemp
            if float(bms_infoN[BatNo])>param.PackOTlmt:
                InVMaxBatNo.append(t+1)                   
            else:
                pass
            minCellTemp=min(minCellTempt,float(bms_infoN[BatNo]))
            if minCellTemp<minCellTempt:
                MinBatNo=t+1
                minCellTempt=minCellTemp
            if float(bms_infoN[BatNo])<param.PackUTlmt:
                InVMinBatNo.append(t+1)                   
            else:
                pass
            TotalCellTemp=TotalCellTemp+float(bms_infoN[BatNo])
        if param.CellTempNums>2:
            AvgCellTemp=(TotalCellTemp-maxCellTemp-minCellTemp)/float(param.CellTempNums-2)
        else:
            AvgCellTemp=TotalCellTemp/float(param.CellTempNums)
#——————————————————————————————————温度无效，离群和断线判断——————————————————————————————————
        if maxCellTemp>param.PackOTlmt:
            if minCellTemp<param.PackUTlmt:
                QuitErrCount[53]=0
                if not 53 in df_Diag_Ram['code'].values.tolist():#如果故障发生当前故障中没有该故障，则压入该故障
                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,53,3,'电池温度采样断线,最高温度为{}℃,电池编号为{}，最低温度为{}℃,电池编号为{}'.format(maxCellTemp,MaxBatNo,minCellTemp,MinBatNo),'返厂维修']
                    ErrorFlg=1            
                else:#如果故障发生当前故障中有该故障，则不进行操作
                    pass 
            else:#如果没有故障，并且当前故障表中有该故障，则判断故障是否结束
                QuitErrCount[2]=0
                if 53 in df_Diag_Ram['code'].values.tolist():
                    QuitErrCount[53]=QuitErrCount[53]+1
                    if QuitErrCount[53]>6:
                        end_time=datetime.datetime.now()
                        end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                        df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==53].index,['end_time']]=end_time
                        
                    else:
                        pass
                else:
                    pass
                if not 2 in df_Diag_Ram['code'].values.tolist():
                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,2,3,str(InVMaxBatNo)+'号温度大于{}℃,采样无效'.format(param.PackOTlmt),'返厂维修']
                    
                    ErrorFlg=1
                else:
                    pass
        elif minCellTemp<param.PackUTlmt:
            QuitErrCount[2]=0
            if not 2 in df_Diag_Ram['code'].values.tolist():
                df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,2,3,str(InVMinBatNo)+'号温度小于{}℃,采样无效'.format(param.PackUTlmt),'返厂维修']
                
                ErrorFlg=1
            else:
                pass
        else:
            if 2 in df_Diag_Ram['code'].values.tolist():
                QuitErrCount[2]=QuitErrCount[2]+1
                if QuitErrCount[2]>6:
                    end_time=datetime.datetime.now()
                    end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                    df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==2].index,['end_time']]=end_time
                    
                else:
                    pass
            else:
                pass
        if ErrorFlg==0:
            if param.CellTempNums>2:            
                for t in range(0,param.CellTempNums):
                    BatNo=['单体温度'+str(t+1)]
                    AvgCellTempGap=abs((float(bms_infoN[BatNo]))-AvgCellTemp)
                    if AvgCellTempGap>param.AvgCellTempGap and float(bms_infoN[BatNo])>param.PackUTlmt and float(bms_infoN[BatNo])<param.PackOTlmt and not 8 in df_Diag_Ram['code']:
                        OutlierTempNo.append(t+1)
            else:
                AvgCellTempGap=maxCellTemp-minCellTemp
                if AvgCellTempGap>param.AvgCellTempGap and minCellTemp>param.PackUTlmt and maxCellTemp<param.PackOTlmt and not 8 in df_Diag_Ram['code']:
                    OutlierTempNo=[1,2]
            if len(OutlierTempNo)>0:
                QuitErrCount[8]=0
                if not 8 in df_Diag_Ram['code'].values.tolist():#如果故障发生当前故障中没有该故障，则压入该故障
                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,8,2,str(OutlierTempNo)+'号电池异常温度离群','技术介入诊断']
                    
                    ErrorFlg=1            
                else:#如果故障发生当前故障中有该故障，则不进行操作
                    pass
            else:
                if 8 in df_Diag_Ram['code'].values.tolist():
                    QuitErrCount[8]=QuitErrCount[8]+1
                    if QuitErrCount[8]>6:
                        end_time=datetime.datetime.now()
                        end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                        df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==8].index,['end_time']]=end_time
                        
                        #df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['sn']==sn and df_Diag_Ram['code']==8].index,['end_time']]=end_time
                    else:
                        pass
                else:
                    pass
        #——————————————————————————————————OtherTemp————————————————————————————————————
        InVMaxOtherTempBatNo=[]
        InVMinOtherTempBatNo=[]
        OutlierOtherTempNo=[]
        maxOtherTempt=-40
        minOtherTempt=91
        ErrorFlg=0
        TotalOtherTemp=0
        MaxOtherBatNo=0
        MinOtherBatNo=0
        if param.OtherTempNums>0:
            for t in range(0,param.OtherTempNums):
                BatNo=['其他温度'+str(t+1)]
                maxOtherTemp=max(maxOtherTempt,float(bms_infoN[BatNo]))
                if maxOtherTemp>maxOtherTempt:
                    MaxOtherBatNo=t+1
                    maxOtherTempt=maxOtherTemp
                if float(bms_infoN[BatNo])>param.OtherOTlmt:
                    InVMaxOtherTempBatNo.append(t+1)                   
                else:
                    pass
                minOtherTemp=min(minOtherTempt,float(bms_infoN[BatNo]))
                if minOtherTemp<minOtherTempt:
                    MinOtherBatNo=t+1
                    minOtherTempt=minOtherTemp
                if float(bms_infoN[BatNo])<param.OtherUTlmt:
                    InVMinOtherTempBatNo.append(t+1)                   
                else:
                    pass
                TotalOtherTemp=TotalOtherTemp+float(bms_infoN[BatNo])
            if param.OtherTempNums>2:
                AvgOtherTemp=(TotalOtherTemp-maxOtherTemp-minOtherTemp)/float(param.OtherTempNums-2)
            else:
                AvgOtherTemp=TotalOtherTemp/float(param.OtherTempNums)
    #——————————————————————————————————其他温度无效，离群和断线判断——————————————————————————————————
            if maxOtherTemp>param.OtherOTlmt:
                if minOtherTemp<param.OtherUTlmt:
                    QuitErrCount[54]=0
                    if not 54 in df_Diag_Ram['code'].values.tolist():#如果故障发生当前故障中没有该故障，则压入该故障
                        df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,54,3,'其他温度采样断线,最高温度为{}℃,传感器编号为{}，最低温度为{}℃,传感器编号为{}'.format(maxOtherTemp,MaxOtherBatNo,minOtherTemp,MinOtherBatNo),'返厂维修']
                        
                        ErrorFlg=1            
                    else:#如果故障发生当前故障中有该故障，则不进行操作
                        pass 
                else:#如果没有故障，并且当前故障表中有该故障，则判断故障是否结束
                    QuitErrCount[55]=0
                    if 54 in df_Diag_Ram['code'].values.tolist():
                        QuitErrCount[54]=QuitErrCount[54]+1
                        if QuitErrCount[54]>6:
                            end_time=datetime.datetime.now()
                            end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                            df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==54].index,['end_time']]=end_time
                           
                        else:
                            pass
                    else:
                        pass
                    if not 55 in df_Diag_Ram['code'].values.tolist():
                        df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,55,3,str(InVMaxOtherTempBatNo)+'号传感器温度大于{}℃,采样无效'.format(param.OtherOTlmt),'联系用户核实电池情况，并返厂维修']
                        
                        ErrorFlg=1
                    else:
                        pass
            elif minOtherTemp<param.OtherUTlmt:
                QuitErrCount[55]=0
                if not 55 in df_Diag_Ram['code'].values.tolist():
                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,55,3,str(InVMinOtherTempBatNo)+'号传感器温度小于{}℃,采样无效'.format(param.OtherUTlmt),'返厂维修']
                    
                    ErrorFlg=1
                else:
                    pass
            else:
                if 55 in df_Diag_Ram['code'].values.tolist():
                    QuitErrCount[55]=QuitErrCount[55]+1
                    if QuitErrCount[55]>6:
                        end_time=datetime.datetime.now()
                        end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                        df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==55].index,['end_time']]=end_time
                        
                    else:
                        pass
                else:
                    pass
            if ErrorFlg==0 and param.OtherTempNums>0:
                if param.OtherTempNums>2:            
                    for t in range(0,param.OtherTempNums):
                        BatNo=['其他温度'+str(t+1)]
                        AvgOtherTempGap=abs((float(bms_infoN[BatNo]))-AvgOtherTemp)
                        if AvgOtherTempGap>param.AvgOtherTempGap and float(bms_infoN[BatNo])>param.OtherUTlmt and float(bms_infoN[BatNo])<param.OtherOTlmt and not 8 in df_Diag_Ram['code']:
                            OutlierOtherTempNo.append(t+1)
                else:
                    AvgOtherTempGap=maxOtherTemp-minOtherTemp
                    if AvgOtherTempGap>param.AvgOtherTempGap and minOtherTemp>param.OtherUTlmt and maxOtherTemp<param.OtherOTlmt and not 8 in df_Diag_Ram['code']:
                        OutlierOtherTempNo=[1,2]
                if len(OutlierOtherTempNo)>0:
                    QuitErrCount[56]=0
                    if not 56 in df_Diag_Ram['code'].values.tolist():#如果故障发生当前故障中没有该故障，则压入该故障
                        df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,56,2,str(OutlierOtherTempNo)+'号传感器温度异常离群','技术介入诊断']
                        
                        ErrorFlg=1            
                    else:#如果故障发生当前故障中有该故障，则不进行操作
                        pass
                else:
                    if 56 in df_Diag_Ram['code'].values.tolist():
                            QuitErrCount[56]=QuitErrCount[56]+1
                            if QuitErrCount[56]>6:
                                end_time=datetime.datetime.now()
                                end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                                df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==56].index,['end_time']]=end_time
                                
            if (maxOtherTemp-maxCellTemp)>param.AvgOtherTempGap and  maxOtherTemp<param.OtherOTlmt and maxCellTemp<param.PackOTlmt:
                QuitErrCount[56]=0
                if not 56 in df_Diag_Ram['code'].values.tolist():
                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,56,2,str(OutlierOtherTempNo)+'号传感器温度异常离群','技术立即介入诊断']
                    
                    ErrorFlg=1
            else:
                if 56 in df_Diag_Ram['code'].values.tolist():
                        QuitErrCount[56]=QuitErrCount[56]+1
                        if QuitErrCount[56]>6:
                            end_time=datetime.datetime.now()
                            end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                            df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==56].index,['end_time']]=end_time
                            
            if (maxCellTemp-maxOtherTemp)>param.AvgOtherTempGap and  maxOtherTemp<param.OtherOTlmt and maxCellTemp<param.PackOTlmt and not 8 in df_Diag_Ram['code']:
                QuitErrCount[8]=0
                if not 8 in df_Diag_Ram['code'].values.tolist():
                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_infoN['时间戳'],'0000-00-00 00:00:00',sn,8,2,str(OutlierTempNo)+'号电芯温度异常离群','技术立即介入诊断']
                    
                    ErrorFlg=1
            else:
                if 8 in df_Diag_Ram['code'].values.tolist():
                        QuitErrCount[8]=QuitErrCount[8]+1
                        if QuitErrCount[8]>6:
                            end_time=datetime.datetime.now()
                            end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
                            df_Diag_Ram.loc[df_Diag_Ram[df_Diag_Ram['code']==8].index,['end_time']]=end_time                   
        return df_Diag_Ram
   