package com.energy.manage.service.service.analysis.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson.JSONArray;
import com.energy.manage.common.base.Page;
import com.energy.manage.common.constant.redis.ManagerRedisKeyConstant;
import com.energy.manage.common.enums.IdPrefixEnum;
import com.energy.manage.common.po.analysis.AnalysisGeneralFilePo;
import com.energy.manage.common.po.analysis.AnalysisOptionRecordsPo;
import com.energy.manage.common.po.analysis.AnalysisResultPo;
import com.energy.manage.common.po.analysis.AnalysisTypePo;
import com.energy.manage.common.po.analysisdatarelationrecords.AnalysisDataRelationRecordsPo;
import com.energy.manage.common.po.analysispriorityrecords.AnalysisPriorityRecordsPo;
import com.energy.manage.common.po.windfield.WindFieldPO;
import com.energy.manage.common.reponse.ResultResp;
import com.energy.manage.common.util.HttpUtils;
import com.energy.manage.common.util.IdGeneratorUtil;
import com.energy.manage.service.config.AnalysisTypeConfig;
import com.energy.manage.service.constant.analysis.AnalysisConstants;
import com.energy.manage.service.domain.dto.analysis.AnalysisDto;
import com.energy.manage.service.domain.dto.analysis.AnalysisResultDto;
import com.energy.manage.service.domain.vo.analysis.*;
import com.energy.manage.service.domain.vo.cockpit.CompanyFieldAndBatchTreeVo;
import com.energy.manage.service.domain.vo.datatransfer.DataTransferTypeVo;
import com.energy.manage.service.domain.vo.system.SysOrganizationAuthVo;
import com.energy.manage.service.domain.vo.windenginegroup.WindEngineGroupPageVo;
import com.energy.manage.service.domain.vo.windenginegroup.WindEngineGroupShortVo;
import com.energy.manage.service.domain.vo.windenginegroup.WindEngineGroupVo;
import com.energy.manage.service.domain.vo.windfield.WindFieldDescriptVo;
import com.energy.manage.service.domain.vo.windfield.WindFieldVo;
import com.energy.manage.service.filter.LoginUser;
import com.energy.manage.service.filter.LoginUserContextHolder;
import com.energy.manage.service.mappers.analysis.*;
import com.energy.manage.service.mappers.analysisdatarelationrecords.AnalysisDataRelationRecordsMapper;
import com.energy.manage.service.mappers.analysispriorityrecords.AnalysisPriorityRecordsMapper;
import com.energy.manage.service.mappers.datatransfertype.DataTransferTypeMapper;
import com.energy.manage.service.mappers.system.SysOrganizationAuthMapper;
import com.energy.manage.service.mappers.system.SysUserInfoMapper;
import com.energy.manage.service.mappers.windenginegroup.WindEngineGroupMapper;
import com.energy.manage.service.mappers.windfield.WindFieldMapper;
import com.energy.manage.service.property.analysis.AlgorithmProperties;
import com.energy.manage.service.service.analysis.AnalysisService;
import com.energy.manage.service.service.cache.CacheService;
import com.energy.manage.service.util.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.minio.GetObjectArgs;
import io.minio.ListObjectsArgs;
import io.minio.MinioClient;
import io.minio.Result;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 分析服务
 * @author chy
 * @date 2024/5/23 12:59
 * @desc
 */
@Slf4j
@Service
public class AnalysisServiceImpl implements AnalysisService {

    @Autowired
    private AnalysisTypeMapper analysisTypeMapper;

    @Autowired
    private WindEngineGroupMapper engineGroupMapper;

    @Autowired
    private AnalysisCommentDescriptionMapper commentDescriptionMapper;

    @Autowired
    private AnalysisCommentTypeRelationMapper commentTypeRelationMapper;

    @Autowired
    private AnalysisDiagramRelationMapper diagramRelationMapper;

    @Autowired
    private AnalysisGeneralFileMapper generalFileMapper;

    @Autowired
    private WindEngineGroupMapper windEngineGroupMapper;

    @Autowired
    private SysUserInfoMapper sysUserInfoMapper;

    @Autowired
    private AnalysisResultReportMapper resultReportMapper;

    @Autowired
    private SysOrganizationAuthMapper sysOrganizationAuthMapper;

    @Autowired
    private WindFieldMapper windFieldMapper;

    @Autowired
    private AnalysisPriorityRecordsMapper priorityRecordsMapper;

    @Autowired
    private AnalysisDataRelationRecordsMapper dataRelationRecordsMapper;

    @Autowired
    private DataTransferTypeMapper dataTransferTypeMapper;

    @Autowired
    private AlgorithmProperties algorithmProperties;

    @Autowired
    private AnalysisTypeConfig analysisTypeConfig;

    @Autowired
    private  MinioClient minioClient;

    @Autowired
    private BatchDownloadUtil batchDownloadUtil;

    @Autowired
    private CacheService cacheService;


    private static AnalysisOptionRecordsMapper optionRecordsMapper;


    private static AnalysisResultMapper analysisResultMapper;

    /**
     * 操作内容
     */
    private static final String OPTION_CONTENT = "手动分析";

    /**
     * 分析编号分隔符
     */
    private final static String SEPARATOR = "-";


    private final static String ZREO_STR = "0";

    /**
     * 当分析类型不按照机型分析的话 总图数据库表中风机类型编号的值为total
     */
    private final static String GENERAL_FILE_TYPE_CODE = "total";

    /**
     * 过滤掉html展示
     */
    private final static String FILTER_PATTEN = ".html";

    /**
     * 风机编号正则
     */
    private static final String ENGINE_CODE_PATTEN = IdPrefixEnum.WIND_EILL_NUMBER.getCode() + "\\d{3," + IdGeneratorUtil.DEC_INIT_LENGTH + "}";


    private static ObjectMapper mapper = new ObjectMapper();


    /**
     * 分析结果列表
     * @param analysisResultDto
     * @param isIntranet
     * @return
     */
    @Override
    public List<AnalysisResultVo> analysisResultList(AnalysisResultDto analysisResultDto, Boolean isIntranet) {
        List<DataTransferTypeVo> transferTypeVos = dataTransferTypeMapper.selectAllInfo();
        List<AnalysisResultVo> resultVos = analysisResultMapper.selectByCondition(analysisResultDto);
        List<AnalysisPriorityRecordsPo> priorityRecords = priorityRecordsMapper.queryAllPriority();
        resultVos.stream().forEach(item -> {
            //设置数据类型名称
            setDataTypeName(item,transferTypeVos);
            if(CollectionUtils.isNotEmpty(priorityRecords)){
                setOrderNum(item,priorityRecords);
            }
            //设置报告
            item.setReportVos(setReportAddress(resultReportMapper.selectByBatchCode(item.getBatchCode()),isIntranet));
        });
        return resultVos;
    }

