package com.njcn.utils;


import com.njcn.pojo.data.PqsComasses;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.net.UnknownHostException;
import java.util.List;

/**
 * @author yexb
 * @version 1.0
 * @Date 2018/8/23 16:02
 */
//因素集U={频率偏差、电网谐波、电压波动与闪变、电压偏差、电压暂降、三相不平衡}
//评判级分为5个等级，即：Q = {很差，较差，合格，良好，优质}
        /*	   电压偏差         电网谐波          三相不平衡     频率偏差          电压波动       电压暂降
               (偏差绝对值/%)   (电压总谐波畸变率%)   (不平衡度/%)   (偏差绝对值/Hz)   (短时闪变值)   (暂降幅度%)
        第1 级   10～             6..0～            4.0～          0.3～             0.8～          90～
        第2 级   7～10            4.0～6.0          2..0～4.0      0.2～0.3          0.6～0.8       40～90
        第3 级   4～7             2.0～4.0          1.0～2.0       0.1～0.2          0.4～0.6       20～40
        第4 级   2～4             1.0～2.0          0.5～1.0       0.05～0.1         0.2～0.4       10～20
        第5 级   0～2             0～1.0            0～0.5         0～0.05           0～0.2         0～10
        */
@Component
public class ComAssesUtil {
    // 日志记录
    private static final Logger logger = LoggerFactory.getLogger(ComAssesUtil.class);
    private static final int ST_QT_NUM = 6;//系统评价指标数目
    private static final int GRADE_NUM = 5;//指标分级数目
    private static final int METHOD_NUM = 5;//评估方法数
    private static final int METHOD_IDX1 = 0;//层次分析法
    private static final int METHOD_IDX2 = 1;//优序图法
    private static final int METHOD_IDX3 = 2;//专家打分法
    private static final int METHOD_IDX4 = 3;//熵权法
    private static final int METHOD_IDX5 = 4;//变异系数法

    private static final int IDX_FREQ = 0;//频率
    private static final int IDX_UTHD = 1;//电压畸变率
    private static final int IDX_FLICK = 2;//电压闪变
    private static final int IDX_UDEV = 3;//电压偏差
    private static final int IDX_EVT = 4;//电压暂降
    private static final int IDX_UBPH = 5;//电压不平衡

    private static final int MAX_DATA_TYPE = 5;//5种统计数据
    private static final int MAX_DATA_NUM = 1440 * 31;//最大统计数据个数
    private static final int MAX_EVT_NUM = 1000;//最大暂态事件个数

    //3种主观赋权法直接摘录文档中计算好的最终评估权重
    //层次分析法
    private float W1[] = {0.38f, 0.22f, 0.13f, 0.12f, 0.08f, 0.07f};
    //优序图法
    private float W2[] = {0.28f, 0.24f, 0.19f, 0.14f, 0.10f, 0.05f};
    //专家打分法
    private float W3[] = {0.39f, 0.26f, 0.12f, 0.09f, 0.07f, 0.07f};

    //数据评估矩阵
    private float Assess[][];
    //权重矩阵
    private float Weight[][];

    float A[];

    // 综合评估程序,返回值为评估分
    public float GetComAsses(float in_data[][]) {
        float fResult = 0.0f;//返回最终评分
        try{
            //实例化所有参数
            Assess = new float[ST_QT_NUM][GRADE_NUM];
            Weight = new float[ST_QT_NUM][METHOD_NUM];
            A = new float[ST_QT_NUM];
            float B[] = new float[GRADE_NUM];

            int i, j;
            float sum1, sum2;
            Assess = in_data;//给评估矩阵赋值，此值直接从相应的数据库中获取

            //W1-W3为主观赋权，直接从文档上摘录赋权
            for (i = 0; i < ST_QT_NUM; i++) {
                Weight[i][METHOD_IDX1] = W1[i];
                Weight[i][METHOD_IDX2] = W2[i];
                Weight[i][METHOD_IDX3] = W3[i];
            }
            //熵权法求W4
            if (getSqf()) {
                //变异系数法求W5
                if (getBysxf()) {
                    //G和F得出综合权重A
                    if (getZhqzf()) {
                        //A[0] = 0.28;A[1] = 0.23;A[2] = 0.13;A[3] = 0.16;A[4] = 0.08;A[5] = 0.12;
                        for (i = 0; i < GRADE_NUM; i++) {
                            B[i] = 0;
                            for (j = 0; j < ST_QT_NUM; j++) {
                                B[i] += A[j] * Assess[j][i];
                            }
                        }
                        sum1 = 0;
                        sum2 = 0;
                        for (i = 0; i < GRADE_NUM; i++) {
                            sum1 += (i + 1) * B[i];
                            sum2 += B[i];
                        }
                        fResult = sum1 / sum2;
                    }
                }
            }
            fResult =  FloatUtils.get2Float(fResult);
        }catch (Exception e){
           //Todo
        }
        return fResult;
    }

