package org.jeecg.modules.warning.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.mchange.lang.DoubleUtils;
import net.sf.saxon.type.Converter;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.modules.warning.common.Fitting;
import org.jeecg.modules.warning.entity.ALLDModel;
import org.jeecg.modules.warning.entity.WellPosition;
import org.jeecg.modules.warning.mapper.FzqkMapper;
import org.jeecg.modules.warning.model.DrillInfoModel;
import org.jeecg.modules.warning.service.IFzqkService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@DS("fzqkDataSource2021")
public class FzqkServiceImpl implements IFzqkService {

    @Autowired
    private FzqkMapper fzqkMapper;

    private Map<String, List<ALLDModel>> historyList = new HashMap<>();

    /**
     *
     * @param radius
     * @param jh
     * @param jsStart dataType为1时提供， 为0实时时不用
     * @param jsEnd 保留参数， 不用
     * @param dataType， 0实时， 1 历史
     * @param x 默认 -1
     * @param y 默认 -1
     * @return
     */
    @Override
    public Map<String, List<DrillInfoModel>> Calculate(double radius, String jh,
                                                       String jsStart, String jsEnd, int dataType,
                                                       double x, double y) {
        jsStart="";
        String[] zd = {"dgfh", "ly", "zs", "ckmd", "ckdd", "zctj", "ckll"};
        String[] alfzqk = {"井涌", "卡钻", "井漏", "断钻具", "井塌", "钻井液污染"};
        Map<String, List<DrillInfoModel>> results = new HashMap<>();
        for (String item : alfzqk) {
            results.put(item, new ArrayList<DrillInfoModel>());
        }
        double[][] weight = {{0, 0.05, 0.1, 0, 0, 0.75, 0.1},
                {0.85, 0.05, 0, 0, 0, 0.05, 0.05},
                {0, 0, 0.05, 0, 0, 0.8, 0.15},
                {0.45, 0.45, 0, 0, 0, 0.05, 0.05},
                {0.2, 0.5, 0.2, 0, 0, 0.05, 0.05},
                {0, 0, 0, 0.55, 0.35, 0.05, 0.05}};
        Map<String, Object> quryMap = new HashMap<>();
        quryMap.put("jh", jh);
        quryMap.put("js", Double.parseDouble(jsEnd));
        if (dataType == 0) {
            quryMap.put("realTime", "Y");
        } else {
            quryMap.put("realTime", "N");
        }
        List<ALLDModel> WellData = fzqkMapper.getWellData(quryMap);
        double pX = Double.MIN_VALUE;
        double pY = Double.MIN_VALUE;
        if (x > 0 && y > 0) {
            pX = x;
            pY = y;
        } else{
            WellPosition wellInfo = fzqkMapper.getAzj01ByJh(jh);
            if (StringUtils.isEmpty(wellInfo.getSjjwzzbx()) || StringUtils.isEmpty(wellInfo.getSjjwzzby())) {

            } else {
                pX = Double.parseDouble(wellInfo.getSjjwzzbx());
                pY = Double.parseDouble(wellInfo.getSjjwzzby());
            }
        }
        SetHistoryData(pX, pY, radius);

        int dataCount = WellData.size();//进行匹配的数据量
        int zdCount = zd.length;
        Double[][] realData = new Double[dataCount][zdCount];
        for (int i = 0; i < dataCount; i++) {
            double tmpdb = 0;
            try {
                tmpdb = Double.parseDouble(WellData.get(i).getDgfh());
                realData[i][0] = tmpdb;
            } catch (Exception e) {
                realData[i][0] = new Double(0);
            }
            try {
                tmpdb = Double.parseDouble(WellData.get(i).getLy());
                realData[i][1] = tmpdb;
            } catch (Exception e) {
                realData[i][1] = new Double(0);
            }
            try {
                tmpdb = Double.parseDouble(WellData.get(i).getLy());
                realData[i][1] = tmpdb;
            } catch (Exception e) {
                realData[i][1] = new Double(0);
            }
            try {
                tmpdb = Double.parseDouble(WellData.get(i).getZs());
                realData[i][2] = tmpdb;
            } catch (Exception e) {
                realData[i][2] = new Double(0);
            }
            try {
                tmpdb = Double.parseDouble(WellData.get(i).getCkmd());
                realData[i][3] = tmpdb;
            } catch (Exception e) {
                realData[i][3] = new Double(0);
            }
            try {
                tmpdb = Double.parseDouble(WellData.get(i).getCkdd());
                realData[i][4] = tmpdb;
            } catch (Exception e) {
                realData[i][4] = new Double(0);
            }
            try {
                tmpdb = Double.parseDouble(WellData.get(i).getZctj());
                realData[i][5] = tmpdb;
            } catch (Exception e) {
                realData[i][5] = new Double(0);
            }
            try {
                tmpdb = Double.parseDouble(WellData.get(i).getCkll());
                realData[i][6] = tmpdb;
            } catch (Exception e) {
                realData[i][6] = new Double(0);
            }
        }
        List<String> alList = new ArrayList<>();
        for (Map.Entry<String, List<ALLDModel>> entry : historyList.entrySet()) {
            alList.add(entry.getKey());
        }
        List<String> fitType = FilterRealDataType(WellData);
        for (int i = 0; i < alList.size(); i++) {
            String tmpJh = alList.get(i).split(",")[0];
            String tmpAlbh = alList.get(i).split(",")[1];

            List<ALLDModel> oneHistoryList = historyList.get(alList.get(i));
            int dataCount1 = dataCount > oneHistoryList.size() ? oneHistoryList.size() : dataCount;
            Double[][] hisData = new Double[dataCount1][zdCount];

            int index = oneHistoryList.size() - dataCount1;
            for (int j = 0; j < dataCount1; j++) {
                double tmpdb = 0;
                try {
                    tmpdb = Double.parseDouble(oneHistoryList.get(index).getDgfh());
                    hisData[j][0] = tmpdb;
                } catch (Exception e) {
                    hisData[j][0] = new Double(0);//数据为空时，0代替
                }
                try {
                    tmpdb = Double.parseDouble(oneHistoryList.get(index).getLy());
                    hisData[j][1] = tmpdb;
                } catch (Exception e) {
                    hisData[j][1] = new Double(0);//数据为空时，0代替
                }
                try {
                    tmpdb = Double.parseDouble(oneHistoryList.get(index).getZs());
                    hisData[j][2] = tmpdb;
                } catch (Exception e) {
                    hisData[j][2] = new Double(0);//数据为空时，0代替
                }
                try {
                    tmpdb = Double.parseDouble(oneHistoryList.get(index).getCkmd());
                    hisData[j][3] = tmpdb;
                } catch (Exception e) {
                    hisData[j][3] = new Double(0);//数据为空时，0代替
                }
                try {
                    tmpdb = Double.parseDouble(oneHistoryList.get(index).getCkdd());
                    hisData[j][4] = tmpdb;
                } catch (Exception e) {
                    hisData[j][4] = new Double(0);//数据为空时，0代替
                }
                try {
                    tmpdb = Double.parseDouble(oneHistoryList.get(index).getZctj());
                    hisData[j][5] = tmpdb;
                } catch (Exception e) {
                    hisData[j][5] = new Double(0);//数据为空时，0代替
                }
                try {
                    tmpdb = Double.parseDouble(oneHistoryList.get(index).getCkll());
                    hisData[j][6] = tmpdb;
                } catch (Exception e) {
                    hisData[j][6] = new Double(0);//数据为空时，0代替
                }
                index++;
            }
            //读取该复杂情况所属类别
            String tmpfzqk = oneHistoryList.get(0).getMc();

            //计算所属序列号
            int tmpFzIndex = 0;
            for (int j = 0; j < alfzqk.length; j++) {
                String fzqk=alfzqk[j];
                if (fzqk.equals(tmpfzqk)) {
                    tmpFzIndex = j;
                    break;
                }
            }
            //增加 复杂情况过滤
            if (fitType.contains(tmpfzqk))
                continue;

            //计算相关系数
            double tmpCorr = 0;
            double sumQz = 1;//剩余权重之和
            double[] tmpcorr = new double[zdCount];
            for (int j = 0; j < zdCount; j++) {
                double[] tmpX = new double[dataCount];
                double[] tmpY = new double[dataCount1];
                for (int k = 0; k < dataCount; k++) {
                    tmpX[k] = realData[k][j];
                }
                for (int k = 0; k < dataCount1; k++) {
                    tmpY[k] = hisData[k][j];
                }

                double res = pearsoncorr(tmpX, tmpY);
                if (res == 2) {
                    sumQz = sumQz - weight[tmpFzIndex][j];
                    res = 0;//数据为空值时相似为0
                }
                tmpcorr[j] = res;
            }
            for (int i2 = 0; i2 < zdCount; i2++) {
                tmpCorr += (weight[tmpFzIndex][i2] + weight[tmpFzIndex][i2] * (1 - sumQz) / sumQz) * tmpcorr[i2];
            }
            DrillInfoModel calResult = new DrillInfoModel();
            calResult.setCorr(tmpCorr * 0.8);
            calResult.setJh(tmpJh);
            calResult.setAlbh(tmpAlbh);
            calResult.setFzmc(tmpfzqk);
            calResult.setFzmcIndex(FirstIndexOf(alfzqk, tmpfzqk));

            List<DrillInfoModel> l = results.get(tmpfzqk);
            if (tmpCorr > (l.size() > 0 ? l.get(0).getCorr() : -1)) {
                if (l.size() == 0) {
                    l.add(calResult);
                } else {
                    l.set(0, calResult);
                }
            } else if (l.size() > 1 && tmpCorr > l.get(1).getCorr()) {
                l.set(1, calResult);
            } else if (l.size() == 1) {
                l.add(calResult);
            }
            results.put(tmpfzqk,l);
        }
        return results;
    }