    /**
     * 设置数据类型名称
     * @param analysisResultVo
     * @param transferTypeVos
     */
    private void setDataTypeName(AnalysisResultVo analysisResultVo, List<DataTransferTypeVo> transferTypeVos) {
        if(StringUtils.isBlank(analysisResultVo.getDataTypeCode())){
            return;
        }
        Map<String,String> typeMap = transferTypeVos.stream().collect(Collectors.toMap(DataTransferTypeVo::getTransferType, DataTransferTypeVo::getTransferTypeName));
        List<String> dataTypeCodes = Arrays.asList(analysisResultVo.getDataTypeCode().split(","));
        List<String> dataTypeNames = dataTypeCodes.stream().map(typeCode -> typeMap.get(typeCode)).collect(Collectors.toList());
        analysisResultVo.setDataTypeName(dataTypeNames.stream().collect(Collectors.joining(",")));
     }

    /**
     * 设置排队中的任务排队序号
     * @param analysisResultVo
     */
    private void setOrderNum(AnalysisResultVo analysisResultVo, List<AnalysisPriorityRecordsPo> priorityRecords) {
        priorityRecords.stream().forEach(item -> {
            if(item.getBatchCode().equals(analysisResultVo.getBatchCode())){
                String currentOrderNum = analysisResultVo.getOrderNum();
                String newOrderNum = String.valueOf(priorityRecords.indexOf(item) + 1);
                String orderNum = StringUtils.isBlank(currentOrderNum)  ? newOrderNum : currentOrderNum + "," + newOrderNum;
                analysisResultVo.setOrderNum(orderNum);
            }
        });
    }

    /**
     * 设置报告地址
     * @param reportVos
     * @return
     */
    private List<AnalysisResultReportVo> setReportAddress(List<AnalysisResultReportVo> reportVos, Boolean isIntranet) {
        if(CollectionUtils.isNotEmpty(reportVos)){
            reportVos.stream().forEach(item -> item.setReportAddr(NetUtils.getFilePath(isIntranet,item.getReportAddr())));
        }
        return reportVos;
    }

    @Override
    public Page<WindFieldPO> analysisResulFieldList(AnalysisResultDto analysisResultDto){
        int pageNum = analysisResultDto.getPageNum();
        int pageSize = analysisResultDto.getPageSize();
        PageHelper.startPage(pageNum, pageSize);
        List<WindFieldPO> resultVos = analysisResultMapper.selectFieldCode(analysisResultDto);
        Long total = org.apache.commons.collections.CollectionUtils.isEmpty(resultVos) ? 0L : new PageInfo<>(resultVos).getTotal();
        return Page.build(pageNum, pageSize, total, resultVos);
    }

    @Override
    public List<AnalysisResultVo> analysisResultListByAnalysisCode(String fieldCode){
        List<AnalysisResultVo> resultVos = analysisResultMapper.selectByFieldCode(fieldCode);
        resultVos.stream().forEach(item -> item.setReportVos(resultReportMapper.selectByBatchCode(item.getBatchCode())));
        return resultVos;
    }

    /**
     * 添加分析结果
     *
     * @param analysisResultPo
     * @return
     */
    @Override
    public int addAnalysisResult(AnalysisResultPo analysisResultPo) {
        String fieldCode = analysisResultPo.getFieldCode();
        String batchCode = createWindFieldBatchCode(fieldCode);
        analysisResultPo.setBatchCode(batchCode);
        if(StringUtils.isBlank(analysisResultPo.getAnalysisName())){
            WindFieldVo  windFieldVo = windFieldMapper.selectByCodeNumber(fieldCode);
            analysisResultPo.setAnalysisName(createBatchName(windFieldVo.getFieldName()));
        }

        return analysisResultMapper.insertSelective(analysisResultPo);
    }

    /**
     * 分析
     * @param analysisDto
     * @return
     */
    @Override
    public ResultResp analysis(AnalysisDto analysisDto) {
        try {
            //（是因为算法分析类型code与平台分析类型code没有做统一，开发之后才做统一，所以需要转换）
            transferAnalysisFlagByCode(analysisDto);
            //当有功功率没有设置的话 设置默认值 整个风场最大额定功率*1.2 （图像设计移动到前端了，废弃）
            //setActivePower(analysisDto);
            //查询分析中或者排队中的数量
            int analysingCount = analysisResultMapper.selectAnalysisingCount();
            if(analysingCount > 0){
                String taskId = UUIDUtil.getShortUUIDLowCase();
                //排队
                addPriorityRecord(analysisDto.getDataBatchNum(), taskId);
                //保存请求参数
                addDataRelationRecord(analysisDto,taskId);
                //更新任务状态为排队中（只更新分析完成与未分析状态）
                analysisResultMapper.updateAnalysisState(analysisDto.getDataBatchNum());
            }else{
                //调用算法逻辑
                callAnalysis(analysisDto);
            }
            return ResultResp.SUCCESS();
        } catch (Exception e) {
            log.error("批次号 = {} 手动分析异常",analysisDto.getDataBatchNum(),e);
            return ResultResp.FAIL();
        }
    }

    /**
     * 将任务添加到优先级记录表
     * @param batchCode
     */
    private void addPriorityRecord(String batchCode,String taskId) {
        AnalysisPriorityRecordsPo priorityRecordsPo = new AnalysisPriorityRecordsPo()
                                                            .setBatchCode(batchCode)
                                                            .setTaskId(taskId);
        priorityRecordsMapper.insertSelective(priorityRecordsPo);
    }