    /**
     * 大批量的监测点的综合得分获取平均值
     * @param pqsComasses 批量数据
     */
    public float getAllComAss(List<PqsComasses> pqsComasses) {
        float allData=0f;
        for(int i=0;i<pqsComasses.size();i++){
            PqsComasses tempPqs=pqsComasses.get(i);
            //组合二维数组
            float f1[][]={{tempPqs.getFreqDev1(),tempPqs.getFreqDev2(),tempPqs.getFreqDev3(),tempPqs.getFreqDev4(),tempPqs.getFreqDev5()}
            ,{tempPqs.getVThd1(),tempPqs.getVThd2(),tempPqs.getVThd3(),tempPqs.getVThd4(),tempPqs.getVThd5(),}
            ,{tempPqs.getDataPst1(),tempPqs.getDataPst2(),tempPqs.getDataPst3(),tempPqs.getDataPst4(),tempPqs.getDataPst5()}
            ,{tempPqs.getVuDev1(),tempPqs.getVuDev2(),tempPqs.getVuDev3(),tempPqs.getVuDev4(),tempPqs.getVuDev5(),}
            ,{tempPqs.getVUnbalance1(),tempPqs.getVUnbalance2(),tempPqs.getVUnbalance3(),tempPqs.getVUnbalance4(),tempPqs.getVUnbalance5(),}
            ,{tempPqs.getEvent1(),tempPqs.getEvent2(),tempPqs.getEvent3(),tempPqs.getEvent4(),tempPqs.getEvent5(),}};
            //获取该值返回的数据
            float temp=GetComAsses(f1);
            allData+=temp;
        }
        float aveData=allData/pqsComasses.size();
        return FloatUtils.get2Float(aveData);
    }



    //熵权法求权重
    private boolean getSqf() {
        boolean blSqfFlag = true;
        try {
            int i, j;
            float k, m;
            float sum[] = new float[ST_QT_NUM];
            float e[] = new float[ST_QT_NUM];
            float d[] = new float[ST_QT_NUM];

            //计算第j个指标的熵值e(j)
            m = GRADE_NUM;
            //k = (1/1.6094379124341);
            k = (float) (1 / ((Math.log(m)) / Math.log(2.7183)));
            for (i = 0; i < ST_QT_NUM; i++) {
                sum[i] = 0;
                for (j = 0; j < GRADE_NUM; j++) {
                    if (Assess[i][j] != 0)
                        sum[i] += Assess[i][j] * (Math.log(Assess[i][j]) / Math.log(2.7183));
                }
                e[i] = -k * sum[i];
            }
            for (i = 0; i < ST_QT_NUM; i++)
                d[i] = 1 - e[i];
            sum[0] = 0;
            for (i = 0; i < ST_QT_NUM; i++)
                sum[0] += d[i];
            for (i = 0; i < ST_QT_NUM; i++)
                Weight[i][METHOD_IDX4] = d[i] / sum[0];
        } catch (Exception e) {
            logger.error(e.getMessage());
            blSqfFlag = false;
        }
        return blSqfFlag;
    }