    /**
     * 计算相似度系数
     *
     * @param X
     * @param Y
     * @return
     */
    private double pearsoncorr(double[] X, double[] Y) {
        double r = 0;
        if (X.length != Y.length) {
            return 0;
        }
        int count = X.length;
        //计算平均值
        double aveX = 0;
        double aveY = 0;
        double sumX = 0;
        double sumY = 0;
        for (int i = 0; i < count; i++) {
            sumX += X[i];
            sumY += Y[i];
        }
        aveX = sumX / count;
        aveY = sumY / count;

        //计算相关系数
        double tmpA = 0;
        double tmpB = 0;
        double tmpC = 0;
        for (int i = 0; i < count; i++) {
            tmpA += (X[i] - aveX) * (Y[i] - aveY);
            tmpB += (X[i] - aveX) * (X[i] - aveX);
            tmpC += (Y[i] - aveY) * (Y[i] - aveY);
        }

        //判断x、y取值都相同的情况
        if (tmpB < 0.0000001 && tmpC < 0.0000001) {
            if (sumX == 0)//x,y取值均为0时，相关系数取0
            {
                r = 2;
            } else {
                r = 1;
            }
        } else if (tmpB * tmpC < 0.000000001)//x或y只有一组取值相同，另一组取值不同时，即分母为0时，直接结果取0
        {
            r = 0;
        } else {
            r = tmpA / Math.sqrt(tmpB * tmpC);
        }
        if (r > 1 && r != 2) {
            r = 1;
        } else if (r < 0) {
            r = 0;
        }

        return r;
    }