    /**
     * 将任务参数传入参数数据表
     * @param analysisDto
     */
    private void addDataRelationRecord(AnalysisDto analysisDto,String taskId) {
        AnalysisDataRelationRecordsPo relationRecordsPo = new AnalysisDataRelationRecordsPo();
        BeanUtils.copyProperties(analysisDto,relationRecordsPo);
        //设置分析类型
        relationRecordsPo.setConfigAnalysis(analysisDto.getConfigAnalysis().stream().collect(Collectors.joining(",")));
        //设置风机
        if(CollectionUtils.isNotEmpty(analysisDto.getTurbines())){
            relationRecordsPo.setTurbines(analysisDto.getTurbines().stream().collect(Collectors.joining(",")));
        }
        //设置排除月份
        if(CollectionUtils.isNotEmpty(analysisDto.getExcludingMonths())) {
            relationRecordsPo.setExcludingMonths(analysisDto.getExcludingMonths().stream().collect(Collectors.joining(",")));
        }
        //设置有功功率
        if(CollectionUtils.isNotEmpty(analysisDto.getValueActivePower())) {
            relationRecordsPo.setValueActivePower(analysisDto.getValueActivePower().stream().map(Object::toString).collect(Collectors.joining(",")));
        }
        //设置风机转速
        if(CollectionUtils.isNotEmpty(analysisDto.getValueGeneratorSpeed())) {
            relationRecordsPo.setValueGeneratorSpeed(analysisDto.getValueGeneratorSpeed().stream().map(Object::toString).collect(Collectors.joining(",")));
        }
        //设置桨距角
        if(CollectionUtils.isNotEmpty(analysisDto.getValuePitchAngle())) {
            relationRecordsPo.setValuePitchAngle(analysisDto.getValuePitchAngle().stream().map(Object::toString).collect(Collectors.joining(",")));
        }
        //设置风速
        if(CollectionUtils.isNotEmpty(analysisDto.getValueWindSpeed())) {
            relationRecordsPo.setValueWindSpeed(analysisDto.getValueWindSpeed().stream().map(Object::toString).collect(Collectors.joining(",")));
        }
        relationRecordsPo.setTaskId(taskId);
        dataRelationRecordsMapper.insertSelective(relationRecordsPo);
    }
    /**
     * 调用算法
     * @param analysisDto
     * @throws Exception
     */
    @Override
    public void callAnalysis(AnalysisDto analysisDto) throws Exception{
        //将配置文件中的算法json转换为对象
        JsonNode rootNode = mapper.readTree(algorithmProperties.getAnalysisAlgorithmJson());
        //将入参analysisDto转换为算法标准json
        dataProccess(analysisDto,rootNode);
        log.info("调用分析算法之前，将入参analysisDto转换为算法标准json = {}" , mapper.writeValueAsString(rootNode));
        //调用算法
        String result = HttpUtils.doPost(algorithmProperties.getAnalysisUrl(),mapper.writeValueAsString(rootNode));
        log.info("调用算法分析返回结果：{}",result);
        //调用分析算法接口后更新数据筛选记录
        updateAnalysisByBatchCode(analysisDto);
        //手动操作进行操作记录添加
        if(analysisDto.getAutoOrManual().equals(AnalysisConstants.MANUAL_ANALYSIS)){
            addOptionRecords(analysisDto.getPowerFarmID(),null,OPTION_CONTENT);
        }
    }


    /**
     * 更新数据筛选记录
     * @param analysisDto
     */
    private void updateAnalysisByBatchCode(AnalysisDto analysisDto){
        //多数据源拼接
        Set<String> dataTypeCode = analysisDto.getConfigAnalysis().stream().map(item -> getLastStr(item)).collect(Collectors.toSet());
        analysisDto.setScada(dataTypeCode.stream().collect(Collectors.joining(",")));
        analysisResultMapper.updateByBatchCode(analysisDto);
    }

    /**
     * 获取最后一个字符串
     * @return
     */
    private String getLastStr(String str){
        String[] strings = str.split("\\|");
        return strings[strings.length-1];
    }

    /**
     * 分析编辑查询（查询分析类型、风机组）
     * @param batchCode
     * @return
     */
    @Override
    public AnalysisResultShowVo analysisEditQuery(String batchCode){
        AnalysisResultShowVo analysisResultShowVo = new AnalysisResultShowVo();
        return analysisResultShowVo.setAnalysisTypeList(getAnalysisType())
                .setWindEngineGroupList(getWindEngineGroupByBatchCode(batchCode));
    }

    /**
     * 查询已经分析的分析类型
     * @param batchCode
     * @return
     */
    @Override
    public List<Map<String, Object>> queryAnalysisedType(String batchCode){
        Set<String> analysisCodes = new HashSet<>();
        //总图分析类型
        List<AnalysisGeneralFileVo> generalFileVos = generalFileMapper.selectByBatchCode(batchCode);
        generalFileVos.stream().forEach(item -> analysisCodes.add(item.getAnalysisTypeCode()));
        //分图分析类型
        List<AnalysisDiagramRelationVo> relationVos = diagramRelationMapper.selectByBatchCode(batchCode);
        relationVos.stream().forEach(item -> analysisCodes.add(item.getAnalysisTypeCode()));
        return getAnalysisType(analysisCodes);
    }

    /**
     *过滤分析类型并生成树形结构
     * @param analysisCodes
     * @return
     */
    private List<Map<String, Object>> getAnalysisType(Set<String> analysisCodes){
        if(CollectionUtils.isEmpty(analysisCodes)){
            return new ArrayList<>();
        }
        List<AnalysisTypePo> analysisTypePos = analysisTypeMapper.selectAllByOrderNum();
        analysisTypePos = analysisTypePos.stream().filter(item -> analysisCodes.contains(item.getTypeCode()) || item.getParentId().equals(ZREO_STR)).collect(Collectors.toList());
        return TreeUtil.getJava8ResultTree(BeanMapUtils.listBeanToListMap(analysisTypePos), "parentId", "id");
    }

    /**
     * 查询所有的分析类型
     */
    @Override
    public List<Map<String, Object>> queryAllAnalysisType() {
        List<AnalysisTypePo> analysisTypeList = analysisTypeMapper.selectAllByOrderNum();
        return TreeUtil.getJava8ResultTree(BeanMapUtils.listBeanToListMap(analysisTypeList), "parentId", "id");
    }

    /**
     * 查询已经分析的风机信息
     * @param batchCode
     * @param analysisTypeCode
     * @return
     */
    @Override
    public Set<WindEngineGroupShortVo> queryAnalysisedEngine(String batchCode, String analysisTypeCode){
        Set<WindEngineGroupShortVo> set = diagramRelationMapper.selectByBatchCodeAndAnalysisTypeCode(batchCode,analysisTypeCode);
        if(CollectionUtils.isEmpty(set)){
            int count  = generalFileMapper.selectCount(new AnalysisGeneralFilePo().setBatchCode(batchCode));
            if(count > 0){
                AnalysisResultPo analysisResultPo = analysisResultMapper.selectByBatchCode(batchCode);
                set = engineGroupMapper.selectWindEngineGroupShortList(analysisResultPo.getFieldCode())
                        .stream().collect(Collectors.toSet());
            }else{
                return new HashSet<>();
            }
        }
        //排序
        return set.stream()
                .sorted(Comparator.comparing(WindEngineGroupShortVo::getEngineName))
                .collect(Collectors.toCollection(LinkedHashSet :: new));
    }

