package com.pqs9000.serviceimpl.responsibility;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.njcn.mapper.configuration.LineMapper;
import com.njcn.pojo.commons.RedisDB;
import com.njcn.pojo.responsibility.ResponsibilityData;
import com.njcn.shiro.token.TokenManager;
import com.njcn.utils.AppConfig;
import com.njcn.utils.PubUtils;
import com.njcn.utils.SerializeUtil;
import com.njcn.utils.redis.JedisManager;
import com.pqs9000.exception.UserDataException;
import com.pqs9000.mapper.data.DataIMapper;
import com.pqs9000.mapper.data.DataVMapper;
import com.pqs9000.mapper.responsibility.ResponsibilityDataMapper;
import com.pqs9000.mapper.responsibility.UserExcelDataMapper;
import com.pqs9000.mapper.responsibility.UserExcelDataNoIntegrityMapper;
import com.pqs9000.pojo.data.*;
import com.pqs9000.pojo.report.UserDataExcelBody;
import com.pqs9000.pojo.responsibility.*;
import com.pqs9000.service.responsibility.ResponsibilityService;
import com.pqs9000.util.UserDataExcelUtil;
import net.sf.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author hongawen
 * @Date: 2019/3/28 15:27
 */
@Service
public class ResponsibilityServiceImpl implements ResponsibilityService {

    private static final Logger logger = LoggerFactory.getLogger(ResponsibilityServiceImpl.class);

    @Autowired
    private DataVMapper dataVMapper;

    @Autowired
    private DataIMapper dataIMapper;

    @Autowired
    private GetQvvrData getQvvrData;

    @Autowired
    private UserExcelDataMapper userExcelDataMapper;

    @Autowired
    private AppConfig appConfig;

    @Autowired
    private UserExcelDataNoIntegrityMapper userExcelDataNoIntegrityMapper;

    @Autowired
    private JedisManager jedisManager;

    @Autowired
    private LineMapper lineMapper;

    @Autowired
    private ResponsibilityDataMapper responsibilityDataMapper;


    /**
     * 获取历史谐波数据
     *
     * @param lineIndex 监测点索引
     * @param startTime 起始时间
     * @param endTime   截止时间
     * @param type      谐波类型
     * @param time      谐波次数
     */
    @Override
    public List<Responsibility> getHistoryData(Integer lineIndex, Date startTime, Date endTime, String type, Integer time) throws UserDataException {
        List<Responsibility> historyData = new ArrayList<>();
        //判断是电压还是电流
        if (type.equalsIgnoreCase("vol")) {
            historyData = getVHistoryData(lineIndex, startTime, endTime, time);
        } else if (type.equalsIgnoreCase("ele")) {
            historyData = getIHistoryData(lineIndex, startTime, endTime, time);
        }
        //如果result不为空，排序下
        if (!CollectionUtils.isEmpty(historyData)) {
            Collections.sort(historyData);
        }

        return historyData;
    }

    /**
     * 获取谐波电压的数据
     * <p>
     * 因历史谐波表DATA_V表数据庞大，需要运用起缓存
     *
     * @param lineIndex 监测点索引
     * @param startTime 起始时间
     * @param endTime   截止时间
     * @param time      谐波次数
     */
    private List<Responsibility> getVHistoryData(Integer lineIndex, Date startTime, Date endTime, Integer time) throws UserDataException {
        List<Responsibility> result = new ArrayList<>();
        List<ResponsibilityStr> temp;
        logger.error("开始获取历史电压谐波数据");
        try {
            //谐波电压次+监测点索引+用户索引+起始时间+截止时间。
            String key = time + "vol" + lineIndex + TokenManager.getUserId() + PubUtils.date2String(startTime, "yyyy-MM-dd") + PubUtils.date2String(endTime, "yyyy-MM-dd");
            String jsonStr = jedisManager.getValueByKey(RedisDB.LONG_TIME_QUERY, key);
            if (StringUtils.isEmpty(jsonStr)) {
                //没有命中缓存则去数据库查询
                result = dataVMapper.getHistoryData(lineIndex, startTime, endTime, time);
                //补齐历史谐波数据
                int lineInterval = lineMapper.getIntervalByIndex(lineIndex);
                if (CollectionUtils.isEmpty(result)) {
                    //如果数据为空，则提示给用户暂无数据
                    throw new UserDataException("时间范围内无谐波数据");
                }
                //最新两条数据的间隔与监测点查出的间隔做对比，返回一个合理的间隔
                lineInterval = getInterval(lineInterval, result.get(result.size() - 1).getTime(), result.get(result.size() - 2).getTime());
                result = dealHistoryData(result, lineInterval);
                if (CollectionUtils.isEmpty(result)) {
                    //如果数据为空，则提示给用户暂无数据
                    throw new UserDataException("时间范围内无谐波数据");
                }
                //根据时间天数，获取理论上多少次用采数据
                List<String> dateStr = PubUtils.getTimes(startTime, endTime);
                int dueTimes = dateStr.size() * 1440 / lineInterval;
                int realTimes = result.size();
                if (dueTimes != realTimes) {
                    //期待值与实际值不等，则提示用户时间范围内谐波数据完整性不足
                    throw new UserDataException("时间范围内谐波数据完整性不足");
                }
                temp = getResStr(result);
                saveArrayData(temp, key);
            } else {
                JSONArray ja = JSONArray.fromObject(jsonStr);
                temp = (List<ResponsibilityStr>) JSONArray.toCollection(ja, ResponsibilityStr.class);
                result = getResDate(temp);
            }
        } catch (UserDataException u) {
            throw u;
        } catch (Exception e) {
            logger.error("redis读取缓存出现异常，方法为getVHistoryData，异常为：e" + e.toString());
        }
        return result;
    }

    /**
     * 获取合理的测量间隔
     */
    private int getInterval(int lineInterval, Date lastOne, Date lastTwo) {
        int interval = 0;
        Calendar one = Calendar.getInstance();
        one.setTime(lastOne);
        Calendar two = Calendar.getInstance();
        two.setTime(lastTwo);
        long oneTime = lastOne.getTime();
        long twoTime = lastTwo.getTime();
        long intvalTime = oneTime - twoTime;
        long databaseInterval = lineInterval * 60 * 1000;
        if (oneTime < twoTime || intvalTime >= databaseInterval) {
            interval = lineInterval;
        }
        if (intvalTime < databaseInterval) {
            interval = (int) (intvalTime / (1000 * 60));
        }
        return interval;
    }


    /**
     * 获取谐波电流的数据
     * <p>
     * 因历史谐波表DATA_I表数据庞大，需要运用起缓存
     *
     * @param lineIndex 监测点索引
     * @param startTime 起始时间
     * @param endTime   截止时间
     * @param time      谐波次数
     */
    private List<Responsibility> getIHistoryData(Integer lineIndex, Date startTime, Date endTime, Integer time) {
        List<Responsibility> result = new ArrayList<>();
        List<ResponsibilityStr> temp;
        try {
            //谐波电流次+监测点索引+用户索引+起始时间+截止时间。
            String key = time + "ele" + lineIndex + TokenManager.getUserId() + PubUtils.date2String(startTime, "yyyy-MM-dd") + PubUtils.date2String(endTime, "yyyy-MM-dd");
            String jsonStr = jedisManager.getValueByKey(RedisDB.LONG_TIME_QUERY, key);
            if (StringUtils.isEmpty(jsonStr)) {
                //没有命中缓存则去数据库查询
                result = dataIMapper.getHistoryData(lineIndex, startTime, endTime, time);
                //补齐历史谐波数据
                int lineInterval = lineMapper.getIntervalByIndex(lineIndex);
                if (CollectionUtils.isEmpty(result)) {
                    //如果数据为空，则提示给用户暂无数据
                    throw new UserDataException("时间范围内无谐波数据");
                }
                //最新两条数据的间隔与监测点查出的间隔做对比，返回一个合理的间隔
                lineInterval = getInterval(lineInterval, result.get(result.size() - 1).getTime(), result.get(result.size() - 2).getTime());
                result = dealHistoryData(result, lineInterval);
                if (CollectionUtils.isEmpty(result)) {
                    //如果数据为空，则提示给用户暂无数据
                    throw new UserDataException("时间范围内无谐波数据");
                }
                //根据时间天数，获取理论上多少次用采数据
                List<String> dateStr = PubUtils.getTimes(startTime, endTime);
                int dueTimes = dateStr.size() * 1440 / lineInterval;
                int realTimes = result.size();
                if (dueTimes != realTimes) {
                    //期待值与实际值不等，则提示用户时间范围内谐波数据完整性不足
                    throw new UserDataException("时间范围内谐波数据完整性不足");
                }
                temp = getResStr(result);
                saveArrayData(temp, key);
            } else {
                JSONArray ja = JSONArray.fromObject(jsonStr);
                temp = (List<ResponsibilityStr>) JSONArray.toCollection(ja, ResponsibilityStr.class);
                result = getResDate(temp);
            }
        } catch (Exception e) {
            logger.error("redis读取缓存出现异常，getIHistoryData，异常为：e" + e.toString());
        }
        return result;
    }