    private int FirstIndexOf(String[] source, String item) {
        int result = 0;

        for (int i = 0; i < source.length; i++) {
            if (source[i] == item) {
                result = i;
                break;
            }
        }

        return result;
    }

    private void SetHistoryData(double zbX, double zbY, double radius) {
        historyList = new HashMap<>();
        Map<String, Object> map = new HashMap<>();
        if (zbX == Double.MIN_VALUE || zbY == Double.MIN_VALUE) {
            map.put("zbX", null);
            map.put("zbY", null);
        } else {
            map.put("zbX", zbX);
            map.put("zbY", zbY);
        }
        map.put("radius", radius);
        List<ALLDModel> records = fzqkMapper.getHistoryData(map);
        String key = "";
        List<ALLDModel> wellRecords = new ArrayList<>();
        for (ALLDModel item : records) {
            String keyNow = item.getAlbh() + "," + item.getJh();
            if (key.equals(keyNow)) {
                wellRecords.add(item);
            } else {
                wellRecords = new ArrayList<>();
                wellRecords.add(item);
                if (!key.equals("")) {
                    historyList.put(keyNow, wellRecords);
                }else{
                    historyList.put(keyNow, wellRecords);
                }
            }
            key = keyNow;
        }
        if (!key.equals("")) {
           // historyList.put(key, wellRecords);
        }
    }