    /**
     * 分析详情
     * @param batchCode
     * @param analysisTypeCode
     * @param fieldEngineCodes
     * @return
     */
    @Override
    public List<AnalysisDetailVo> analysisDetail(String batchCode, String analysisTypeCode, List<String> fieldEngineCodes, boolean isIntranet) {
        List<AnalysisDetailVo> analysisDetailVos = new ArrayList<>();
        //获取所有的分析类型
        List<AnalysisTypeVo> analysisTypeVos = analysisTypeMapper.selectByTypeCode(analysisTypeCode);
        if(CollectionUtils.isEmpty(analysisTypeVos)){
            return analysisDetailVos;
        }
        Set<String> analysisTypeCodes = analysisTypeVos.stream().map(item -> item.getTypeCode()).collect(Collectors.toSet());
        //最新总文件
        List<AnalysisGeneralFileVo> newGeneralFileVos = getAllGeneralFiles(batchCode,analysisTypeCodes,isIntranet);
        //获取最新分文件
        List<AnalysisDiagramRelationVo> newDiagramRelationVos = getNewDiagramRelations(batchCode, analysisTypeCode, fieldEngineCodes,isIntranet);
        //查询评论
        List<AnalysisCommentDescriptionVo> commentDescriptionVos = commentDescriptionMapper.selecByBatchCodeAndAnalysisTypeCode(batchCode,analysisTypeCode);
        //根据分析类型设置分析结果
        analysisTypeVos.forEach(analysisTypeVo -> {
            //设置相应参数
            AnalysisDetailVo analysisDetailVo = getAnalysisDetailVo(analysisTypeVo,
                                                                    newGeneralFileVos,
                                                                    newDiagramRelationVos,
                                                                    commentDescriptionVos);
            if(analysisDetailVo != null){
                analysisDetailVos.add(analysisDetailVo);
            }
        });
        //只有当分析类型不为空的时候才返回评论类型
        if(StringUtils.isNotBlank(analysisTypeCode) && CollectionUtils.isNotEmpty(analysisDetailVos)){
            analysisDetailVos.get(0).setCommentTypeRelations(commentTypeRelationMapper.selectByAnalysisTypeCode(batchCode,analysisTypeCode));
        }

        return analysisDetailVos;
    }


    /**
     * 分析中检查
     * @return
     */
    @Override
    public boolean checkAnalysising(){
        return analysisResultMapper.selectAlasisingCount() > AnalysisConstants.SERVER_MERCHINE_COUNT;
    }

    /**
     * 开启/关闭自动分析
     * @param batchCode
     * @return
     */
    @Override
    public int onOffAutoAnalysis(String batchCode, Integer onOffCall) {
        return analysisResultMapper.updateOnOffCall(batchCode,onOffCall);
    }

    /**
     * 分析类型结果图配置接口
     *
     * @return
     */
    @Override
    public JSONArray queryAnalysisTypeConfig() {
        return JSONArray.parseArray(analysisTypeConfig.getAnalysisTypeConfig());
    }

    /**
     * 根据角色获取风场及分析编号信息
     *
     * @return
     */
    @Override
    public List<Map<String, Object>> getAnalysisCodeInfo(Integer roleId) {
        //查询所有权限风场
        List<SysOrganizationAuthVo> list = sysOrganizationAuthMapper.selectInfoByRoleId(roleId);
        List<CompanyFieldAndBatchTreeVo> transferList = new ArrayList<>();
        list.stream().forEachOrdered(item -> transferList.add(transferVo(item)));
        return TreeUtil.getJava8ResultTree(BeanMapUtils.listBeanToListMap(transferList));
    }

    /**
     * 转换vo
     * @param authVo
     * @return
     */
    private CompanyFieldAndBatchTreeVo transferVo(SysOrganizationAuthVo authVo){
        CompanyFieldAndBatchTreeVo treeVo = new CompanyFieldAndBatchTreeVo();
        treeVo.setCodeNumber(authVo.getCodeNumber())
                .setCodeType(authVo.getCodeType());
        if(StringUtils.isBlank(authVo.getCompanyCode())){
            treeVo.setFieldOrCompanyName(authVo.getCompanyName())
                    .setParentCode(ZREO_STR);
        }else{
            treeVo.setFieldOrCompanyName(authVo.getFieldName())
                    .setCodeNumber(authVo.getCodeNumber())
                    .setParentCode(authVo.getCompanyCode())
                    .setBatchCodes(analysisResultMapper.selectShortInfoByFieldCode(authVo.getCodeNumber()));
        }
        return treeVo;
    }


    /**
     * 查询风场及分析信息
     * @param batchCode
     * @return
     */
    @Override
    public FieldAndAnalysisInfoVo getFieldInfo(String batchCode) {
        if(StringUtils.isBlank(batchCode)){
            return new FieldAndAnalysisInfoVo();
        }
        AnalysisResultPo analysisResultPo = analysisResultMapper.selectByBatchCode(batchCode);
        return  new FieldAndAnalysisInfoVo().setFieldInfo(getWindFieldDescriptVo(analysisResultPo.getFieldCode()))
                                            .setAnalysisInfo(getAnalysisCodeInfo(batchCode));
    }

    /**
     * 根据风场编号获取风场信息
     * @param fieldCode
     * @return
     */
    private WindFieldDescriptVo getWindFieldDescriptVo(String fieldCode){
        WindFieldVo windFieldVo = windFieldMapper.selectByCodeNumber(fieldCode);
        if(windFieldVo == null){
            return new WindFieldDescriptVo();
        }
        windFieldVo.setRatedCapacityNumber(windFieldVo.getRatedCapacityNumber()/1000);
        WindFieldDescriptVo windFieldDescriptVo = new WindFieldDescriptVo();
        BeanUtils.copyProperties(windFieldVo,windFieldDescriptVo);
        List<WindEngineGroupPageVo> windEngineGroupPageVos = windEngineGroupMapper.selectWindEngineGroupListByFieldCode(fieldCode);
        //设置风机数量
        windFieldDescriptVo.setEngineCount(windEngineGroupPageVos.size());
        //设置机型集合
        windFieldDescriptVo.setEngineMillTypes(windEngineGroupPageVos.stream().map(WindEngineGroupPageVo::getMachineTypeCode).collect(Collectors.toSet()));
        return windFieldDescriptVo;
    }

    /**
     *根据分析编号获取分析信息
     * @param batchCode
     * @return
     */
    private AnalysisRelateInfoVo getAnalysisCodeInfo(String batchCode){
        AnalysisRelateInfoVo returnVo = new AnalysisRelateInfoVo();
        AnalysisResultPo analysisResultPo = analysisResultMapper.selectByBatchCode(batchCode);
        BeanUtils.copyProperties(analysisResultPo,returnVo);
        List<Map<String,Object>> list = queryAnalysisedType(batchCode);
        returnVo.setUpdateByName(sysUserInfoMapper.getUserInfoByUserId(analysisResultPo.getCreateBy()).getUserName())
                .setAnalysisTypes(list)
                .setWindEngineGroups(queryAnalysisedEngine(batchCode,null));
        return returnVo;
    }