    /**
     * 根据库中查询的数据，进行数据补齐操作
     *
     * @param beforeDeal 库中实际的历史谐波数据
     */
    private List<Responsibility> dealHistoryData(List<Responsibility> beforeDeal, int lineInterval) throws Exception {
        logger.error("开始处理历史电压谐波数据");
        List<Responsibility> result = new ArrayList<>();
        try {
            if (CollectionUtils.isEmpty(beforeDeal)) {
                return result;
            } else {
                //先将查询数据按日进行收集
                Map<String/*yyyy-MM-dd的时间格式*/, Map<Date, Responsibility>/*当前天的所有谐波数据*/> dayHistoryDatas = new HashMap<>();
                for (Responsibility responsibility : beforeDeal) {
                    Date time = responsibility.getTime();
                    if (null == time) {
                        continue;
                    }
                    String date = PubUtils.date2String(time, "yyyy-MM-dd");
                    if (dayHistoryDatas.containsKey(date)) {
                        Map<Date, Responsibility> responsibilities = dayHistoryDatas.get(date);
                        responsibilities.put(PubUtils.getSecondsAsZero(responsibility.getTime()), responsibility);
                        dayHistoryDatas.put(date, responsibilities);
                    } else {
                        Map<Date, Responsibility> responsibilities = new HashMap<>();
                        responsibilities.put(PubUtils.getSecondsAsZero(responsibility.getTime()), responsibility);
                        dayHistoryDatas.put(date, responsibilities);
                    }
                }
                //将数据按日期处理后，开始进行完整性判断，满足完整性则进行补齐，否则返回空数据
                Set<String> days = dayHistoryDatas.keySet();
                for (String day : days) {
                    //获取出当天的历史谐波数据
                    Map<Date, Responsibility> responsibilities = dayHistoryDatas.get(day);
                    if (CollectionUtils.isEmpty(responsibilities)) {
                        continue;
                    }
                    //可能会存在非当天的数据，很奇葩的问题，怎么把剔除掉？
                    int dueTimes = 1440 / lineInterval;
                    int realTimes = responsibilities.size();
                    double integrity = new Double(realTimes) / new Double(dueTimes);
                    if (integrity < 0.9) {
                        //完整性不足，则返回原数据
                        Set<Date> dates = responsibilities.keySet();
                        for (Date time : dates) {
                            result.add(responsibilities.get(time));
                        }
                    } else {
                        //进行数据补齐,数据补齐需要根据监测点测量间隔,最好是MAP格式 map的key是yyyy-MM-dd HH:mm
                        List<Responsibility> afterDeal = new ArrayList<>();
                        String timeTemp = day + " 00:00:00";
                        Date date = PubUtils.string2Date(timeTemp, "yyyy-MM-dd HH:mm:ss");
                        for (int i = 0; i < dueTimes; i++) {
                            Calendar calendar = Calendar.getInstance();
                            calendar.setTime(date);
                            calendar.add(Calendar.MINUTE, lineInterval * i);
                            Responsibility temp = responsibilities.get(calendar.getTime());
                            if (temp != null && temp.getValue() != null) {
                                afterDeal.add(temp);
                            } else {
                                //递归找到前面的值
                                Float preValue = getPreHarmValue(date, calendar.getTime(), responsibilities, lineInterval);
                                //递归找到后面的值
                                Float appendValue = getAppendHarmValue(date, calendar.getTime(), responsibilities, lineInterval);
                                Responsibility responsibility = new Responsibility();
                                responsibility.setTime(calendar.getTime());
                                //还需要判断前值和后值为空的情况
                                if (null == preValue && null == appendValue) {
                                    responsibility.setValue(0.0f);
                                } else if (null == preValue) {
                                    responsibility.setValue(appendValue);
                                } else if (null == appendValue) {
                                    responsibility.setValue(preValue);
                                } else {
                                    responsibility.setValue((preValue + appendValue) / 2);
                                }
                                afterDeal.add(responsibility);
                            }
                        }
                        result.addAll(afterDeal);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("开始处理历史电压谐波数据失败，失败原因：" + e.toString());
        }
        logger.error("结束处理历史电压谐波数据");
        return result;
    }


    /**
     * 递归找前值 谐波数据
     *
     * @param date       起始时间
     * @param time       当前事件
     * @param beforeDeal 处理前的数据
     */
    private Float getPreHarmValue(Date date, Date time, Map<Date, Responsibility> beforeDeal, int interval) {
        Float result;
        if (date.getTime() >= time.getTime()) {
            return null;
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(time);
            interval = 0 - interval;
            calendar.add(Calendar.MINUTE, interval);
            Responsibility temp = beforeDeal.get(calendar.getTime());
            if (temp == null || temp.getValue() == null) {
                result = getPreHarmValue(date, calendar.getTime(), beforeDeal, Math.abs(interval));
            } else {
                result = temp.getValue();
            }
        }
        return result;
    }

    /**
     * 递归找后置 谐波数据
     *
     * @param date 起始时间
     * @param time 截止时间
     */
    private Float getAppendHarmValue(Date date, Date time, Map<Date, Responsibility> beforeDeal, int interval) {
        Float result;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        calendar.add(Calendar.MINUTE, -interval);
        if (calendar.getTimeInMillis() <= time.getTime()) {//time.equals(calendar.getTime())
            return null;
        } else {
            Calendar calendar1 = Calendar.getInstance();
            calendar1.setTime(time);
            calendar1.add(Calendar.MINUTE, interval);
            Responsibility temp = beforeDeal.get(calendar1.getTime());
            if (temp == null || temp.getValue() == null) {
                result = getAppendHarmValue(date, calendar1.getTime(), beforeDeal, interval);
            } else {
                result = temp.getValue();
            }
        }
        return result;
    }


    /**
     * 将String格式转为日期
     */
    private List<Responsibility> getResDate(List<ResponsibilityStr> temp) throws Exception {
        List<Responsibility> result = new ArrayList<>();
        if (!CollectionUtils.isEmpty(temp)) {
            for (ResponsibilityStr responsibilityStr : temp) {
                Responsibility r = new Responsibility();
                r.setValue(responsibilityStr.getValue());
                r.setTime(PubUtils.string2Date(responsibilityStr.getTime(), "yyyy-MM-dd HH:mm:ss"));
                result.add(r);
            }
        }
        return result;
    }

    /**
     * 将日期格式转为String
     */
    private List<ResponsibilityStr> getResStr(List<Responsibility> temp) throws Exception {
        List<ResponsibilityStr> result = new ArrayList<>();
        if (!CollectionUtils.isEmpty(temp)) {
            for (Responsibility responsibility : temp) {
                ResponsibilityStr r = new ResponsibilityStr();
                r.setValue(responsibility.getValue());
                r.setTime(PubUtils.date2String(responsibility.getTime(), "yyyy-MM-dd HH:mm:ss"));
                result.add(r);
            }
        }
        return result;
    }


    //根据key进行数据缓存
    public void saveArrayData(List<ResponsibilityStr> result, String key) {
        JSONArray jsonArray = JSONArray.fromObject(result);
        String value = jsonArray.toString();
        jedisManager.saveValueByKey(RedisDB.LONG_TIME_QUERY, key, value, RedisDB.LONG_TIME);
    }


    /**
     * 根据谐波数据和功率数据获取动态数据以及责任量化值
     *
     * @param startTime     起始时间
     * @param endTime       截止时间
     * @param type          干扰源类型终
     * @param lineIndex     监测点号
     * @param time          次数
     * @param userDataIndex 用采数据索引
     */
    @Override
    public ResponsibilityResult getDynamicDataAndResponsibiltyByPData(Date startTime, Date endTime, String type, Integer lineIndex, Integer time, String userDataIndex, int calFlag) throws Exception {
        ResponsibilityResult result = new ResponsibilityResult();
        int pNode;
        int pNum;
        float harmMk;
        int win;
        int harmNum;
        //先准备用采数据
        UserExcelData userExcelData = new UserExcelData();
        userExcelData.setExcelIndex(userDataIndex);
        userExcelData = userExcelDataMapper.selectByPrimaryKey(userExcelData);
        if (null == userExcelData) {
            throw new UserDataException("库中无用采数据");
        }
        File userDataFile = new File(userExcelData.getExcelPath());
        String excelPath = userExcelData.getExcelPath();
        ExcelTypeEnum excelTypeEnum;
        if (excelPath.endsWith(ExcelTypeEnum.XLS.getValue())) {
            excelTypeEnum = ExcelTypeEnum.XLS;
        } else {
            excelTypeEnum = ExcelTypeEnum.XLSX;
        }
        //判断文件是否存在
        if (!userDataFile.exists() || !userDataFile.isFile()) {
            throw new UserDataException("本地无用采数据表格");
        }
        List<UserDataExcelBody> userDataExcelBodies = new ArrayList<>();
        try {
            userDataExcelBodies = extractData(new FileInputStream(userDataFile),excelTypeEnum);
        } catch (FileNotFoundException e) {
            logger.error(e.getMessage());
        }
        if (CollectionUtils.isEmpty(userDataExcelBodies)) {
            throw new UserDataException("本地无用采数据表格");
        }
        //开始处理，根据接口参数需求，需要节点数（用户数，用户名+监测点号为一个用户），时间范围内功率数据
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        DealDataResult dealDataResult = getStanderData(userDataExcelBodies, sdf, 1);
        Map<String/*户号@监测点号@户名*/, Map<String/*yyyy-MM-dd天日期*/, List<UserDataExcelBody>>> totalData = dealDataResult.getTotalListData();
        Map<String/*户号@监测点号@户名*/, Map<String/*yyyy-MM-dd天日期*/, List<UserDataExcelBody>>> finalData = new HashMap<>();
        /*第一个参数pNode 如果时间范围内完整性不足90%的节点，不参与责任量化统计,因为之前处理过用采数据，此时只需要判断是否满足100%就可以判断*/
        //根据时间天数，获取理论上多少次用采数据
        List<String> dateStr = PubUtils.getTimes(startTime, endTime);
        int dueCounts = dateStr.size() * 96;
        Set<String> userNames = totalData.keySet();
        for (String userName : userNames) {
            int realCounts = 0;
            Map<String, List<UserDataExcelBody>> temp = totalData.get(userName);
            for (String date : dateStr) {
                if (temp.get(date) != null) {
                    realCounts = realCounts + temp.get(date).size();
                }
            }
            if (realCounts == dueCounts) {
                //只有期望和实际数量一致的时候才作为计算用户
                finalData.put(userName, temp);
            }
        }
        //至此，finalData便是我们最终获得的用于计算责任数据,第一个参数节点数值pNode获取到
        pNode = finalData.size();
        if (pNode < 1) {
            //没有合理的用采数据直接返回
            throw new UserDataException("无用采用户或所有用户的完整性均不满足条件");
        }
        //第二个参数pNum，根据起始时间和截止时间以及监测点测量间隔计算数量
        int lineInteval = lineMapper.getIntervalByIndex(lineIndex);
        int userIntervalTime;
        if (lineInteval == 1 || lineInteval == 3 || lineInteval == 5) {
            userIntervalTime = 15;
            pNum = dateStr.size() * 96;
        } else {
            userIntervalTime = 30;
            pNum = dateStr.size() * 48;
            finalData = dealFinalDataByLineInterval(finalData, lineInteval);
        }

        //第三个参数win,根据起始时间和截止时间的间隔
        if (dateStr.size() > 1) {
            win = 96;
        } else {
            win = 4;
        }
        //第四个参数harmMk，默认为0f
        harmMk = 0f;
        //第五个参数harmNum，与功率数据保持一致
        harmNum = pNum;
        //至此基础数据组装完毕，开始组装功率数据和谐波数据
        //先做谐波数据，理论上到这步的时候，谐波数据是满足完整性并已经补充完整性到100%，此处需要将谐波数据与功率数据长度匹配上
        List<Responsibility> historyData = getHistoryData(lineIndex, startTime, endTime, type, time);
        historyData = getDataWithLineInterval(historyData, lineInteval);
        //理论上此处的historyData的长度等于pNum,开始填充harm_data
        float[] harmData = new float[144000];
        //谐波波形的横轴时间集合
        List<Long> harmTime = new ArrayList<>();
        for (int i = 0; i < historyData.size(); i++) {
            Float value = historyData.get(i).getValue();
            if (value != null) {
                value = value * 1000;
            }
            harmData[i] = value;
            harmTime.add(historyData.get(i).getTime().getTime());
        }
        //harmData填充完毕后，开始组装功率数据
        //首先获取当前时间内的各个用户的数据
        Map<String/*用户名*/, List<UserDataExcelBody>> originalPData = new HashMap<>();
        List<String> names = new ArrayList<>();
        Set<String> userNamesFinal = finalData.keySet();
        for (String userName : userNamesFinal) {
            List<UserDataExcelBody> tempData = new ArrayList<>();
            //根据日期将日期数据全部获取出来
            Map<String, List<UserDataExcelBody>> tempResult = finalData.get(userName);
            for (String date : dateStr) {
                tempData.addAll(tempResult.get(date));
            }
            //按日期排序
            Collections.sort(tempData);
            originalPData.put(userName, tempData);
            names.add(userName);
        }
        //然后开始组装数据
        PDataStruct[] pData = new PDataStruct[QvvrStruct.MAX_P_NUM];
        for (int i = 0; i < names.size(); i++) {
            //当前某用户测量节点的所有数据
            List<UserDataExcelBody> userDataExcelBodies1 = originalPData.get(names.get(i));
            for (int k = 0; k < userDataExcelBodies1.size(); k++) {
                PDataStruct pDataStruct = pData[k];
                if (pDataStruct == null) {
                    pDataStruct = new PDataStruct();
                }
                float[] p = pDataStruct.getP();
                p[i] = userDataExcelBodies1.get(k).getWork().floatValue();
                pData[k] = pDataStruct;
            }
        }
        //至此功率数据也组装完毕，调用友谊提供的接口
        QvvrStruct qvvrStruct = new QvvrStruct();
        qvvrStruct.cal_flag = calFlag;
        qvvrStruct.p_node = pNode;
        qvvrStruct.p_num = pNum;
        qvvrStruct.win = win;
        qvvrStruct.harm_num = harmNum;
        qvvrStruct.harm_mk = harmMk;
        qvvrStruct.p_data = pData;
        qvvrStruct.harm_data = harmData;
        qvvrStruct = getQvvrData.getResponsibilityResult(qvvrStruct);
        //至此接口调用结束，开始组装动态责任数据和用户责任量化结果
        //首先判断cal_ok的标识位是否为1，为0表示程序没有计算出结果
        if (qvvrStruct.cal_ok == 0) {
            throw new UserDataException("调用接口程序计算失败，参数非法");
        }
        //没问题后，先玩动态责任数据
        CustomerData[] customerDatas = new CustomerData[qvvrStruct.p_node];
        PDataStruct[] fKdata/*无背景的动态责任数据*/ = qvvrStruct.getFKdata();
        //第一个时间节点是起始时间+win窗口得到的时间
        Date sTime = PubUtils.string2Date(dateStr.get(0) + " 00:00:00", "yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(sTime);
        calendar.add(Calendar.MINUTE, (win - 1) * userIntervalTime);
        for (int i = 0; i < qvvrStruct.p_num - qvvrStruct.win; i++) {
            calendar.add(Calendar.MINUTE, userIntervalTime);
            //一个时间点所有的用户数据
            PDataStruct fKdatum = fKdata[i];
            for (int k = 0; k < qvvrStruct.p_node; k++) {
                CustomerData customerData = customerDatas[k];
                if (null == customerData) {
                    customerData = new CustomerData();
                    customerData.setCustomerName(names.get(k));
                }
                List<Float> valueDatas = customerData.getValueDatas();
                Float valueTemp = fKdatum.getP()[k];
                if (valueTemp.isNaN()) {
                    valueTemp = 0.0f;
                }
                valueDatas.add(valueTemp);
                List<Long> timeDatas = customerData.getTimeDatas();
                timeDatas.add(calendar.getTimeInMillis());
                customerData.setValueDatas(valueDatas);
                customerData.setTimeDatas(timeDatas);
                customerDatas[k] = customerData;
            }
        }
        //OK拿到所有测量点的数据了，现在就是看如何将相同户号的动态数据进行算术和求值，之前的用户name为：户号@测量点号@用户名
        Map<String/*用户名（户号）*/, List<CustomerData>> customerDataTemp = new HashMap<>();
        for (int i = 0; i < customerDatas.length; i++) {
            String customerName = customerDatas[i].getCustomerName();
            String[] customerInfo = customerName.split("@");
            String name = customerInfo[2] + "(" + customerInfo[0] + ")";
            List<CustomerData> customerData = customerDataTemp.get(name);
            CustomerData temp = customerDatas[i];
            temp.setCustomerName(name);
            if (CollectionUtils.isEmpty(customerData)) {
                customerData = new ArrayList<>();
            }
            customerData.add(temp);
            customerDataTemp.put(name, customerData);
        }
        //动态数据组装完成后，开始组装责任数据
        List<CustomerResponsibility> customerResponsibilities = getCustomerResponsibilityData(names, qvvrStruct.sumFKdata, qvvrStruct.p_node);
        //根据前十的用户数据，获取这些用户的动态责任数据
        List<CustomerData> customerData = new ArrayList<>();
        for (CustomerResponsibility customerResponsibility : customerResponsibilities) {
            String cusName = customerResponsibility.getCustomerName();
            List<CustomerData> customerData1 = customerDataTemp.get(cusName);
            if (CollectionUtils.isEmpty(customerData1)) {
                continue;
            }
            if (customerData1.size() == 1) {
                //表示用户唯一的
                customerData.add(customerData1.get(0));
            } else {
                //表示用户可能包含多个监测点号，需要进行数据累加
                CustomerData customerDataT = new CustomerData();
                customerDataT.setCustomerName(cusName);
                customerDataT.setTimeDatas(customerData1.get(0).getTimeDatas());
                //进行数值累加
                List<Float> valueDatas = new ArrayList<>();
                for (int i = 0; i < customerData1.get(0).getValueDatas().size(); i++) {
                    float original = 0.0f;
                    for (int k = 0; k < customerData1.size(); k++) {
                        original = original + customerData1.get(k).getValueDatas().get(i);
                    }
                    valueDatas.add(original);
                }
                customerDataT.setValueDatas(valueDatas);
                customerData.add(customerDataT);
            }
        }
        result.setDatas(customerData);
        result.setResponsibilities(customerResponsibilities);
        //此次的操作进行入库操作responsibilityData表数据
        //根据监测点索引获取供电公司名、变电站名、装置名称、ip、监测点名称
        ResponsibilityData responsibilityData = lineMapper.queryByLineIndex(lineIndex);
        if (null == responsibilityData) {
            throw new UserDataException("监测点信息非法");
        }
        //根据监测点名称+谐波框选的时间来查询，是否做过责任量化
        String timeWin = PubUtils.date2String(startTime, "yyyyMMdd") + "-" + PubUtils.date2String(endTime, "yyyyMMdd");
        type = type.equalsIgnoreCase("vol") ? "谐波电压" : "谐波电流";
        //为了避免有监测点名称重复的，最终还是选择使用监测点索引来判断唯一性
        List<ResponsibilityData> responsibilityDataTemp = responsibilityDataMapper.selectData(lineIndex.toString(), userExcelData.getExcelName(), timeWin, type);
        if (CollectionUtils.isEmpty(responsibilityDataTemp)) {
            //库中没有记录则可以新建数据进行插入
            responsibilityData.setResIndex(UUID.randomUUID().toString());
            responsibilityData.setResTimes(time.toString());
            responsibilityData.setResType(type);
            responsibilityData.setTimeWin(timeWin);
            responsibilityData.setUserData(userExcelData.getExcelName());
            responsibilityData.setUpdateTime(new Date());
            //进行插入操作
            responsibilityDataMapper.insert(responsibilityData);
        } else {
            //库中存在记录只需要判断次数进行数据更新
            responsibilityData = responsibilityDataTemp.get(0);
            responsibilityData.setUpdateTime(new Date());
            String times = responsibilityData.getResTimes();
            if (!times.contains(time.toString())) {
                times = times + "," + time;
                String[] split = times.split(",");
                Integer[] timesSplit = new Integer[split.length];
                for (int i = 0; i < split.length; i++) {
                    timesSplit[i] = Integer.parseInt(split[i]);
                }
                Arrays.sort(timesSplit);
                String timeTemp = timesSplit[0] + "";
                for (int i = 1; i < timesSplit.length; i++) {
                    timeTemp = timeTemp + "," + timesSplit[i];
                }
                responsibilityData.setResTimes(timeTemp);
            }
            //执行更新操作
            responsibilityDataMapper.updateByPrimaryKey(responsibilityData);
        }
        //入库完毕之后，需要将必要数据进行序列化存储，方便后期的重复利用
        /**
         * 需要序列化三种数据结构 1 cal_flag置为1时需要的一些列参数的CacheQvvrData 2 cal_flag为0时的，动态结果。3 用户责任量化结果
         * 其中1/2都只需要一个文件即可
         * 3因为用户限值的变化调整，可能存在很多个文件，具体根绝用户的选择而定
         *
         * 路径的结构为，temPath+userData+excelName+type+timeWin+lineIndex+time+文件名
         *  用户责任量化结果，需要再细化到限值
         */
        String dynamicDataPath = appConfig.getTmppath() + File.separator + "userData" + File.separator + userExcelData.getExcelName() + File.separator + type + File.separator + timeWin + File.separator + lineIndex + File.separator + time + File.separator + 0.0 + "_" + PubUtils.date2String(startTime, "yyyyMMddHHmmss") + "_" + PubUtils.date2String(endTime, "yyyyMMddHHmmss") + "_dynamic.txt";
        PubUtils.createFile(dynamicDataPath);
        //将动态结果序列化到本地磁盘
        try (FileOutputStream fos = new FileOutputStream(dynamicDataPath); ObjectOutputStream oos = new ObjectOutputStream(
                fos)) {
            oos.writeObject(customerData);
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
        //总数据序列化
        CacheQvvrData cacheQvvrData = new CacheQvvrData();
        cacheQvvrData.setpNode(qvvrStruct.getP_node());
        cacheQvvrData.setHarmNum(qvvrStruct.getHarm_num());
        cacheQvvrData.setHarmData(qvvrStruct.getHarm_data());
        cacheQvvrData.setFKdata(qvvrStruct.FKdata);
        cacheQvvrData.setHKdata(qvvrStruct.HKdata);
        cacheQvvrData.setNames(names);
        cacheQvvrData.setWin(qvvrStruct.win);
        cacheQvvrData.setMinMultiple(userIntervalTime);
        cacheQvvrData.setTimes(harmTime);
        String cacheQvvrDataPath = appConfig.getTmppath() + File.separator + "userData" + File.separator + userExcelData.getExcelName() + File.separator + type + File.separator + timeWin + File.separator + lineIndex + File.separator + time + File.separator + "cacheQvvrData.txt";
        PubUtils.createFile(cacheQvvrDataPath);
        //将动态结果序列化到本地磁盘
        try (FileOutputStream fos = new FileOutputStream(cacheQvvrDataPath); ObjectOutputStream oos = new ObjectOutputStream(
                fos)) {
            oos.writeObject(cacheQvvrData);
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
        //此次的用户责任量化结果序列化，此处要按类型、次数、时间窗口、监测点、限值等来做唯一文件控制
        String responsbilityDataPath = appConfig.getTmppath() + File.separator + "userData" + File.separator + userExcelData.getExcelName() + File.separator + type + File.separator + timeWin + File.separator + lineIndex + File.separator + time + File.separator + 0.0 + "_" + PubUtils.date2String(startTime, "yyyyMMddHHmmss") + "_" + PubUtils.date2String(endTime, "yyyyMMddHHmmss") + "_responsbilityData.txt";
        PubUtils.createFile(responsbilityDataPath);
        //因为原实体实现了comparable接口，导致序列化失败，需要转换实体，其实内部结构是一致的
        List<CustomerResponsibilitySeri> customerResponsibilitySeris = convertResponsibilityData(customerResponsibilities);
        try (FileOutputStream fos = new FileOutputStream(responsbilityDataPath); ObjectOutputStream oos = new ObjectOutputStream(
                fos)) {
            oos.writeObject(customerResponsibilitySeris);
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
        //防止过程中创建了大量的对象，主动调用下GC处理
        System.gc();
        result.setResponsibilityDataIndex(responsibilityData.getResIndex());
        return result;
    }


    /**
     * 转换实体类，方便序列化到本地
     *
     * @param customerResponsibilities 原始数据
     */
    private List<CustomerResponsibilitySeri> convertResponsibilityData(List<CustomerResponsibility> customerResponsibilities) {
        List<CustomerResponsibilitySeri> customerResponsibilitySeris = new ArrayList<>();
        if (CollectionUtils.isEmpty(customerResponsibilities)) {
            return customerResponsibilitySeris;
        }
        for (CustomerResponsibility customerResponsibility : customerResponsibilities) {
            CustomerResponsibilitySeri temp = new CustomerResponsibilitySeri();
            temp.setCustomerName(customerResponsibility.getCustomerName());
            temp.setResponsibilityData(customerResponsibility.getResponsibilityData());
            customerResponsibilitySeris.add(temp);
        }
        return customerResponsibilitySeris;
    }

    /**
     * 通过监测点测量间隔计算对齐后的谐波数据
     * 暂且认为最小公倍数就15、30两种可能
     *
     * @param historyData 原始的谐波数据
     * @param lineInteval 测量间隔
     */
    private List<Responsibility> getDataWithLineInterval(List<Responsibility> historyData, int lineInteval) {
        List<Responsibility> result = new ArrayList<>();
        //先按行时间排序
        Collections.sort(historyData);
        switch (lineInteval) {
            case 1:
                result = getHarmResultByTimes(historyData, 15);
                break;
            case 3:
                result = getHarmResultByTimes(historyData, 5);
                break;
            case 5:
                result = getHarmResultByTimes(historyData, 3);
                break;
            case 10:
                result = getHarmResultByTimes(historyData, 3);
                break;
        }
        Collections.sort(result);
        return result;
    }

    /**
     * 通过监测点测量间隔计算对齐后的谐波数据
     *
     * @param historyData 原始的谐波数据
     */
    private List<Responsibility> getHarmResultByTimes(List<Responsibility> historyData, int times) {
        List<Responsibility> result = new ArrayList<>();
        DecimalFormat decimalFormat = new DecimalFormat("0.0000");
        for (int i = 0; i < historyData.size(); i = i + times) {
            float temp = 0.0f;
            for (int j = 0; j < times; j++) {
                int index = i + j;
                temp = temp + historyData.get(index).getValue();
            }
            //求平均值
            temp = Float.valueOf(decimalFormat.format(temp / new Float(times)));
            Responsibility resTemp = new Responsibility();
            resTemp.setTime(historyData.get(i).getTime());
            resTemp.setValue(temp);
            result.add(resTemp);
        }
        return result;
    }

    /**
     * 监测点测量间隔获取最后用于计算的功率数据
     *
     * @param finalData   参数计算的功率数据
     * @param lineInteval 监测点测量间隔
     */
    private Map<String, Map<String, List<UserDataExcelBody>>> dealFinalDataByLineInterval(Map<String, Map<String, List<UserDataExcelBody>>> finalData, int lineInteval) {
        DecimalFormat decimalFormat = new DecimalFormat("0.0000");
        Map<String, Map<String, List<UserDataExcelBody>>> result;
        //当监测点测量间隔为10分钟时，功率数据需要调整为30分钟数据
        result = new HashMap<>();
        Set<String> userNames = finalData.keySet();
        for (String userName : userNames) {
            Map<String, List<UserDataExcelBody>> temp = new HashMap<>();
            Map<String, List<UserDataExcelBody>> original = finalData.get(userName);
            Set<String> dates = original.keySet();
            for (String date : dates) {
                List<UserDataExcelBody> single = original.get(date);//某当天的数据
                //先根据事时间排序
                Collections.sort(single);
                //此时根据当天所有的数据，重新计算出所有时间点的数据，担心这个过程会消耗过长时间
                List<UserDataExcelBody> tempDatas = new ArrayList<>();
                for (int i = 0; i < 96; i = i + 2) {
                    //30分钟内的2个15分钟功率数据相加作平均计算30分钟内的功率数据，最终的数据序列时间间隔30分钟。by 友谊文档
                    UserDataExcelBody tempData = new UserDataExcelBody();
                    tempData.setUserName(single.get(i).getUserName());
                    tempData.setUserId(single.get(i).getUserId());
                    tempData.setLine(single.get(i).getLine());
                    tempData.setTime(single.get(i).getTime());
                    //功率为 2个15分钟功率数据相加作平均
                    double work = single.get(i).getWork().doubleValue() + single.get(i + 1).getWork().doubleValue();
                    tempData.setWork(new BigDecimal(decimalFormat.format(work / 2.0)));
                    tempDatas.add(tempData);
                }
                temp.put(date, tempDatas);
            }
            result.put(userName, temp);
        }
        return result;
    }


    /**
     * 根据谐波数据和动态责任数据获取动态数据以及责任量化值
     *
     * @param startTime  起始时间
     * @param endTime    截止时间
     * @param time       次数
     * @param limitValue 限值作为门槛使用
     * @param limitS     限值起始时间点
     * @param limitE     限值结束时间点
     */
    @Override
    public ResponsibilityResult getDynamicDataAndResponsibiltyByFkData(Date startTime, Date endTime, Integer time, float limitValue, Date limitS, Date limitE, String responsibilityIndex) throws Exception {
        ResponsibilityResult result = new ResponsibilityResult();
        List<String> dateStr = PubUtils.getTimes(startTime, endTime);
        //根据时间天数，获取理论上多少次用采数据
        ResponsibilityData responsibilityData = new ResponsibilityData();
        responsibilityData.setResIndex(responsibilityIndex);
        responsibilityData = responsibilityDataMapper.selectByPrimaryKey(responsibilityData);
        if (null == responsibilityData) {
            throw new UserDataException("库中没有责任列表记录存在");
        }
        //获取总数据
        String cacheQvvrDataPath = appConfig.getTmppath() + File.separator + "userData" + File.separator + responsibilityData.getUserData() + File.separator + responsibilityData.getResType() + File.separator + responsibilityData.getTimeWin() + File.separator + responsibilityData.getLineIndex() + File.separator + time + File.separator + "cacheQvvrData.txt";
        File cacheQvvrDataFile = new File(cacheQvvrDataPath);
        CacheQvvrData cacheQvvrData;
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(cacheQvvrDataFile))) {
            cacheQvvrData = (CacheQvvrData) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            throw new UserDataException("获取第一次处理后的总数据为空");
        }
        if (null == cacheQvvrData) {
            throw new UserDataException("获取第一次处理后的总数据为空");
        }
        //获取成功后，延长该缓存的生命周期为初始生命时长
        int win = cacheQvvrData.getWin();
        //不管窗口为4或者96，都需要考虑最小公倍数
        //最小公倍数根据监测点测量间隔来获取，可以考虑也由第一步操作缓存起来
        int minMultiple = cacheQvvrData.getMinMultiple();
        //谐波横轴所有的时间
        List<Long> times = cacheQvvrData.getTimes();
        //首先根据窗口判断限值时间范围是否满足最小窗口
        Long limitSL = limitS.getTime();
        Long limitEL = limitE.getTime();
        List<Integer> temp = getTimes(times, limitSL, limitEL);
        //在动态责任数据中，时间的起始索引位置和截止索引位置
        Integer timeStartIndex = temp.get(0);
        Integer timeEndIndex = temp.get(1);
        //间隔中的时间长度
        int minus = timeEndIndex - timeStartIndex + 1;
        //组装参数
        QvvrStruct qvvrStruct = new QvvrStruct();
        qvvrStruct.cal_flag = 1;
        qvvrStruct.p_node = cacheQvvrData.getpNode();
        qvvrStruct.harm_mk = limitValue;
        qvvrStruct.win = win;
        int resNum;
        PDataStruct[] FKdata = new PDataStruct[9600];
        HKDataStruct[] HKdata = new HKDataStruct[9600];
        float[] harmData = new float[1440 * 100];
        PDataStruct[] fKdataOriginal = cacheQvvrData.getFKdata();
        HKDataStruct[] hKdataOriginal = cacheQvvrData.getHKdata();
        float[] harmDataOriginal = cacheQvvrData.getHarmData();
        //如果起始索引与截止索引的差值等于时间轴的长度，则说明用户没有选择限值时间，直接带入全部的原始数据，参与计算即可
        if (minus == times.size()) {
            qvvrStruct.harm_num = cacheQvvrData.getHarmNum();
            qvvrStruct.res_num = cacheQvvrData.getHarmNum() - cacheQvvrData.getWin();
            qvvrStruct.setFKdata(cacheQvvrData.getFKdata());
            qvvrStruct.setHKdata(cacheQvvrData.getHKdata());
            qvvrStruct.harm_data = cacheQvvrData.getHarmData();
        } else {
            if (win == 4) {
                //当窗口为4时,两个时间限制范围在最小公倍数为15时，最起码有5个有效时间点，在最小公倍数为30时，最起码有3个有效时间点
                if (minMultiple == 15) {
                    if (minus < 5) {
                        throw new UserDataException("限值时间小于窗口");
                    }
                    resNum = minus - 4;

                } else if (minMultiple == 30) {
                    if (minus < 3) {
                        throw new UserDataException("限值时间小于窗口");
                    }
                    resNum = minus - 2;
                } else {
                    throw new UserDataException("对齐计算间隔值非法");
                }
            } else if (win == 96) {
                //当窗口为96时,两个时间限值范围在最小公倍数为15时，最起码有97个有效时间点，在最小公倍数为30时，最起码有49个有效时间点
                if (minMultiple == 15) {
                    if (minus < 97) {
                        throw new UserDataException("限值时间小于窗口");
                    }
                    resNum = minus - 96;
                } else if (minMultiple == 30) {
                    if (minus < 49) {
                        throw new UserDataException("限值时间小于窗口");
                    }
                    resNum = minus - 48;
                } else {
                    throw new UserDataException("对齐计算间隔值非法");
                }
            } else {
                throw new UserDataException("窗口值非法");
            }
            qvvrStruct.res_num = resNum;
            qvvrStruct.harm_num = minus;
            //因为限值时间实际是含头含尾的，所以harmNum需要索引差值+1
            for (int i = timeStartIndex; i <= timeEndIndex; i++) {
                harmData[i - timeStartIndex] = harmDataOriginal[i];
            }
            qvvrStruct.harm_data = harmData;
            //FKData与HKData的值则等于resNum
            for (int i = timeStartIndex; i < timeStartIndex + resNum; i++) {
                FKdata[i - timeStartIndex] = fKdataOriginal[i];
                HKdata[i - timeStartIndex] = hKdataOriginal[i];
            }

            qvvrStruct.setFKdata(FKdata);
            qvvrStruct.setHKdata(HKdata);
        }
        qvvrStruct = getQvvrData.getResponsibilityResult(qvvrStruct);
        if (qvvrStruct.cal_ok == 0) {
            throw new UserDataException("调用接口程序计算失败，参数非法");
        }
        //没问题后，先玩动态责任数据
        List<String> names = cacheQvvrData.getNames();
        CustomerData[] customerDatas = new CustomerData[qvvrStruct.p_node];
        PDataStruct[] fKdata/*无背景的动态责任数据*/ = qvvrStruct.getFKdata();
        //第一个时间节点是起始时间+win窗口得到的时间
        Date sTime = new Date();
        sTime.setTime(times.get(timeStartIndex));
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(sTime);
        calendar.add(Calendar.MINUTE, (win - 1) * minMultiple);
        for (int i = 0; i < qvvrStruct.harm_num - qvvrStruct.win; i++) {
            calendar.add(Calendar.MINUTE, minMultiple);
            //一个时间点所有的用户数据
            PDataStruct fKdatum = fKdata[i];
            for (int k = 0; k < qvvrStruct.p_node; k++) {
                CustomerData customerData = customerDatas[k];
                if (null == customerData) {
                    customerData = new CustomerData();
                    customerData.setCustomerName(names.get(k));
                }
                List<Float> valueDatas = customerData.getValueDatas();
                Float valueTemp = fKdatum.getP()[k];
                if (valueTemp.isNaN()) {
                    valueTemp = 0.0f;
                }
                valueDatas.add(valueTemp);
                List<Long> timeDatas = customerData.getTimeDatas();
                timeDatas.add(calendar.getTimeInMillis());
                customerData.setValueDatas(valueDatas);
                customerData.setTimeDatas(timeDatas);
                customerDatas[k] = customerData;
            }
        }
        //OK拿到所有测量点的数据了，现在就是看如何将相同户号的动态数据进行算术和求值，之前的用户name为：户号@测量点号@用户名
        Map<String/*用户名（户号）*/, List<CustomerData>> customerDataTemp = new HashMap<>();
        for (int i = 0; i < customerDatas.length; i++) {
            String customerName = customerDatas[i].getCustomerName();
            String[] customerInfo = customerName.split("@");
            String name = customerInfo[2] + "(" + customerInfo[0] + ")";
            List<CustomerData> customerData = customerDataTemp.get(name);
            CustomerData customerTemp = customerDatas[i];
            customerTemp.setCustomerName(name);
            if (CollectionUtils.isEmpty(customerData)) {
                customerData = new ArrayList<>();
            }
            customerData.add(customerTemp);
            customerDataTemp.put(name, customerData);
        }
        //调用程序接口后，首先组装责任量化结果
        float[] sumFKdata = qvvrStruct.sumFKdata;
        List<CustomerResponsibility> customerResponsibilities = getCustomerResponsibilityData(names, sumFKdata, qvvrStruct.p_node);
        //根据前十的用户数据，获取这些用户的动态责任数据
        List<CustomerData> customerData = new ArrayList<>();
        for (CustomerResponsibility customerResponsibility : customerResponsibilities) {
            String cusName = customerResponsibility.getCustomerName();
            List<CustomerData> customerData1 = customerDataTemp.get(cusName);
            if (CollectionUtils.isEmpty(customerData1)) {
                continue;
            }
            if (customerData1.size() == 1) {
                //表示用户唯一的
                customerData.add(customerData1.get(0));
            } else {
                //表示用户可能包含多个监测点号，需要进行数据累加
                CustomerData customerDataT = new CustomerData();
                customerDataT.setCustomerName(cusName);
                customerDataT.setTimeDatas(customerData1.get(0).getTimeDatas());
                //进行数值累加
                List<Float> valueDatas = new ArrayList<>();
                for (int i = 0; i < customerData1.get(0).getValueDatas().size(); i++) {
                    float original = 0.0f;
                    for (int k = 0; k < customerData1.size(); k++) {
                        original = original + customerData1.get(k).getValueDatas().get(i);
                    }
                    valueDatas.add(original);
                }
                customerDataT.setValueDatas(valueDatas);
                customerData.add(customerDataT);
            }
        }
        //接着组装动态数据结果
        result.setResponsibilities(customerResponsibilities);
        result.setDatas(customerData);
        String dynamicDataPath = appConfig.getTmppath() + File.separator + "userData" + File.separator + responsibilityData.getUserData() + File.separator + responsibilityData.getResType() + File.separator + responsibilityData.getTimeWin() + File.separator + responsibilityData.getLineIndex() + File.separator + time + File.separator + limitValue + "_" + PubUtils.date2String(limitS, "yyyyMMddHHmmss") + "_" + PubUtils.date2String(limitE, "yyyyMMddHHmmss") + "_dynamic.txt";
        PubUtils.createFile(dynamicDataPath);
        //将动态结果序列化到本地磁盘
        try (FileOutputStream fos = new FileOutputStream(dynamicDataPath); ObjectOutputStream oos = new ObjectOutputStream(
                fos)) {
            oos.writeObject(customerData);
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
        //此次的用户责任量化结果序列化，此处要按类型、次数、时间窗口、监测点、限值等来做唯一文件控制
        String responsbilityDataPath = appConfig.getTmppath() + File.separator + "userData" + File.separator + responsibilityData.getUserData() + File.separator + responsibilityData.getResType() + File.separator + responsibilityData.getTimeWin() + File.separator + responsibilityData.getLineIndex() + File.separator + time + File.separator + limitValue + "_" + PubUtils.date2String(limitS, "yyyyMMddHHmmss") + "_" + PubUtils.date2String(limitE, "yyyyMMddHHmmss") + "_responsbilityData.txt";
        PubUtils.createFile(responsbilityDataPath);
        //因为原实体实现了comparable接口，导致序列化失败，需要转换实体，其实内部结构是一致的
        List<CustomerResponsibilitySeri> customerResponsibilitySeris = convertResponsibilityData(customerResponsibilities);
        try (FileOutputStream fos = new FileOutputStream(responsbilityDataPath); ObjectOutputStream oos = new ObjectOutputStream(
                fos)) {
            oos.writeObject(customerResponsibilitySeris);
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
        return result;
    }

    /**
     * 获取计算时间范围内的谐波责任数据
     *
     * @param startTime 起始时间
     * @param endTime   截止时间
     */
    @Override
    public List<ResponsibilityData> responsibilityDataList(Date startTime, Date endTime) {
        return responsibilityDataMapper.responsibilityDataList(startTime, endTime);
    }

    /**
     * 根据索引返回责任计算结果
     */
    @Override
    public ResponsibilityData selectByIndex(String resIndex) {
        ResponsibilityData responsibilityData = new ResponsibilityData();
        responsibilityData.setResIndex(resIndex);
        return responsibilityDataMapper.selectOne(responsibilityData);
    }

    /**
     * 获取历史动态数据和责任数据显示
     *
     * @param time     谐波次数
     * @param resIndex 责任计算列表对应索引
     */
    @Override
    public List<ResponsibilityResult> displayHistoryData(Integer time, String resIndex) throws Exception {
        List<ResponsibilityResult> responsibilityResults = new ArrayList<>();
        ResponsibilityData responsibilityData = new ResponsibilityData();
        responsibilityData.setResIndex(resIndex);
        responsibilityData = responsibilityDataMapper.selectOne(responsibilityData);
        if (null == responsibilityData) {
            throw new UserDataException("责任计算数据为空");
        }
        //开始获取所有的文件
        String dirPath = appConfig.getTmppath() + File.separator + "userData" + File.separator + responsibilityData.getUserData() + File.separator + responsibilityData.getResType() + File.separator + responsibilityData.getTimeWin() + File.separator + responsibilityData.getLineIndex() + File.separator + time;
        File dir = new File(dirPath);
        //获取出下面的所有的文件
        File[] files = dir.listFiles();
        //依次获取各个文件的名称
        Map<String, List<File>> fileMap = new HashMap<>();
        for (File file : files) {
            String name = file.getName();
            if (name.contains("_")) {
                //包含这个符号，说明是动态数据或者责任数据
                String prefixx = name.substring(0, name.lastIndexOf("_"));
                List<File> filesTemp = fileMap.get(prefixx);
                if (CollectionUtils.isEmpty(filesTemp)) {
                    filesTemp = new ArrayList<>();
                }
                filesTemp.add(file);
                fileMap.put(prefixx, filesTemp);
            }
        }
        //筛选完毕后开始组装前台需要数据
        if (CollectionUtils.isEmpty(fileMap)) {
            throw new UserDataException("历史责任数据为空");
        }
        //ResponsibilityResult
        Set<String> prefixs = fileMap.keySet();
        for (String prefix : prefixs) {
            List<File> filesTemp = fileMap.get(prefix);
            if (filesTemp.size() == 2) {
                ResponsibilityResult result = new ResponsibilityResult();
                //只有当长度为2时，才是合理的数据，一个动态数据，一个责任数据
                for (File file : filesTemp) {
                    if (file.getName().endsWith("dynamic.txt")) {
                        //说明是动态数据
                        List<CustomerData> customerData;
                        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
                            customerData = (List<CustomerData>) ois.readObject();
                        } catch (IOException | ClassNotFoundException e) {
                            throw new UserDataException("根据文件获取动态数据为空");
                        }
                        if (CollectionUtils.isEmpty(customerData)) {
                            throw new UserDataException("根据文件获取动态数据为空");
                        }
                        result.setDatas(customerData);
                    } else if (file.getName().endsWith("responsbilityData.txt")) {
                        //说明是谐波责任数据
                        List<CustomerResponsibilitySeri> customerResponsibilitySeris;
                        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
                            customerResponsibilitySeris = (List<CustomerResponsibilitySeri>) ois.readObject();
                        } catch (IOException | ClassNotFoundException e) {
                            throw new UserDataException("根据文件获取责任数据为空");
                        }
                        if (CollectionUtils.isEmpty(customerResponsibilitySeris)) {
                            throw new UserDataException("根据文件获取责任数据为空");
                        }
                        result.setResponsibilities(convertResponsibilityDataSeris(customerResponsibilitySeris));
                    }
                }
                if (CollectionUtils.isEmpty(result.getDatas()) || CollectionUtils.isEmpty(result.getResponsibilities())) {
                    continue;
                }
                //解析前缀
                String[] limit = prefix.split("_");
                result.setLimitValue(limit[0]);
                Date start = PubUtils.string2Date(limit[1], "yyyyMMddHHmmss");
                Date end = PubUtils.string2Date(limit[2], "yyyyMMddHHmmss");
                result.setLimitSTime(PubUtils.date2String(start, "yyyy-MM-dd HH:mm:ss"));
                result.setLimitETime(PubUtils.date2String(end, "yyyy-MM-dd HH:mm:ss"));
                responsibilityResults.add(result);
            }
        }
        return responsibilityResults;
    }

    /**
     * 根据索引删除记录以及对应的所有数据文件
     *
     * @param resIndex 责任列表索引
     */
    @Override
    public void deleteResponsibilityByResIndex(String resIndex) {
        ResponsibilityData responsibilityData = new ResponsibilityData();
        responsibilityData.setResIndex(resIndex);
        responsibilityData = responsibilityDataMapper.selectOne(responsibilityData);
        if (null != responsibilityData) {
            String responsbilityDataPath = appConfig.getTmppath() + File.separator + "userData" + File.separator + responsibilityData.getUserData() + File.separator + responsibilityData.getResType() + File.separator + responsibilityData.getTimeWin() + File.separator + responsibilityData.getLineIndex();
            responsibilityDataMapper.deleteByResIndex(resIndex);
            File dir = new File(responsbilityDataPath);
            FileUtil.cleanEmpty(dir);
            File baseDir = new File(appConfig + File.separator + "userData");
            FileUtil.cleanEmpty(baseDir);
        }
    }

    /**
     * 根据监测点获取指定条件的限值
     *
     * @param lineIndex 监测点索引
     * @param time      次数
     * @param type      干扰源类型
     */
    @Override
    public Float getLimitByTimeAndType(Integer lineIndex, Integer time, String type) {
        Float value;
        if (type.equalsIgnoreCase("vol")) {
            value = responsibilityDataMapper.getLimitU(lineIndex, time);
        } else {
            value = responsibilityDataMapper.getLimitI(lineIndex, time);
        }
        return value;
    }

    /**
     * 转换实体类，方便序列化到本地
     *
     * @param customerResponsibilitySeris 原始数据
     */
    private List<CustomerResponsibility> convertResponsibilityDataSeris(List<CustomerResponsibilitySeri> customerResponsibilitySeris) {
        List<CustomerResponsibility> customerResponsibilities = new ArrayList<>();
        if (CollectionUtils.isEmpty(customerResponsibilitySeris)) {
            return customerResponsibilities;
        }
        for (CustomerResponsibilitySeri customerResponsibilitySeri : customerResponsibilitySeris) {
            CustomerResponsibility temp = new CustomerResponsibility();
            temp.setCustomerName(customerResponsibilitySeri.getCustomerName());
            temp.setResponsibilityData(customerResponsibilitySeri.getResponsibilityData());
            customerResponsibilities.add(temp);
        }
        return customerResponsibilities;
    }

    /**
     * 根据接口返回值组装需要显示的责任量化数据
     *
     * @param sumFKdata
     */
    private List<CustomerResponsibility> getCustomerResponsibilityData(List<String> names, float[] sumFKdata, int pNode) {
        Map<String/*用户名（户号）*/, CustomerResponsibility> customerResponsibilityMap = new HashMap<>();
        for (int i = 0; i < pNode; i++) {
            String[] customerInfo = names.get(i).split("@");/*用户ID 测量点ID 用户名*/
            String name = customerInfo[2] + "(" + customerInfo[0] + ")";
            CustomerResponsibility customerResponsibility;
            if (customerResponsibilityMap.containsKey(name)) {
                customerResponsibility = customerResponsibilityMap.get(name);
                customerResponsibility.setResponsibilityData(customerResponsibility.getResponsibilityData() + sumFKdata[i]);
            } else {
                customerResponsibility = new CustomerResponsibility();
                customerResponsibility.setCustomerName(name);
                customerResponsibility.setResponsibilityData(sumFKdata[i]);
            }
            customerResponsibilityMap.put(name, customerResponsibility);
        }
        //map转为list
        List<CustomerResponsibility> customerResponsibilities = new ArrayList<>();
        Set<String> cusNames = customerResponsibilityMap.keySet();
        for (String cusName : cusNames) {
            customerResponsibilities.add(customerResponsibilityMap.get(cusName));
        }
        //取出前十的用户责任数据
        Collections.sort(customerResponsibilities);
        if (customerResponsibilities.size() > 10) {
            //当用户超出10，将前十用户保留，然后剩余归类为其他用户
            float tenTotal = 0.0f;
            for (int i = 0; i < 10; i++) {
                float temp = PubUtils.floatRound(3, customerResponsibilities.get(i).getResponsibilityData());
                tenTotal = tenTotal + temp;
            }
            int size = customerResponsibilities.size() - 10;
            customerResponsibilities = customerResponsibilities.subList(0, 10);
            CustomerResponsibility others = new CustomerResponsibility();
            others.setCustomerName("其他用户(" + size + ")");
            others.setResponsibilityData(PubUtils.floatRound(3, 100.0f - tenTotal));
            customerResponsibilities.add(others);
        }
        return customerResponsibilities;
    }

    /**
     * 根据起始时间获取在集合中最接近的起始和截止值
     *
     * @param times   时间集合
     * @param limitSL 起始值
     * @param limitEL 截止值
     */
    private List<Integer> getTimes(List<Long> times, Long limitSL, Long limitEL) {
        List<Integer> result = new ArrayList<>();
        Integer temps = null;
        Integer tempe = null;
        //因为可以知道times是为4的倍数，所以长度肯定是偶数，不会出现索引越界的异常
        if (limitSL < times.get(0)) {
            temps = 0;
        }
        if (limitEL > times.get(times.size() - 1)) {
            tempe = times.size() - 1;
        }
        for (int i = 0; i < times.size() - 1; i++) {
            if (temps != null & tempe != null) {
                //判断都已经赋值后，跳出循环
                break;
            }
            //锁定前值
            if (times.get(i).equals(limitSL)) {
                //相等则给起始时间赋值
                temps = i;
            } else if (times.get(i + 1).equals(limitSL)) {
                temps = i + 1;
            } else if (times.get(i) < limitSL & times.get(i + 1) > limitSL) {
                //当起始时间处于中间时，将后值赋值给temps
                temps = i + 1;
            }
            //锁定后值
            if (times.get(i).equals(limitEL)) {
                //相等则给起始时间赋值
                tempe = i;
            } else if (times.get(i + 1).equals(limitEL)) {
                tempe = i + 1;
            } else if (times.get(i) < limitEL & times.get(i + 1) > limitEL) {//
                //当起始时间处于中间时，将前值赋值给temps
                tempe = i;
            }
        }
        if (temps == null) {
            temps = 0;
        }
        if (tempe == null) {
            tempe = times.size() - 1;
        }
        result.add(temps);
        result.add(tempe);
        return result;
    }


    /**
     * 处理用采数据
     *
     * @param file 用采文件
     */
    @Override
    public String dealExcelData(MultipartFile file) throws Exception {
        String name = file.getOriginalFilename();
        UserExcelData userExcelData = getUserDatas(file.getInputStream(), name);
        Long startTime = new Date().getTime();
        if (userExcelData.getUpdateTime() == null) {
            throw new UserDataException("用采数据为空");
        } else {
            logger.error("耗时秒数为：" + (new Date().getTime() - startTime) / 1000);
            return "用采数据上传成功";
        }
    }


    /**
     * 根据流获取出用采有功功率数据
     */
    private UserExcelData getUserDatas(InputStream inputStream, String excelName) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<UserDataExcelBody> exportExcel = new ArrayList<>();
        List<UserDataExcelBody> userDataExcelBodies;
        if (excelName.endsWith(ExcelTypeEnum.XLS.getValue())) {
            userDataExcelBodies = extractData(inputStream, ExcelTypeEnum.XLS);
        } else {
            userDataExcelBodies = extractData(inputStream, ExcelTypeEnum.XLSX);
        }
        UserExcelData userExcelData = new UserExcelData();
        //判断数据提取情况
        if (CollectionUtils.isEmpty(userDataExcelBodies)) {
            return userExcelData;
        }

        //给海南造数据，数据偏移4个月。到12月
//        userDataExcelBodies.removeIf(userDataExcelBody -> userDataExcelBody.getUserName().equalsIgnoreCase("永嘉县山河供水有限公司"));
//        for (UserDataExcelBody userDataExcelBody : userDataExcelBodies) {
//            userDataExcelBody.setTime(DateUtil.offset(userDataExcelBody.getTime(), DateField.MONTH, 4));
//        }
        
        DealDataResult dealDataResult = getStanderData(userDataExcelBodies, sdf, 0);
        Map<String/*户号@监测点号@户名*/, Map<String/*yyyy-MM-dd天日期*/, Map<Date/*yyyy-MM-dd HH:mm:ss日期格式*/, UserDataExcelBody>>> totalData = dealDataResult.getTotalData();
        //收集所有的日期，以便获取起始日期和截止日期
        List<String> dates = dealDataResult.getDates();
        //将前面获取出来的日期进行排序，提供入库
        List<Date> resultDates = getSortDate(dates);
        Date endTime = resultDates.get(resultDates.size() - 1);
        Date startTime = resultDates.get(0);

        //针对每个用户的数据进行完整度的判断 todo 暂且认为所有用户的时间跨度是一样的，比如都是15天或者都是30天，不存在有的用户5天数据，有的用户10天数据
        Map<String, List<UserDataExcelBody>> tempResult = new HashMap<>();
        List<UserExcelDataNoIntegrity> noIntegrities = new ArrayList<>();
        Set<String> userNames = totalData.keySet();
        for (String name : userNames) {
            Map<String, Map<Date, UserDataExcelBody>> userDataTemp = totalData.get(name);
            //现在数据拿到了，但是因为是hashkey，所以日期顺序是乱的-->怎么变成有序的呢
            Set<String> times = userDataTemp.keySet();
            for (String time : times) {
                DealUserDataResult dealedData = dealUserData(name, userDataTemp.get(time), time, 15);
                List<UserDataExcelBody> userDataExcelBodyTemp = dealedData.getCompleted();
                List<UserDataExcelBody> userDataExcelBody;
                if (CollectionUtils.isEmpty(userDataExcelBodyTemp) && dealedData.getUserExcelDataNoIntegrity() != null) {
                    //为空，说明补齐操作没有进行，选择填充缺失数据即可
                    noIntegrities.add(dealedData.getUserExcelDataNoIntegrity());
                    userDataExcelBody = dealedData.getLack();
                } else {
                    //填充补齐完整性后的数据
                    userDataExcelBody = userDataExcelBodyTemp;
                }
                List<UserDataExcelBody> userDatas = tempResult.get(name);
                if (!CollectionUtils.isEmpty(userDataExcelBody)) {
                    if (CollectionUtils.isEmpty(userDatas)) {
                        userDatas = new ArrayList<>(userDataExcelBody);
                    } else {
                        userDatas.addAll(userDataExcelBody);
                    }
                }

                tempResult.put(name, userDatas);
            }
        }
        //完成后，开始将数据按公司排序，然后输出到指定表格中，方便下次使用
        for (String name : userNames) {
            List<UserDataExcelBody> tempUserData = tempResult.get(name);
            //按时间排序
            Collections.sort(tempUserData);
            exportExcel.addAll(tempUserData);
        }
        //输出到报表中
        String fileNameWithOutSuffix = excelName.substring(0, excelName.indexOf('.'));
        String dateFolder = PubUtils.date2String(startTime, "yyyyMMdd") + "-" + PubUtils.date2String(endTime, "yyyyMMdd");
        fileNameWithOutSuffix = fileNameWithOutSuffix + dateFolder;
        String path = appConfig.getTmppath() + File.separator + "userData" + File.separator + fileNameWithOutSuffix + ".xlsx";
        // 定义表的标题
        String title = "用采数据";
        //定义表的列名
        String[] rowsName = new String[]{"时间", "瞬时功率", "户号", "测量点局号", "户名"};
        // 创建ExportExcel对象
        UserDataExcelUtil excelUtil1 = new UserDataExcelUtil();
        try {
            excelUtil1.exportExcel(title, rowsName, exportExcel, path);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        //入库前进行查询操作，存在则更新，不存在则插入

        userExcelData = userExcelDataMapper.selectUserExcelData(fileNameWithOutSuffix, startTime, endTime);
        //不存在则插入
        if (null == userExcelData) {
            userExcelData = new UserExcelData();
            userExcelData.setEndTime(endTime);
            userExcelData.setStartTime(startTime);
            String excelIndex = UUID.randomUUID().toString();
            userExcelData.setExcelIndex(excelIndex);
            userExcelData.setExcelName(fileNameWithOutSuffix);
            userExcelData.setExcelPath(path);
            userExcelData.setUpdateTime(new Date());
            if (!CollectionUtils.isEmpty(noIntegrities)) {
                //关联插入数据 户号，监测点号，户名，时间，完整性
                for (UserExcelDataNoIntegrity userExcelDataNoIntegrity :
                        noIntegrities) {
                    userExcelDataNoIntegrity.setExcelIndex(excelIndex);
                }
                //插入操作
                userExcelDataNoIntegrityMapper.insertAll(noIntegrities);
                userExcelData.setLackIntegrity(1);
            } else {
                userExcelData.setLackIntegrity(0);
            }
            try {
                userExcelDataMapper.insert(userExcelData);
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        } else {
            //存在则更新
            userExcelData.setUpdateTime(new Date());
            if (!CollectionUtils.isEmpty(noIntegrities)) {
                //先删除之前所有的，然后在批量插入完整性不足数据
                String tempIndex = userExcelData.getExcelIndex();
                jedisManager.saveValueByKey(RedisDB.SHORT_TIME_QUERY, "shortResponsibility", tempIndex, RedisDB.SHORT_TIME);
                String suoyin = jedisManager.getValueByKey(RedisDB.SHORT_TIME_QUERY, "shortResponsibility");
                jedisManager.deleteByKey(RedisDB.SHORT_TIME_QUERY, "shortResponsibility");
                userExcelDataNoIntegrityMapper.deleteByExcelIndex(suoyin);
                for (UserExcelDataNoIntegrity userExcelDataNoIntegrity :
                        noIntegrities) {
                    userExcelDataNoIntegrity.setExcelIndex(suoyin);
                }
                //批量插入
                userExcelDataNoIntegrityMapper.insertAll(noIntegrities);
                userExcelData.setLackIntegrity(1);
            } else {
                userExcelData.setLackIntegrity(0);
            }
            try {
                userExcelDataMapper.updateByPrimaryKey(userExcelData);
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        }
        return userExcelData;
    }


    /**
     * 从文件流中提取用采数据
     *
     * @param inputStream 文件流
     */
    private List<UserDataExcelBody> extractData(InputStream inputStream, ExcelTypeEnum excelTypeEnum) {
        List<UserDataExcelBody> userDataExcelBodies = new ArrayList<>();
        try {
            ExcelReader reader = new ExcelReader(inputStream, excelTypeEnum, null,
                    new AnalysisEventListener() {
                        @Override
                        public void invoke(Object object, AnalysisContext context) {
                            UserDataExcelBody obj = (UserDataExcelBody) object;
                            userDataExcelBodies.add(obj);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext context) {
                        }
                    }, true);
            List<Sheet> sheets = reader.getSheets();
            for (Sheet sheet : sheets) {
                reader.read(sheet, UserDataExcelBody.class);
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                logger.error(e.getMessage());
            }
        }
        return userDataExcelBodies;
    }


    /**
     * 解析用采数据为一个标准格式
     */
    private DealDataResult getStanderData(List<UserDataExcelBody> userDataExcelBodies, SimpleDateFormat sdf, int flag) {
        DealDataResult result = new DealDataResult();
        //收集所有的日期，以便获取起始日期和截止日期
        List<String> dates = new ArrayList<>();
        Map<String, Map<String, Map<Date, UserDataExcelBody>>> totalData = new HashMap<>();
        Map<String, Map<String, List<UserDataExcelBody>>> totalListData = new HashMap<>();
        for (UserDataExcelBody userDataExcelBody : userDataExcelBodies) {
            //第一个key
            String key = userDataExcelBody.getUserId() + "@" + userDataExcelBody.getLine() + "@" + userDataExcelBody.getUserName();
            String time = sdf.format(userDataExcelBody.getTime());
            if (!dates.contains(time)) {
                dates.add(time);
            }
            if (!totalData.containsKey(key)) {
                if (flag == 0) {
                    //Map形式，避免后面补齐数据嵌套循环
                    Map<Date, UserDataExcelBody> userDatas = new HashMap<>();
                    userDatas.put(PubUtils.getSecondsAsZero(userDataExcelBody.getTime()), userDataExcelBody);
                    Map<String, Map<Date, UserDataExcelBody>> dataToUserDatas = new HashMap<>();
                    dataToUserDatas.put(time, userDatas);
                    totalData.put(key, dataToUserDatas);
                } else if (flag == 1) {
                    //List形式,避免后面责任数据提取嵌套循环
                    List<UserDataExcelBody> userListDatas = new ArrayList<>();
                    userListDatas.add(userDataExcelBody);
                    Map<String, List<UserDataExcelBody>> dataToUserListDatas = new HashMap<>();
                    dataToUserListDatas.put(time, userListDatas);
                    totalData.put(key, new HashMap<>());
                    totalListData.put(key, dataToUserListDatas);
                }
            } else {
                if (flag == 0) {
                    //Map形式，避免后面补齐数据嵌套循环
                    Map<String, Map<Date, UserDataExcelBody>> dataToUserDatas = totalData.get(key);
                    Map<Date, UserDataExcelBody> userDatas = dataToUserDatas.get(time);
                    if (CollectionUtils.isEmpty(userDatas)) {
                        userDatas = new HashMap<>();
                        userDatas.put(PubUtils.getSecondsAsZero(userDataExcelBody.getTime()), userDataExcelBody);
                        dataToUserDatas.put(time, userDatas);
                    } else {
                        userDatas.put(PubUtils.getSecondsAsZero(userDataExcelBody.getTime()), userDataExcelBody);
                        dataToUserDatas.put(time, userDatas);
                    }
                    totalData.put(key, dataToUserDatas);
                } else if (flag == 1) {
                    //List形式,避免后面责任数据提取嵌套循环
                    Map<String, List<UserDataExcelBody>> dataToUserListDatas = totalListData.get(key);
                    List<UserDataExcelBody> userListDatas = dataToUserListDatas.get(time);
                    if (CollectionUtils.isEmpty(userListDatas)) {
                        userListDatas = new ArrayList<>();
                        userListDatas.add(userDataExcelBody);
                        dataToUserListDatas.put(time, userListDatas);
                    } else {
                        userListDatas.add(userDataExcelBody);
                        dataToUserListDatas.put(time, userListDatas);
                    }
                    totalListData.put(key, dataToUserListDatas);
                }
            }

        }
        result.setDates(dates);
        result.setTotalData(totalData);
        result.setTotalListData(totalListData);
        return result;
    }


    /**
     * 将日期排序后返回
     */
    private List<Date> getSortDate(List<String> dates) throws Exception {
        List<Date> result = new ArrayList<>();
        for (String date :
                dates) {
            Date temp = PubUtils.string2Date(date, "yyyy-MM-dd");
            result.add(temp);
        }
        if (!CollectionUtils.isEmpty(result)) {
            Collections.sort(result);
        }
        return result;
    }

    /**
     * 处理用户每日数据
     *
     * @param name       用户名
     * @param beforeDeal 处理前的用户数据
     */
    private DealUserDataResult dealUserData(String name, Map<Date, UserDataExcelBody> beforeDeal, String time, int step) throws Exception {
        DealUserDataResult result = new DealUserDataResult();
        String[] userFlag = name.split("@");
        //每天的最开是的数据是从00:00:00开始的，所以起始时间为time + 00:00:00
        List<UserDataExcelBody> completed = new ArrayList<>();
        List<UserDataExcelBody> lack = new ArrayList<>();
        if (CollectionUtils.isEmpty(beforeDeal)) {
            return result;
        } else {
            String timeTemp = time + " 00:00:00";
            Date date = PubUtils.string2Date(timeTemp, "yyyy-MM-dd HH:mm:ss");
            int count = 24 * 60 / 15;
            if (new Float(beforeDeal.size()) / new Float(count) < 0.9) {
                Set<Date> dates = beforeDeal.keySet();
                for (Date tempDate :
                        dates) {
                    UserDataExcelBody userDataExcelBody = beforeDeal.get(tempDate);
                    if (userDataExcelBody.getWork() != null) {
                        lack.add(userDataExcelBody);
                    }
                }
                DecimalFormat decimalFormat = new DecimalFormat("0.0000");
                UserExcelDataNoIntegrity userExcelDataNoIntegrity = new UserExcelDataNoIntegrity();
                userExcelDataNoIntegrity.setExcelIndex("");
                userExcelDataNoIntegrity.setIntergrity(decimalFormat.format((double) lack.size() / 96.0));
                userExcelDataNoIntegrity.setLackDate(time);
                userExcelDataNoIntegrity.setIntergrityIndex(UUID.randomUUID().toString());
                userExcelDataNoIntegrity.setUserName(userFlag[2]);
                userExcelDataNoIntegrity.setLineNo(userFlag[1]);
                userExcelDataNoIntegrity.setUserNo(userFlag[0]);
                result.setLack(lack);
                result.setUserExcelDataNoIntegrity(userExcelDataNoIntegrity);
                return result;
            } else {
                for (int i = 0; i < count; i++) {
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(date);
                    calendar.add(Calendar.MINUTE, step * i);
                    UserDataExcelBody userDataExcelBody = beforeDeal.get(calendar.getTime());
                    if (userDataExcelBody != null && userDataExcelBody.getWork() != null) {
                        completed.add(userDataExcelBody);
                    } else {
                        //找到前一个时间点值
                        Float perValue = getPreValue(date, calendar.getTime(), beforeDeal);
                        //找到后一个时间点值
                        Float appendValue = getAppendValue(date, count, step, calendar.getTime(), beforeDeal);
                        UserDataExcelBody temp = new UserDataExcelBody();
                        temp.setTime(calendar.getTime());
                        temp.setUserId(userFlag[0]);
                        temp.setLine(userFlag[1]);
                        temp.setUserName(userFlag[2]);
                        //还需要判断前值和后值为空的情况
                        if (null == perValue && null == appendValue) {
                            temp.setWork(new BigDecimal(0.0));
                        } else if (null == perValue) {
                            temp.setWork(new BigDecimal(appendValue));
                        } else if (null == appendValue) {
                            temp.setWork(new BigDecimal(perValue));
                        } else {
                            temp.setWork(new BigDecimal((perValue + appendValue) / 2));
                        }
                        completed.add(temp);
                    }
                }
            }
        }
        result.setCompleted(completed);
        return result;
    }

    /**
     * 递归找前值
     *
     * @param date       起始时间
     * @param time       当前事件
     * @param beforeDeal 处理前的数据
     */
    private Float getPreValue(Date date, Date time, Map<Date, UserDataExcelBody> beforeDeal) {
        Float result;
        if (date.equals(time)) {
            return null;
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(time);
            calendar.add(Calendar.MINUTE, -15);
            UserDataExcelBody temp = beforeDeal.get(calendar.getTime());
            if (temp == null || temp.getWork() == null) {
                result = getPreValue(date, calendar.getTime(), beforeDeal);
            } else {
                result = temp.getWork().floatValue();
            }
        }
        return result;
    }

    /**
     * 递归找后置
     *
     * @param date  起始时间
     * @param count 一天时间的总计数
     * @param step  间隔分钟
     * @param time  截止时间
     */
    private Float getAppendValue(Date date, int count, int step, Date time, Map<Date, UserDataExcelBody> beforeDeal) {
        Float result;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MINUTE, (count - 1) * step);
        if (time.equals(calendar.getTime())) {
            return null;
        } else {
            Calendar calendar1 = Calendar.getInstance();
            calendar1.setTime(time);
            calendar1.add(Calendar.MINUTE, 15);
            UserDataExcelBody temp = beforeDeal.get(calendar1.getTime());
            if (temp == null || temp.getWork() == null) {
                result = getAppendValue(date, count, step, calendar1.getTime(), beforeDeal);
            } else {
                result = temp.getWork().floatValue();
            }
        }
        return result;
    }

}