    private List<String> FilterRealDataType(List<ALLDModel> WellData) {
        List<String> fitType = new ArrayList<>();
        List<Double> jsList = new ArrayList<>();
        List<Double> dgfh = new ArrayList<>();
        List<Double> ly = new ArrayList<>();
        List<Double> ckmd = new ArrayList<>();
        List<Double> zctj = new ArrayList<>();
        List<Double> ckll = new ArrayList<>();
        for (ALLDModel model : WellData) {
            double js = 0;
            try {
                js = Double.parseDouble(model.getJs());
            } catch (Exception e) {
                continue;
            }
            jsList.add(js);
            dgfh.add(TryParseDouble(model.getDgfh()));
            ly.add(TryParseDouble(model.getLy()));
            ckmd.add(TryParseDouble(model.getCkmd()));
            zctj.add(TryParseDouble(model.getZctj()));
            ckll.add(TryParseDouble(model.getCkll()));
        }
        double[] fitdgfh = Fitting.MultiLine(jsList.toArray(new Double[jsList.size()]), dgfh.toArray(new Double[dgfh.size()]), dgfh.size(), 1);
        double[] fitly = Fitting.MultiLine(jsList.toArray(new Double[jsList.size()]), ly.toArray(new Double[ly.size()]), ly.size(), 1);
        double[] fitckmd = Fitting.MultiLine(jsList.toArray(new Double[jsList.size()]), ckmd.toArray(new Double[ckmd.size()]), ckmd.size(), 1);
        double[] fitzctj = Fitting.MultiLine(jsList.toArray(new Double[jsList.size()]), zctj.toArray(new Double[zctj.size()]), zctj.size(), 1);
        double[] fitckll = Fitting.MultiLine(jsList.toArray(new Double[jsList.size()]), ckll.toArray(new Double[ckll.size()]), ckll.size(), 1);

        TrendValue tDgfh = CheckTrend(fitdgfh[1]);
        TrendValue tLy = CheckTrend(fitly[1]);
        TrendValue tCkmd = CheckTrend(fitckmd[1]);
        TrendValue tZctj = CheckTrend(fitzctj[1]);
        TrendValue tCkll = CheckTrend(fitckmd[1]);

        if (tLy == TrendValue.Down || tZctj == TrendValue.Up || tCkll == TrendValue.Up) {
            fitType.add("井涌");
        }
        if (tLy == TrendValue.Up || tLy == TrendValue.Steady || tDgfh == TrendValue.Up || tZctj == TrendValue.Steady || tZctj == TrendValue.Down) {
            fitType.add("卡钻");
        }
        if (tLy == TrendValue.Down || tZctj == TrendValue.Down || tCkll == TrendValue.Down) {
            fitType.add("井漏");
        }
        if (tLy == TrendValue.Down || tDgfh == TrendValue.Down) {
            fitType.add("断钻具");
        }
        if (tLy == TrendValue.Up) {
            fitType.add("井塌");
        }
        if (tCkmd == TrendValue.Down || tZctj == TrendValue.Up || tCkll == TrendValue.Up) {
            fitType.add("钻井液污染");
        }

        return fitType;
    }

    private TrendValue CheckTrend(Double src) {
        TrendValue result = TrendValue.Steady;
        if (src > 0.1) result = TrendValue.Up;
        else if (src < -0.1) result = TrendValue.Down;

        return result;
    }

    public enum TrendValue {
        Up(0),
        Steady(1),
        Down(2);

        TrendValue(int i) {
        }
    }

    private double TryParseDouble(Object src) {
        if (src == null) {
            return 0;
        }
        try {
            double t = Double.parseDouble(src.toString());
            return t;
        } catch (Exception ex) {
            return 0;
        }
    }
}

enum DataType {
    realTime(0),
    history(1);

    DataType(int i) {
    }
}