    /**
     * 全部文件下载查询接口
     * @param fieldCode
     * @param batchCode
     * @return
     */
    @Override
    public List<String> queryDownloadFile(String fieldCode, String batchCode){
        String resourcePath = createSourceFilePath(batchCode,null);
        Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(StringUtils.lowerCase(fieldCode)).prefix(resourcePath).build());
        List<String> returnList = new ArrayList<>();
        for(Result<Item> result : results){
            returnList.add(getAnalysisTypeCode(result));
        }
        return returnList;
    }

    /**
     * 获取分析类型
     * @param item
     * @return
     */
    private String getAnalysisTypeCode(Result<Item> item){
        String analysisTypeCode = null;
        try {
            analysisTypeCode = item.get().objectName().split(File.separator)[1];
        } catch (Exception e) {
            log.error("analysisTypeCode = {} 查询文件异常", analysisTypeCode, e);
        }
        return analysisTypeCode;
    }

    /**
     * 文件下载
     * @param fieldCode 风场code
     * @param batchCode 批次code
     * @param analysisTypeCode 分析类型code
     * @param response 响应
     */
    @Override
    public ResultResp downloadFile(String fieldCode, String batchCode, String analysisTypeCode, HttpServletResponse response) {
        List<InputStream> inputStreams = new ArrayList<>();
        List<String> zipFilePaths = new ArrayList<>();
        try{
            String resourcePath = createSourceFilePath(batchCode,analysisTypeCode);
            setStreamAndPath(fieldCode, resourcePath, zipFilePaths, inputStreams);
            log.info("fieldCode = {} ,batchCode = {} ,analysisTypeCode = {} 文件数量 = {}",fieldCode,batchCode,analysisTypeCode,zipFilePaths.size());
            String[] pathsArray = zipFilePaths.stream().toArray(String[] :: new);
            InputStream[] inputStreamsArray = inputStreams.stream().toArray(InputStream[] :: new);
            response.reset();
            String zipName = batchCode + analysisTypeCode + AnalysisConstants.ZIP_SUFFIX;
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(zipName, "UTF-8"));
            response.setContentType("application/octet-stream");
            log.info("fieldCode = {} ,batchCode = {} ,analysisTypeCode = {} 响应头部设置完毕，准备压缩下载",fieldCode,batchCode,analysisTypeCode);
            ZipUtil.zip(response.getOutputStream(), pathsArray, inputStreamsArray);
            log.info("fieldCode = {} ,batchCode = {} ,analysisTypeCode = {} 压缩下载完毕 ！！！",fieldCode,batchCode,analysisTypeCode);
            //这个结果不会返回，但是错误的必须返回
            return ResultResp.SUCCESS();
        }catch (Exception e){
            log.error("fileCode = {} batchCode = {} analysisTypeCode = {} 文件下载失败",fieldCode,batchCode,analysisTypeCode,e);
            return ResultResp.FAIL("文件下载失败，请重试或联系管理员");
        }
    }