    //变异系数法求权重
    private boolean getBysxf() {
        boolean blBysxfFlag = true;
        try {
            float avg_f[] = new float[ST_QT_NUM];//平均值
            float std_f[] = new float[ST_QT_NUM];//标准差
            float byxs[] = new float[ST_QT_NUM];//变异系数
            float sum;
            int i, j;
            for (i = 0; i < ST_QT_NUM; i++) {
                avg_f[i] = 0;
                std_f[i] = 0;
                byxs[i] = 0;
            }
            //求平均值
            for (i = 0; i < ST_QT_NUM; i++) {
                sum = 0;
                for (j = 0; j < GRADE_NUM; j++)
                    sum += Assess[i][j];
                avg_f[i] = sum / GRADE_NUM;
            }
            //求标准差
            for (i = 0; i < ST_QT_NUM; i++) {
                sum = 0;
                for (j = 0; j < GRADE_NUM; j++)
                    sum += Math.pow((Assess[i][j] - avg_f[i]), 2);
                std_f[i] = (float) (Math.sqrt(sum / GRADE_NUM));
            }
            //求变异系数
            for (i = 0; i < ST_QT_NUM; i++) {
                if (avg_f[i] < 0)
                    avg_f[i] = 0 - avg_f[i];
                byxs[i] = std_f[i] / avg_f[i];
            }
            sum = 0;
            for (i = 0; i < ST_QT_NUM; i++)
                sum += byxs[i];
            for (i = 0; i < ST_QT_NUM; i++)
                Weight[i][METHOD_IDX5] = byxs[i] / sum;
        } catch (Exception e) {
            logger.error(e.getMessage());
            blBysxfFlag = false;
        }
        return blBysxfFlag;
    }

    //求综合权重,主观权重和客观权重占比相等各自50%
    private boolean getZhqzf() {
        float D[] = new float[ST_QT_NUM];
        float e[] = new float[ST_QT_NUM];
        float C[][] = new float[ST_QT_NUM][ST_QT_NUM];
        float C1[][] = new float[ST_QT_NUM][ST_QT_NUM];
        float tmp1[] = new float[ST_QT_NUM];
        float tmp2[] = new float[ST_QT_NUM];
        boolean blZhqzfFlag = true;
        try {
            int i, j, k;
            float t1, t2;

            //求C
            for (i = 0; i < ST_QT_NUM; i++) {
                tmp1[i] = 0;
                for (j = 0; j < GRADE_NUM; j++)
                    tmp1[i] += 2 * METHOD_NUM * Math.pow(Assess[i][j], 2);
            }
            for (i = 0; i < ST_QT_NUM; i++) {
                for (j = 0; j < ST_QT_NUM; j++) {
                    if (i == j)
                        C[i][j] = tmp1[i];
                    else
                        C[i][j] = 0;
                }
            }
            //求C的逆矩阵C1,由于C是对角矩阵，简化矩阵求逆
            for (i = 0; i < ST_QT_NUM; i++) {
                for (j = 0; j < ST_QT_NUM; j++) {
                    if (i == j)
                        C1[i][j] = (float) 1.0 / C[i][j];
                    else
                        C1[i][j] = 0;
                }
            }
            //求D
            for (i = 0; i < ST_QT_NUM; i++) {
                tmp1[i] = 0;
                for (k = 0; k < METHOD_NUM; k++)
                    tmp1[i] += Weight[i][k];
                tmp2[i] = 0;
                for (j = 0; j < GRADE_NUM; j++) {
                    tmp2[i] += tmp1[i] * Math.pow(Assess[i][j], 2);
                }
                D[i] = 2 * tmp2[i];
            }
            //e赋值
            for (i = 0; i < ST_QT_NUM; i++)
                e[i] = 1;
            //计算eT*C1
            for (i = 0; i < ST_QT_NUM; i++) {
                tmp1[i] = 0;
                for (j = 0; j < ST_QT_NUM; j++)
                    tmp1[i] += e[i] * C1[j][i];
            }
            t1 = 0;
            for (i = 0; i < ST_QT_NUM; i++)
                t1 += tmp1[i] * e[i];
            t2 = 0;
            for (i = 0; i < ST_QT_NUM; i++)
                t2 += tmp1[i] * D[i];
            for (i = 0; i < ST_QT_NUM; i++)
                e[i] = e[i] * ((1 - t2) / t1);
            for (i = 0; i < ST_QT_NUM; i++)
                D[i] = D[i] + e[i];
            //求A
            for (i = 0; i < ST_QT_NUM; i++) {
                A[i] = 0;
                for (j = 0; j < ST_QT_NUM; j++)
                    A[i] += C1[i][j] * D[j];
            }
        } catch (Exception ex) {
            logger.error(ex.getMessage());
            blZhqzfFlag = false;
        }
        return blZhqzfFlag;
    }
}