//    /**
//     * 文件下载
//     * @param fieldCode
//     * @param batchCode
//     * @return
//     */
//    @Override
//    public void downloadFile(String fieldCode, String batchCode, String analysisTypeCode, HttpServletResponse response) {
//        //下载文件到本地
//        String downloadUrl = BatchDownloadUtil.backResourceAddress(StringUtils.lowerCase(fieldCode),createSourceFilePath(batchCode,analysisTypeCode));
//        if(StringUtils.isBlank(downloadUrl)){
//            log.info("fieldCode = {} ,batchCode = {} ,analysisTypeCode = {} 文件不存在",fieldCode,batchCode,analysisTypeCode);
//            return ;
//        }
//        File file = ZipUtil.zip(downloadUrl, createZipPath(batchCode),true);
//        //异步删除临时文件与zip文件
//        deleteFileDir(downloadUrl);
//        downloadZip(file,response);
//        //异步删除临时文件与zip文件
//        deleteFileDir(createDeleteZipPath());
//    }


    /**
     * 设置文件流与文件路径
     * @param bucketName
     * @param resoucePath
     * @param zipFilePaths
     * @param inputStreams
     * @throws Exception
     */
    private void setStreamAndPath (String bucketName,
                                   String resoucePath,
                                   List<String> zipFilePaths,
                                   List<InputStream> inputStreams) throws Exception {
        bucketName = StringUtils.lowerCase(bucketName);
        //递归获取文件列表（只有文件不含文件夹）
        Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(resoucePath).recursive(true).build());
        int count = 0;
        for(Result<Item> result : results){
            Item item = result.get();
            String objectName = item.objectName();
            log.info("当前操作文件名称 {} ", resoucePath, objectName);
            GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucketName).object(objectName).build();
            String filePath = objectName.replace(resoucePath, resoucePath.replaceFirst(File.separator,"_"));
            zipFilePaths.add(filePath);
            log.info("当前放入文件-{} ", resoucePath, objectName);
            inputStreams.add(minioClient.getObject(getObjectArgs));
            log.info("文件-{} 放入下载列表成功,当前放入文件数量 = {}",objectName,++count);
        }
    }


    /**
     * 生成源文件路径
     * @param batchCode 批次编号
     * @param analysisTypeCode 分析类型code
     * @return
     */
    private String createSourceFilePath(String batchCode,String analysisTypeCode){
        String resourcePath = batchCode + AnalysisConstants.PATH_SEPARATOR ;
        if(StringUtils.isNotBlank(analysisTypeCode)){
            resourcePath +=  analysisTypeCode + AnalysisConstants.PATH_SEPARATOR;
        }
        return resourcePath;
    }

    /**
     * 创建压缩文件路径
     * @param batchCode
     * @return
     */
    private String createZipPath(String batchCode){
        return batchDownloadUtil.localDir + AnalysisConstants.ZIP_DIR
                + AnalysisConstants.PATH_SEPARATOR + batchCode
                + AnalysisConstants.ZIP_SUFFIX;
    }

    /**
     * 删除路径
     * @return
     */
    private String createDeleteZipPath(){
        return batchDownloadUtil.localDir + AnalysisConstants.PATH_SEPARATOR + AnalysisConstants.ZIP_DIR;
    }

    /**
     * 下载zip文件
     * @param file
     * @param response
     * @throws IOException
     */
    private void downloadZip(File file,HttpServletResponse response){
        try{
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
            response.setContentType("application/octet-stream");
            byte[] bytes = FileUtil.readBytes(file.getAbsolutePath());
            OutputStream os = response.getOutputStream();
            os.write(bytes);
            os.flush();
            os.close();
        }catch (IOException ioe){
            log.error("fileName = {} 文件下载失败",file.getName(),ioe);
        }
    }

    /**
     * 异步删除文件
     * @param filePath
     */
    private void deleteFileDir(String filePath){
        File file = new File(filePath);
        if(file.exists()){
            CompletableFuture.supplyAsync(() -> FileUtil.del(file))
                    .thenAccept(result -> log.info("filePath = {} 删除结果result = :{} " , filePath, result));
        }
    }


    /**
     * 获取分析类型
     */
    private List<Map<String,Object>> getAnalysisType(){
        List<Map<String,Object>> resultList = new ArrayList<>();
        List<AnalysisTypeVo> analysisTypeVos =  analysisTypeMapper.selectAllVo();
        if(CollectionUtils.isEmpty(analysisTypeVos)){
            return resultList;
        }
        analysisTypeVos = analysisTypeVos.stream().filter(item->StringUtils.isNotBlank(item.getTypeCode())).sorted(Comparator.comparing(AnalysisTypeVo::getParentId)).collect(Collectors.toList());
        analysisTypeVos.forEach(analysisTypeVo -> {
            String[] typeFlagStrs = analysisTypeVo.getTypeFlag().split("\\|");
            analysisTypeVo.setTypeFlag(typeFlagStrs[typeFlagStrs.length-1]);
            resultList.add(BeanMapUtils.beanToMap(analysisTypeVo));
        });
        return resultList;
//        return TreeUtil.getJava8ResultTree(resultList, AnalysisConstants.ANALYSIS_TYPE_PARRENT_KEY,AnalysisConstants.ANALYSIS_TYPE_KEY);
    }

    /**
     * 获取风机组编号
     * @param batchCode
     * @return
     */
    private List<WindEngineGroupVo> getWindEngineGroupByBatchCode(String batchCode){
        return engineGroupMapper.selectWindEngineGroupByBatchCode(batchCode);
//        if(CollectionUtils.isEmpty(engineGroupVos)){
//            return new HashMap<>();
//        }
//        return engineGroupVos.parallelStream().collect(Collectors.toMap(WindEngineGroupVo::getEngineCode,WindEngineGroupVo::getEngineName, (k1, k2) -> k1, LinkedHashMap::new));
    }

    /**
     * 获取所有分析类型总文件
     * @param batchCode
     * @param typeCodes
     * @param isIntranet
     * @return
     */
    private List<AnalysisGeneralFileVo> getAllGeneralFiles(String batchCode,Set<String> typeCodes, boolean isIntranet){
        List<AnalysisGeneralFileVo> resultList = new ArrayList<>();
        typeCodes.stream().forEach(typeCode -> resultList.addAll(getNewGeneralFiles(batchCode,typeCode,isIntranet)));
        return resultList;
    }

    /**
     * 获取总文件
     * @param batchCode
     * @param analysisTypeCode
     * @return
     */
    private List<AnalysisGeneralFileVo> getNewGeneralFiles(String batchCode,String analysisTypeCode, boolean isIntranet){
        //从数据库获取当前批次、当前分析类型的所有的分析总文件
        List<AnalysisGeneralFileVo> generalFileVos = generalFileMapper.selectByCondition(batchCode,analysisTypeCode);
        generalFileVos = generalFileVos.stream().filter(item-> StringUtils.isNotBlank(item.getEngineTypeCode())
                        && !item.getFileAddr().endsWith(FILTER_PATTEN))
                .collect(Collectors.groupingBy(
                        AnalysisGeneralFileVo::getEngineTypeCode,
                        Collectors.maxBy(Comparator.comparing(AnalysisGeneralFileVo::getCreateTime)))
                ).values().stream().map(Optional::get).collect(Collectors.toList());
                //添加内外网前缀
        generalFileVos.forEach(item -> item.setFileAddr(NetUtils.getFilePath(isIntranet,item.getFileAddr())));
        //当同一个批次、同一个分析类型下，存在多个总文件时，说明一定是按照机型分析，需过滤掉total机型的文件
        if(generalFileVos.size() > 1){
            generalFileVos = generalFileVos.stream().filter(item -> !item.getEngineTypeCode().equals(GENERAL_FILE_TYPE_CODE)).collect(Collectors.toList());
        }
        return generalFileVos;
    }


    /**
     * 获取最新分析结果分文件
     * @param batchCode
     * @param analysisTypeCode
     * @param fieldEngineCodes
     * @return
     */
    private List<AnalysisDiagramRelationVo> getNewDiagramRelations(String batchCode,String analysisTypeCode,List<String> fieldEngineCodes, boolean intranet){
        //获取当前批次、当前分析类型的所有分析结果文件
        List<AnalysisDiagramRelationVo> diagramRelationVos = diagramRelationMapper.selectByCondition(batchCode,analysisTypeCode,fieldEngineCodes);
        if(CollectionUtils.isEmpty(diagramRelationVos)){
            return diagramRelationVos;
        }
        diagramRelationVos = diagramRelationVos.stream().filter(item -> !item.getFileAddr().endsWith(FILTER_PATTEN)).collect(Collectors.toList());
        //根据机组分组获取每组最新文件
        diagramRelationVos = diagramRelationVos.stream().collect(Collectors.groupingBy(
                        AnalysisDiagramRelationVo::getFileAddr,
                        Collectors.maxBy(Comparator.comparing(AnalysisDiagramRelationVo::getCreateTime)))
                ).values().stream().map(Optional::get)
                //对风机编号进行排序
                .sorted(Comparator.comparing(AnalysisDiagramRelationVo::getFieldEngineCode)).collect(Collectors.toList());
                //添加内外网前缀
        diagramRelationVos.forEach(item -> item.setFileAddr(NetUtils.getFilePath(intranet,item.getFileAddr())));
        return diagramRelationVos;
    }

    /**
     * 去重
     * @param keyExtractor
     * @param <T>
     * @return
     */
    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> set = ConcurrentHashMap.newKeySet();
        return t -> set.add(keyExtractor.apply(t));
    }

    /**
     * 替换路径中的手动、自动文件夹名称
     * @param fileAddr
     * @return
     */
    private String replacePath(String fileAddr) {
        //删除自动、手动 文件夹名称
        for(String replaceStr : algorithmProperties.getAnalysisFileReplaceStr()){
            fileAddr = fileAddr.replace(replaceStr, AnalysisConstants.PATH_SEPARATOR);
        }
        //删除文件后缀名
        fileAddr = fileAddr.substring(0, fileAddr.lastIndexOf('.'));
        //中文名字不一样机型编号一样
        Matcher matcher = Pattern.compile(ENGINE_CODE_PATTEN).matcher(fileAddr);
        String engineCode = matcher.find() ? matcher.group() : "";
        return StringUtils.isNotBlank(engineCode) ? engineCode : fileAddr;
    }


    /**
     * 如果列表中含有超过一个的地址链接 删除文件名称中没有机型编码的文件
     * @param generalFileVos
     */
    private void filterDiffFileName(List<AnalysisGeneralFileVo> generalFileVos){
        if(generalFileVos.size() > 1){
            generalFileVos.stream().filter(item -> retainEngineCodeFile(item.getFileAddr())).collect(Collectors.toList());
        }
    }

    private static boolean retainEngineCodeFile(String fileAddr){
        Pattern pattern = Pattern.compile(ENGINE_CODE_PATTEN);
        String fileName = fileAddr.substring(fileAddr.lastIndexOf(AnalysisConstants.PATH_SEPARATOR) + 1);
        return pattern.matcher(fileName).find();
    }

    /**
     * 设置分析结果
     * @param analysisTypeVo
     * @param newGeneralFileVos
     * @param newDiagramRelationVos
     * @param commentDescriptionVos
     * @return
     */
    private AnalysisDetailVo getAnalysisDetailVo(AnalysisTypeVo analysisTypeVo,
                                                 List<AnalysisGeneralFileVo> newGeneralFileVos,
                                                 List<AnalysisDiagramRelationVo> newDiagramRelationVos,
                                                 List<AnalysisCommentDescriptionVo> commentDescriptionVos){
        List<AnalysisGeneralFileVo> generalFileVos = null;
        if(CollectionUtils.isNotEmpty(newGeneralFileVos)) {
            generalFileVos = newGeneralFileVos.stream().filter(analysisGeneralFileVo -> analysisGeneralFileVo.getAnalysisTypeCode().equals(analysisTypeVo.getTypeCode())).collect(Collectors.toList());
        }
        List<AnalysisDiagramRelationVo> diagramRelationVos = null;
        if(CollectionUtils.isNotEmpty(newDiagramRelationVos)){
            diagramRelationVos = newDiagramRelationVos.stream().filter(analysisDiagramRelationVo -> analysisDiagramRelationVo.getAnalysisTypeCode().equals(analysisTypeVo.getTypeCode())).collect(Collectors.toList());
        }
        if(CollectionUtils.isEmpty(generalFileVos) && CollectionUtils.isEmpty(diagramRelationVos)){
            return null;
        }
        return new AnalysisDetailVo()
                .setAnalysisTypeCode(analysisTypeVo.getTypeCode())
                .setAnalysisTypeName(analysisTypeVo.getTypeName())
                .setGeneralFiles(generalFileVos)
                .setDiagramRelations(diagramRelationVos)
                .setCommentDescriptionVos(commentDescriptionVos);
    }

    /**
     * 根据分析类型code转换分析flag
     * @param analysisDto
     */
    private void transferAnalysisFlagByCode(AnalysisDto analysisDto){
        List<String> configAnalysisCodes = analysisDto.getConfigAnalysis();
        if(CollectionUtils.isEmpty(configAnalysisCodes)){
            return;
        }
        //去重处理
        Set<String> flags = new HashSet<>();
        configAnalysisCodes.stream().forEach(item -> {
            String[] typeStrs = item.split("\\|");
            String flag = analysisTypeMapper.selecFlagByCode(typeStrs[0]);
            String dataSource;
            if(StringUtils.isNotBlank(analysisDto.getScada())){
                dataSource = analysisDto.getScada();
            }else{
                dataSource = typeStrs[1];
            }
            flag = flag.substring(0,flag.lastIndexOf("|") + 1) + dataSource;
            flags.add(flag);
        });
        analysisDto.setConfigAnalysis(flags.stream().collect(Collectors.toList()));
    }

    /**
     * 数据处理
     * @param analysisDto 前端入参
     * @param rootNode 根节点json
     */
    private void dataProccess(AnalysisDto analysisDto,JsonNode rootNode){
        //前端入参类
        Field[] analysisFields = analysisDto.getClass().getDeclaredFields();
//        String scada = analysisDto.getScada();
        Arrays.asList(analysisFields).stream().forEach(field -> {
            field.setAccessible(true);
            try {
                //值不能为空且值为list的时候list长度不能为0
                if(field.get(analysisDto) != null){
                    updateNodesByPropertyName(rootNode, field.getName(), field.get(analysisDto));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });
    }


    /**
     * 根据属性修改json值
     * @param parentNode 节点
     * @param propertyName 属性名称
     * @param newValue 新值
     */
    private void updateNodesByPropertyName(JsonNode parentNode, String propertyName, Object newValue) {
        //遍历当前节点
        for (Iterator<Map.Entry<String, JsonNode>> it = parentNode.fields(); it.hasNext(); ) {
            Map.Entry<String, JsonNode> entry = it.next();
            // 匹配到属性名称，进行值的修改
            if (entry.getKey().equalsIgnoreCase(propertyName)) {
                //分析类型及有子节点的处理
                if(propertyName.equalsIgnoreCase(algorithmProperties.getConfigAnalysisProperties()) || entry.getValue().fields().hasNext()){
                    assignmentByPropertyName(entry.getValue(), propertyName, newValue);
                    return;
                }
                //数组属性得特殊处理
                if(algorithmProperties.getAnalysisArrayProperties().contains(propertyName)){
                    ArrayNode arrayNode = mapper.createArrayNode();
                    ((List<String>)newValue).stream().forEach(item-> arrayNode.add(item));
                    ((ObjectNode) parentNode).set(propertyName,arrayNode);
                    return;
                }
                //普通单节点
                ((ObjectNode) parentNode).put(propertyName, newValue.toString());
                return;
            }
            // 递归搜索子节点
            updateNodesByPropertyName(entry.getValue(), propertyName, newValue);
        }

    }

    /**
     * 处理特殊属性
     * @param subNode
     * @param propertyName
     * @param newValue
     */
    private void assignmentByPropertyName(JsonNode subNode, String propertyName, Object newValue){
        //scada数据筛选过滤 、图像设置特殊处理
//        if(algorithmProperties.getGraphSetsProperties().contains(propertyName)||
        if(algorithmProperties.getCustomFilterProperties().contains(propertyName)){
            dealGraphSetsAndCustomFilter(subNode, newValue);
            return ;
        }
        //分析类型特殊处理
        if(algorithmProperties.getConfigAnalysisProperties().equals(propertyName)){
            dealConfigAnalysis(subNode, newValue);
            return;
        }
    }

    /**
     * scada数据筛选过滤 、图像设置特殊处理（图像设置特殊处理废弃）
     * @param subNode
     * @param newValue
     */
    private void dealGraphSetsAndCustomFilter(JsonNode subNode, Object newValue){
        List<Double> list = (List) newValue;
        if(list.size() == 0){
            return;
        }
        AtomicInteger index = new AtomicInteger(0);
        subNode.fields().forEachRemaining(entry -> {
            if(index.get() <= list.size() -1 && list.get(index.get()) != null){
                ((ObjectNode) subNode).put(entry.getKey(), list.get(index.get()));
            }
            index.incrementAndGet();
        });
    }

    /**
     * 分析类型处理
     * @param subNode
     * @param newValue
     */
    private void dealConfigAnalysis(JsonNode subNode, Object newValue){
        try{
            ArrayNode arrayNode = (ArrayNode) subNode;
            List<String> analysisTypes = (List) newValue;
            for(int i = 0 ; i < analysisTypes.size() ; i++){
                JsonNode childNode = mapper.readTree(algorithmProperties.getAnalysisTypeJson());
                //分析类型解析
                String[] types = analysisTypes.get(i).split("\\|");
                AtomicInteger index =  new AtomicInteger(0);
                childNode.fields().forEachRemaining(entry-> {
                    ((ObjectNode)childNode).put(entry.getKey(), types[index.get()]);
                    index.incrementAndGet();
                });
                arrayNode.add(childNode);
            }
        }catch (JsonProcessingException jsonExcep){
            log.error("分析类型解析失败：",jsonExcep);
        }
    }


    /**
     * 操作记录
     * @param fieldCode
     */
    public static void addOptionRecords(String fieldCode,String batchCode,String optionContent){
        try{
            if(StringUtils.isBlank(fieldCode)){
                AnalysisResultPo analysisResultPo = analysisResultMapper.selectByBatchCode(batchCode);
                fieldCode = analysisResultPo.getFieldCode();
            }
            AnalysisOptionRecordsPo optionRecordsPo = new AnalysisOptionRecordsPo();
            LoginUser user = LoginUserContextHolder.get();
            optionRecordsPo.setOptionBy(user.getUserId());
            optionRecordsPo.setOptionByName(user.getUserName());
            optionRecordsPo.setOptionContent(optionContent);
            optionRecordsPo.setFieldCode(fieldCode);
            optionRecordsMapper.insertSelective(optionRecordsPo);
        }catch (Exception e){
            log.info("增加操作记录异常",e);
            return;
        }
    }

    /**
     * 设置额定功率
     * @param analysisDto
     * @return
     */
//    public void setActivePower(AnalysisDto analysisDto){
//        List<Double> targetList = AnalysisConstants.ACTIVITY_POWER;
//        List<Double> sourceList = analysisDto.getActivePower();
//        //替换值为空的元素
//        replaceNullForList(sourceList,targetList);
//        //当源列表长度与指定列表长度一样的话 源列表最后一个元素一定不是空，不需要替换值为最大功率*1.2
//        if(sourceList != null && sourceList.size() == targetList.size()){
//            analysisDto.setActivePower(targetList);
//            return;
//        }
//        String rateCapacity = getRatedCapacity(analysisDto);
//        if(StringUtils.isNotBlank(rateCapacity)){
//            //设置额定功率（风场所有风机中最大功率*1.2）
//            targetList.set(targetList.size() -1 ,new Double(rateCapacity));
//        }
//        analysisDto.setActivePower(targetList);
//    }

    /**
     * 将源列表中非空元素替换到目标列表中且下标不变
     * @param sourcelist
     * @param targetList
     * @return
     */
    private <T> void replaceNullForList(List<T> sourcelist ,List<T> targetList){
        if(CollectionUtils.isEmpty(sourcelist)){
            return;
        }
        sourcelist.stream().forEachOrdered(element -> {
            if(element != null){
                targetList.set(sourcelist.indexOf(element),element);
            }
        });
    }

    /**
     * 获取 ratedCapacity 风机额定功率*1.2
     * @param analysisDto
     * @return
     */
    private String getRatedCapacity(AnalysisDto analysisDto){
        //获取风机机组
        List<String> engineCodes = analysisDto.getTurbines();
        //获取风场编号
        String fieldCode = analysisDto.getPowerFarmID();
        if(StringUtils.isBlank(fieldCode)){
            return null;
        }
        //查询最大功率
       BigDecimal ratedCapacity = windEngineGroupMapper.selectMaxRatedCapacity(fieldCode,engineCodes);
       //功率因数 1.2
       BigDecimal powerFactorRated = new BigDecimal(algorithmProperties.getPowerFactorRated());
       //返回功率
       return ratedCapacity == null ? null : ratedCapacity.multiply(powerFactorRated).toString();
    }

    @Autowired
    private void setAnalysisOptionRecordsMapper(AnalysisOptionRecordsMapper optionRecordsMapper) {
        AnalysisServiceImpl.optionRecordsMapper = optionRecordsMapper;
    }

    @Autowired
    private void setAnalysisResultMapper(AnalysisResultMapper analysisResultMapper) {
        AnalysisServiceImpl.analysisResultMapper = analysisResultMapper;
    }


    /**
     * 生成风场批次号
     * @param fieldCode
     * @return
     */
    @Override
    public String createWindFieldBatchCode(String fieldCode){
        String sequece = IdPrefixEnum.WIND_ENGINE_BATCH_NUMBER.getCode().concat(IdGeneratorUtil.zeroFillUtil(cacheService.incr(ManagerRedisKeyConstant.build(ManagerRedisKeyConstant.IDGENERATOR_CONSTANTS_KEY, fieldCode,IdPrefixEnum.WIND_ENGINE_BATCH_NUMBER.getCode())),6));
        return fieldCode + SEPARATOR + sequece;
    }

    /**
     * 创建分析名称
     * @param fieldName
     * @return
     */
    public String createBatchName(String fieldName){
        String fieldPYHeader = PinYinUtils.getPinYinHeadChar(fieldName);
        return fieldPYHeader.concat(IdGeneratorUtil.zeroFillUtil(cacheService.incr(ManagerRedisKeyConstant.build(ManagerRedisKeyConstant.IDGENERATOR_CONSTANTS_KEY, fieldPYHeader)),6));
    }


    /**
     * 测试排序去重
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException, URISyntaxException {
        AnalysisDto analysisDto = new AnalysisDto();
        List<String> turbines = new ArrayList<>();
        turbines.add("1");
        turbines.add("2");
        turbines.add("3");
        analysisDto.setTurbines(turbines);
        AnalysisDataRelationRecordsPo relationRecordsPo = new AnalysisDataRelationRecordsPo();
        BeanUtils.copyProperties(analysisDto,relationRecordsPo);
        relationRecordsPo.setTurbines(turbines.stream().collect(Collectors.joining(",")));
        System.out.println(relationRecordsPo.getTurbines());
    }

}
