
package com.yeejoin.amos.fas.business.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.yeejoin.amos.component.rule.RuleTrigger;
import com.yeejoin.amos.fas.business.action.model.*;
import com.yeejoin.amos.fas.business.action.mq.WebMqttComponent;
import com.yeejoin.amos.fas.business.bo.*;
import com.yeejoin.amos.fas.business.constants.FasConstant;
import com.yeejoin.amos.fas.business.dao.mapper.*;
import com.yeejoin.amos.fas.business.dao.repository.*;
import com.yeejoin.amos.fas.business.feign.IEquipManageFeign;
import com.yeejoin.amos.fas.business.feign.RemoteSecurityService;
import com.yeejoin.amos.fas.business.jpush.AppMessagePushService;
import com.yeejoin.amos.fas.business.jpush.JPushTypeEnum;
import com.yeejoin.amos.fas.business.jpush.PushMsgParam;
import com.yeejoin.amos.fas.business.param.AlarmParam;
import com.yeejoin.amos.fas.business.param.CommonPageInfoParam;
import com.yeejoin.amos.fas.business.param.FmeaBindParam;
import com.yeejoin.amos.fas.business.service.intfc.*;
import com.yeejoin.amos.fas.business.service.model.ContingencyDeviceStatus;
import com.yeejoin.amos.fas.business.util.DateUtils;
import com.yeejoin.amos.fas.business.util.JexlUtil;
import com.yeejoin.amos.fas.business.util.RpnUtils;
import com.yeejoin.amos.fas.business.vo.EquipCommunicationData;
import com.yeejoin.amos.fas.business.vo.EquipmentSpecificIndexVo;
import com.yeejoin.amos.fas.business.vo.Toke;
import com.yeejoin.amos.fas.business.vo.TopicEntityVo;
import com.yeejoin.amos.fas.client.invoke.RsDataQueue;
import com.yeejoin.amos.fas.common.enums.CheckStatusEnum;
import com.yeejoin.amos.fas.common.enums.DataRefreshTypeEum;
import com.yeejoin.amos.fas.common.enums.RiskSourceRegionEum;
import com.yeejoin.amos.fas.core.common.request.CommonPageable;
import com.yeejoin.amos.fas.core.common.response.RegionTreeResponse;
import com.yeejoin.amos.fas.core.common.response.RiskSourceTreeResponse;
import com.yeejoin.amos.fas.core.enums.NumberEnum;
import com.yeejoin.amos.fas.core.enums.ReserveEnum;
import com.yeejoin.amos.fas.core.util.DateUtil;
import com.yeejoin.amos.fas.core.util.StringUtil;
import com.yeejoin.amos.fas.dao.entity.*;
import com.yeejoin.amos.fas.exception.YeeException;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.typroject.tyboot.component.cache.Redis;
import org.typroject.tyboot.component.cache.enumeration.CacheType;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.Bean;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;


@Service("riskSourceService")
public class RiskSourceServiceImpl implements IRiskSourceService {

    private final Logger log = LoggerFactory.getLogger(RiskSourceServiceImpl.class);

    private static final String DATETYPE_YYYYMMDD = "yyyyMMdd"; //天

    private static final String DATETYPE_YYYYWW = "yyyyWW";//周

    private static final String DATETYPE_YYYYS = "yyyyS";//季节

    private static final String DATETYPE_YYYYMM = "yyyyMM";//月

    private static final String DATETYPE_YYYY = "yyyy";//年

    @Autowired
    private IRiskSourceDao iRiskSourceDao;

    @Autowired
    private AppMessagePushService appMessagePushService;


    @Autowired
    private IRiskLevelDao riskLevelDao;

    @Autowired
    private IEvaluationModelDao iEvaluationModelDao;

    @Autowired
    private FmeaMapper fmeaMapper;

    @Autowired
    private RiskSourceMapper riskSourceMapper;

    @Autowired
    private FireEquipMapper fireEquipMapper;


    @Autowired
    private ImpAndFireEquipMapper impAndFireEquipMapper;

    @Autowired
    private IPreplanPictureDao iPreplanPictureDao;

    @Autowired
    private FireEquipPointMapper fireEquipPointMapper;

    @Autowired
    private IView3dService view3dService;

    @Autowired
    private IRiskLevelDao iRiskLevelDao;

    @Autowired
    private RemoteSecurityService remoteSecurityService;

    @Autowired
    private IRpnChangeLogDao iRpnChangeLogDao;

    @Autowired
    IContingencyOriginalDataDao iContingencyOriginalDataDao;

//    @Autowired
//    IFireEquipmentPointDao iFireEquipmentPointDao;

//    @Autowired
//    IFireEquipmentDataDao iFireEquipmentDataDao;

//    @Autowired
//    private RemoteWebSocketServer remoteWebSocketServer;

    @Autowired
    private IEquipmentService equipmentService;

    @Autowired
    private IDictDao dictDao;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RuleTrigger ruleTrigger;

    @Autowired
    private FmeaEquipmentPointMapper fmeaEquipmentPointMapper;

    @Autowired
    private FmeaPointInputitemMapper fmeaPointInputitemMapper;


    @Autowired
    private IRiskFactorDao iRiskFactorDao;

    @Autowired
    protected HttpServletRequest request;

    @Autowired
    private IEquipmentHandlerService iEquipmentHandlerService;

    @Value("${station.name}")
    private String stationName;

    @Autowired
    IEquipManageFeign iEquipManageFeign;

    @Autowired
    private PlanDetailMapper planDetailMapper;

    public static String cacheKeyForCanBeRunning() {
        return Redis.genKey(CacheType.ERASABLE.name(), "CONTINGENCYRUNING");
    }

    @Autowired
    private IDataRefreshService iDataRefreshService;

    @Autowired
    private WebMqttComponent webMqttComponent;

    @Override
    public RiskSource editRiskSource(HashMap<String, Object> map) throws Exception {
        RiskSource riskSource = (RiskSource) map.get("param");
        Long id = riskSource.getId();
        String orgCode = map.get("org_code") == null ? "" : map.get("org_code").toString();
        String userId = map.get("user_id") == null ? "0" : map.get("user_id").toString();
        riskSource.setOrgCode(orgCode);
        riskSource.setCreateBy(userId);
        Optional<RiskSource> oldRiskSource1 = iRiskSourceDao.findById(id);
        RiskSource oldRiskSource = null;
        if (oldRiskSource1.isPresent()) {
            oldRiskSource = oldRiskSource1.get();
        }
        if (id == 0) {//新增
            riskSource.setStatus(FasConstant.RISK_SOURCE_STATUS_NORMAL);
            riskSource.setCreateDate(new Date());
        } else {// 更新
            riskSource.setCreateDate(oldRiskSource.getCreateDate());
            riskSource.setFmeaList(oldRiskSource.getFmeaList());
            riskSource.setIncrement(oldRiskSource.getIncrement());
            riskSource.setRpn(oldRiskSource.getRpn());
            riskSource.setRpnChangeLogList(oldRiskSource.getRpnChangeLogList());
            riskSource.setRpni(oldRiskSource.getRpni());
            riskSource.setStatus(oldRiskSource.getStatus());
        }
        iRiskSourceDao.saveAndFlush(riskSource);
        return riskSource;
    }

    @Override
    @Transactional
    public void deleteRiskSource(String appKey, String product, String token, String success, Long[] riskSourceId) throws Exception {
        Set<Long> parentIds = new LinkedHashSet<>();
        for (Long rId : riskSourceId) {
            //0.校验
            int count = iRiskSourceDao.countByParentId(rId);
            Optional<RiskSource> rs = iRiskSourceDao.findById(rId);
            rs.ifPresent(riskSource -> parentIds.add(riskSource.getParentId()));
            if (parentIds.contains(0L)) {
                throw new YeeException("公司节点不能删除");
            }
            if (count > 0) {
                throw new YeeException("该数据有关联子项，请先删除子项数据");
            }
            //1、删除风险点
            iRiskSourceDao.deleteById(rId);
            //2.删除关联建筑关系，防止对站服务有问题，捕获异常，不影响业务正常秩序
            try {
                rs.ifPresent(r -> {
                    if (r.getSourceId() != null) {
                        iEquipManageFeign.unbindRelation(r.getSourceId());
                    }
                });

            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        //3.重新计算rpn
        List<Long> existIds = parentIds.stream().filter(e ->
                iRiskSourceDao.findById(e).isPresent()
        ).collect(Collectors.toList());
        RsDataQueue rs = RsDataQueue.getInstance();
        existIds.forEach(rs::addRiskSourcePointDeleteMessage);
    }


    @Override
    public void deleteById(Long id) {
        iRiskSourceDao.deleteById(id);
    }

    @Override
    @Transactional
    public RiskSource synRegion(String userId, String orgCode, RiskSourceSynBo synBo) {
        Optional<RiskSource> op = iRiskSourceDao.findBySourceId(synBo.getId());
        RiskSource riskSource;
        //1.同步上级
        if (op.isPresent()) {
            //有就更新,业务只能调整上级
            riskSource = op.get();
            riskSource.setParentId(synBo.getParentId());
            riskSource = iRiskSourceDao.save(riskSource);
        } else {
            //无则插入
            riskSource = new RiskSource();
            Bean.copyExistPropertis(synBo, riskSource);
            fillBasicParams(userId, orgCode, synBo.getId(), riskSource);
            riskSource = iRiskSourceDao.save(riskSource);
        }
        //2.同步下级(只有一级)
        if (!CollectionUtils.isEmpty(synBo.getChildren())) {
            RiskSource finalRiskSource = riskSource;
            List<RiskSource> children = synBo.getChildren().stream().map(s -> {
                RiskSource t = new RiskSource();
                Bean.copyExistPropertis(s, t);
                fillBasicParams(userId, orgCode, s.getId(), t);
                t.setParentId(finalRiskSource.getId());
                return t;
            }).collect(Collectors.toList());
            iRiskSourceDao.saveAll(children);
        }
        return riskSource;
    }

    private void fillBasicParams(String userId, String orgCode, Long sourceId, RiskSource riskSource) {
        riskSource.setCreateDate(new Date());
        riskSource.setCreateBy(userId);
        riskSource.setOrgCode(orgCode);
        riskSource.setIsRegion(RiskSourceRegionEum.TRUE.getCode());
        riskSource.setStatus("NORMAL");
        riskSource.setIsIndoor(Boolean.FALSE);
        riskSource.setSourceId(sourceId);
    }

    @Override
    public Boolean removeBind(Long instanceId) {
        Optional<RiskSource> exist = iRiskSourceDao.findBySourceId(instanceId);
        if (exist.isPresent()) {
            RiskSource riskSource = exist.get();
            riskSource.setSourceId(null);
            iRiskSourceDao.save(riskSource);
        }
        return exist.isPresent();
    }

    /**
     * 风险模型删除时远程同步
     *
     * @return String
     * @throws <br>
     * @author 张展弋
     * @date 2020-9-8 17:54:12
     */
//    private String deleteToEquipManage(String appKey,String product,String token,String success,Long rId) {
//        if(!isSynEquipManage()) {
//            return null;
//        }
//        CommonResponse cr = null;
//        try {
//            // 父节点id为0表示根节点，对应那边的仓库
//            cr = equipManageFeign.delWarehouse(appKey, product, token, rId.toString());
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        if (cr == null) {
//            return "远程调用同步失败，请检查远程系统后重试！";
//        }
//        if (!success.equals(cr.getResult())) {
//            return "远程同步失败，请检查远程系统后重试！附加消息：" + cr.getMessage();
//        }
//        return null;
//    }
    @Override
    public Page<HashMap<String, Object>> queryRiskSourceByPage(CommonPageInfoParam param) {
        long total = riskSourceMapper.countPageData(param);
        List<HashMap<String, Object>> content = riskSourceMapper.queryRiskSourceByPage(param);
        return new PageImpl<>(content, param, total);
    }


    @Override
    public List<Map> queryForRegion() {
        List<Map> result = riskSourceMapper.queryForRegion();
        if (!CollectionUtils.isEmpty(result)) {
            for (Map map : result) {
                Long id = Long.parseLong(String.valueOf(map.get("id")));
                map.put("regionMaxLevel", findRegionMaxLevel(id));
            }
        }
        return result;
    }


    @Override
    public Map queryFor3DStatistics() {
        Map<String, List> result = riskSourceMapper.statistics3dCount();
        result.put("equipClassify", riskSourceMapper.statisticsEquipClassify());
        result.put("pointStatus", riskSourceMapper.statisticsPointStatus());
        result.put("riskLevel", riskSourceMapper.statisticsRiskLevel());
        return result;
    }


    @Override
    public List<Map> queryRPNReport() {
        return riskSourceMapper.queryRPNReport();
    }


    @Override
    public Map queryForRiseUp() throws Exception {
        Map<String, Map> result = new HashMap<>();

        String startTime, endTime;
        Date now = new Date();
        Date[] timeArrayMonth = getDateInfo(now, DATETYPE_YYYYMM);
        Date[] timeArraySeason = getDateInfo(now, DATETYPE_YYYYS);
        Date[] timeArrayYear = getDateInfo(now, DATETYPE_YYYY);

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        //当月的升上率
        startTime = format.format(timeArrayMonth[0]);
        endTime = format.format(timeArrayMonth[1]);
        Map resultMonth = this.riskSourceMapper.queryForRiseUp(startTime, endTime);

        //当季度的升上率
        startTime = format.format(timeArraySeason[0]);
        endTime = format.format(timeArraySeason[1]);
        Map resultSeason = this.riskSourceMapper.queryForRiseUp(startTime, endTime);


        //当年的升上率
        startTime = format.format(timeArrayYear[0]);
        endTime = format.format(timeArrayYear[1]);
        Map resultYear = this.riskSourceMapper.queryForRiseUp(startTime, endTime);

        result.put("month", resultMonth);
        result.put("season", resultSeason);
        result.put("year", resultYear);
        return result;
    }

    @Override
    public List<Map> queryForMatrix() {
        return this.riskSourceMapper.queryForMatrix();
    }

    private static Date[] getDateInfo(Date date, String datetype) throws Exception {
        Date[] returnDate = new Date[2];


        Date start = null;
        Date end = null;
        if (DATETYPE_YYYYMMDD.equals(datetype)) {
            start = DateUtils.getCurrentDayStartTime(date);
            end = DateUtils.getCurrentDayEndTime(date);
        }

        if (DATETYPE_YYYYWW.equals(datetype)) {
            start = DateUtils.getCurrentWeekDayStartTime(date);
            end = DateUtils.getCurrentWeekDayEndTime(date);
        }

        if (DATETYPE_YYYYS.equals(datetype)) {
            start = DateUtils.getCurrentQuarterStartTime(date);
            end = DateUtils.getCurrentQuarterEndTime(date);
        }

        if (DATETYPE_YYYYMM.equals(datetype)) {
            start = DateUtils.getCurrentMonthStartTime(date);
            end = DateUtils.getCurrentMonthEndTime(date);
        }

        if (DATETYPE_YYYY.equals(datetype)) {
            start = DateUtils.getCurrentYearStartTime(date);
            end = DateUtils.getCurrentYearEndTime(date);
        }
        returnDate[0] = start;
        returnDate[1] = end;
        return returnDate;
    }

    @Override
    public List<RiskSourceTreeResponse> findRiskSourceTrees(String compCode) {
        return riskSourceMapper.getRiskSources(compCode);
    }

    @Override
    public List<FmeaEquipmentPoint> bindFireEquiment(FmeaBindParam fmeaBindParam) {
        Long fmeaId = fmeaBindParam.getFmeaId();
        Long importantEquipId = fmeaBindParam.getImportantEquipmentId();
        List<Long> equipmentPointIds = fmeaEquipmentPointMapper.listEquipmentPointIdsByEquipmentId(fmeaBindParam.getEquipmentId());
        if (!CollectionUtils.isEmpty(equipmentPointIds)) {
            fmeaEquipmentPointMapper.deleteByFmeaIdAndEquipmentPointIds(fmeaId, importantEquipId, equipmentPointIds);
        }
        List<FmeaEquipmentPoint> returnList = new ArrayList<>();
        for (Long equipmentPointId : fmeaBindParam.getEquipmentPointIds()) {
            FmeaEquipmentPoint fmeaEquipmentPoint = new FmeaEquipmentPoint();
            fmeaEquipmentPoint.setFmeaId(fmeaId);
            fmeaEquipmentPoint.setImportantEquipmentId(importantEquipId);
            fmeaEquipmentPoint.setEquipmentPointId(equipmentPointId);
            returnList.add(fmeaEquipmentPoint);
        }
        Equipment equipment = equipmentService.queryOne(importantEquipId);
        if (!CollectionUtils.isEmpty(returnList) && equipment != null) {
            fmeaEquipmentPointMapper.saveBatch(returnList);
        }
        if (equipment != null) {
            RsDataQueue rsDataQueue = RsDataQueue.getInstance();
            rsDataQueue.addEquipmentMessage(fmeaId, equipment.getName());
        }
        return returnList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<FmeaPointInputitem> bindPointInputitem(FmeaBindParam fmeaBindParam) {
        Long fmeaId = fmeaBindParam.getFmeaId();
        List<Long> pointInputitemIds = fmeaPointInputitemMapper.listPointInputitemIdsByPointId(fmeaBindParam.getPointId());
        List<FmeaPointInputitem> fmeaList =  fmeaPointInputitemMapper.listFmeaByFmeaId(fmeaId);
        if (!CollectionUtils.isEmpty(pointInputitemIds)) {
            fmeaPointInputitemMapper.deleteByFmeaIdAndPointInputitemIds(fmeaId, pointInputitemIds);
        }
        List<FmeaPointInputitem> returnList = new ArrayList<>();
        for (Long pointInputitemId : fmeaBindParam.getPointInputitemIds()) {

            FmeaPointInputitem fmeaPointInputitem = new FmeaPointInputitem();
            fmeaPointInputitem.setFmeaId(fmeaId);
            fmeaPointInputitem.setPointInputitemId(pointInputitemId);
            fmeaPointInputitem.setState(0);
             fmeaList.stream().forEach(e ->{
                 if(e.getPointInputitemId().equals(pointInputitemId)){
                     fmeaPointInputitem.setState(e.getState());
                 }
             });
            returnList.add(fmeaPointInputitem);
        }

        if (!CollectionUtils.isEmpty(returnList)) {
            fmeaPointInputitemMapper.saveBatch(returnList);
        }
        RsDataQueue rsDataQueue = RsDataQueue.getInstance();
        rsDataQueue.addPatrolMessage(fmeaId);
        return returnList;
    }

    /**
     * 查询指定风险点和设备之间的关系，包含绑定和未绑定
     */
    @Override
    public Page<Map> queryEquimentRelation(CommonPageable commonPageable, String equipmentId, String fname) {
        Long total = fireEquipMapper.queryEquimentRelationCount(equipmentId, fname);
        List<Map> list = fireEquipMapper.queryEquimentRelation(commonPageable.getOffset(), commonPageable.getPageSize(), equipmentId, fname);
        return new PageImpl<>(list, commonPageable, total);
    }

    @Override
    public List<Map<String, Object>> listEquipmentPointById(Long fmeaId, Long importantEquipId, Long equipmentId, String equipmentPointName) {
        List<Map<String, Object>> list = fmeaEquipmentPointMapper.listEquipmentPoint(fmeaId, importantEquipId, equipmentId, equipmentPointName);
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }
        return list;

    }


    public void alermContingency(String batchNo, FireEquipmentBo fireEquipment, Equipment equipment) throws Exception {
        Object oldContingencyRo = redisTemplate.opsForValue().get("contingencyRo");
        ContingencyRo contingencyRo = new ContingencyRo();
        contingencyRo.setBatchNo(batchNo);
        contingencyRo.setEquipmentId(String.valueOf(equipment.getId()));
        contingencyRo.setEquipmentName(equipment.getName());
        contingencyRo.setFireEquipmentId(String.valueOf(fireEquipment.getId()));
        contingencyRo.setFireEquipmentName(fireEquipment.getName());
        contingencyRo.setStep("0");
        contingencyRo.setConfirm("NONE");
        contingencyRo.setFireTruckRoute(equipment.getFireTruckRoute());
        contingencyRo.setRunstep(false);
        contingencyRo.setEquipmentPosition3d(equipment.getPosition3d());
        contingencyRo.setEquipmentCode(equipment.getCode());
        contingencyRo.setEquipmentOrgCode(equipment.getOrgCode());

        Map cameraInfo = impAndFireEquipMapper.queryForCamera(String.valueOf(equipment.getId()));//查询重点设备关联视频点位，暂不处理

        if (cameraInfo != null) {
            contingencyRo.setCameraCodes(String.valueOf(cameraInfo.get("codes")));
            contingencyRo.setCameraIds(String.valueOf(cameraInfo.get("ids")));
        }
        contingencyRo.setMobile("13259783333");
        contingencyRo.setAdminName("admin");
        contingencyRo.setFireEquipmentPosition(fireEquipment.getPosition3d());

        List<PreplanPicture> pictures = iPreplanPictureDao.findByEquipmentId(Long.valueOf(equipment.getId()));
        if (!CollectionUtils.isEmpty(pictures)) {
            for (PreplanPicture picture : pictures) {
                if (1 == picture.getType()) {
                    contingencyRo.setPicture1(picture.getPicture());
                }
                if (2 == picture.getType()) {
                    contingencyRo.setPicture2(picture.getPicture());
                }
                if (3 == picture.getType()) {
                    contingencyRo.setPicture3(picture.getPicture());
                }
                if (4 == picture.getType()) {
                    contingencyRo.setPicture4(picture.getPicture());
                }
            }
        }

        // 获取遥信指标,暂不处理  ---20201111    code = 设备编码iot_code-指标项name_key
        List<Map> points = fireEquipPointMapper.getPointsByEquipmentIdAndType(equipment.getId(), "SWITCH");//物联属性指标 and 为true或false
        HashMap<String, Integer> telesignallingMap = new HashMap<>();
        for (Map map : points) {
            telesignallingMap.put(map.get("code") + "", (ObjectUtils.isEmpty(map.get("value")) || "false".equals(map.get("value").toString())) ? 0 : 1);
        }
        contingencyRo.setTelesignallingMap(telesignallingMap);
        //获取遥测指标
        points = fireEquipPointMapper.getPointsByEquipmentIdAndType(equipment.getId(), "ANALOGUE"); //物联指标 非 true false
        HashMap<String, Double> telemetryMap = new HashMap<>();
        for (Map map : points) {
            telemetryMap.put(map.get("code") + "", Double.valueOf(ObjectUtils.isEmpty(map.get("value")) ? "0" : map.get("value").toString()));
        }
        contingencyRo.setTelemetryMap(telemetryMap);

        List<String> plan = this.getNumberPlan(Long.parseLong(contingencyRo.getEquipmentId()));
        if (plan.size() > 0) {
            log.debug("开始调用规则");
            Object result = ruleTrigger.publish(contingencyRo, "换流站消防专项预案/" + plan.get(0), ArrayUtils.toArray(equipment.getName()));
            log.debug("规则调用返回==", result);
            ContingencyOriginalData contingencyOriginalData = new ContingencyOriginalData();
            BeanUtils.copyProperties(contingencyRo, contingencyOriginalData);
            iContingencyOriginalDataDao.save(contingencyOriginalData);
        }
    }


    private Integer findRegionMaxLevel(Long regionRiskSourceId) {
        Integer maxLevel = 0;
        List<RiskSource> anomalyRiskSource = findAnomalyRiskSource(regionRiskSourceId);
        for (RiskSource anomaly : anomalyRiskSource) {
            Optional<RiskLevel> anomalyLevel1 = this.iRiskLevelDao.findById(anomaly.getRiskLevelId());
            RiskLevel anomalyLevel = null;
            if (anomalyLevel1.isPresent()) {
                anomalyLevel = anomalyLevel1.get();
            }
            if (anomalyLevel != null && anomalyLevel.getLevel() > maxLevel) {
                maxLevel = anomalyLevel.getLevel();
            }
        }
        return maxLevel;

    }


    private List<RiskSource> findAnomalyRiskSource(Long riskSourceId) {
        List<RiskSource> returnList = new ArrayList<>();
        List<RiskSource> childs = iRiskSourceDao.findByParentId(riskSourceId);

        if (CollectionUtils.isEmpty(childs)) {
            return returnList;
        }
        for (RiskSource child : childs) {
            returnList.add(child);
            returnList.addAll(this.findAnomalyRiskSource(child.getId()));
        }
        return returnList;
    }

    @Override
    public Page<Map<String, Object>> listFmeaPointInputitem(String toke, String product, String appKey, Long fmeaId, Integer pageNumber, Integer pageSize) {
        List<Map<String, Object>> content = Lists.newArrayList();
        CommonPageable pageable = new CommonPageable(pageNumber, pageSize);
        long total = fmeaPointInputitemMapper.countByFmeaId(fmeaId);
        if (total == 0L) {
            return new PageImpl<>(content, pageable, total);
        }
        content = fmeaPointInputitemMapper.listByFmeaId(fmeaId, pageNumber, pageSize);
        if (!CollectionUtils.isEmpty(content)) {
            Set<Object> userIds = content.stream().filter(x -> !StringUtils.isEmpty(x.get("userId"))).map(arg0 -> arg0.get("userId")).collect(Collectors.toSet());
            Set<Object> deptIds = content.stream().filter(x -> !StringUtils.isEmpty(x.get("deptId"))).map(arg0 -> arg0.get("deptId")).collect(Collectors.toSet());
            Map<String, AgencyUserModel> userMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(userIds)) {
                userMap = remoteSecurityService.getUsersMap(toke, product, appKey, userIds);
            }

            Map<Long, String> deptMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(deptIds)) {
                deptMap = remoteSecurityService.getDepName(toke, product, appKey, deptIds);
            }

            for (int i = 0; i < content.size(); i++) {
                if (StringUtil.isNotEmpty(content.get(i).get("userId")) && userMap.containsKey(content.get(i).get("userId"))) {
                    AgencyUserModel user = userMap.get(content.get(i).get("userId"));
                    content.get(i).put("userName", user.getRealName());
                    content.get(i).put("tel", user.getMobile());
                }
                if (StringUtil.isNotEmpty(content.get(i).get("deptId")) && deptMap.containsKey(Long.valueOf(content.get(i).get("deptId").toString()))) {
                    content.get(i).put("deptName", deptMap.get(Long.valueOf(content.get(i).get("deptId").toString())));
                }
            }
        }
        return new PageImpl<>(content, pageable, total);
    }

    @Override
    public Page<Map<String, Object>> listFeamEquipmentPoint(Long fmeaId, Integer pageNumber, Integer pageSize) {
        long total = fmeaEquipmentPointMapper.countByFmeaId(fmeaId);
        List<Map<String, Object>> content = fmeaEquipmentPointMapper.listByFmeaId(fmeaId, pageNumber, pageSize);
        return new PageImpl<>(content, new CommonPageable(pageNumber, pageSize), total);
    }


    @Override
    public boolean processTaskData(ProtalDataRo taskData) throws Exception {
        taskData.setBatchNo(UUID.randomUUID().toString());
        return true;
    }


    @Override
    @Async
    public void processProtalData(String toke, String product, String appKey, ProtalDataRo protalData, String orgCode) {
        //巡检消息规则推送
        protalRuleMessagePush(protalData, toke, product, appKey);
        if (!CollectionUtils.isEmpty(protalData.getPointInputitems())) {
            Long pointId = protalData.getId();
            List<Long> inputIds = Lists.newArrayList();
            Map<Long, CheckInputItemRo> map = Maps.newHashMap();
            for (CheckInputItemRo checkInputItemRo : protalData.getPointInputitems()) {
                inputIds.add(checkInputItemRo.getPointInputitemId());
                map.put(checkInputItemRo.getPointInputitemId(), checkInputItemRo);
            }
            List<FmeaPointInputitem> fmeaPointInputitems = fmeaPointInputitemMapper.listByPointIdAndInputItemIds(pointId, inputIds);
            Set<Long> fmeaIds = Sets.newHashSet();
            List<Long> failIds = Lists.newArrayList();
            List<Long> successIds = Lists.newArrayList();
            fmeaPointInputitems.forEach(fmeaPointInputitem -> {
                CheckInputItemRo checkInputItemRo = map.get(fmeaPointInputitem.getPointInputitemId());
                if (checkInputItemRo.getStatus().equals("2")) {
                    failIds.add(fmeaPointInputitem.getId());
                    fmeaIds.add(fmeaPointInputitem.getFmeaId());
                } else if (checkInputItemRo.getStatus().equals("1")) {
                    successIds.add(fmeaPointInputitem.getId());
                    fmeaIds.add(fmeaPointInputitem.getFmeaId());
                }
            });
            if (failIds.size() > 0) {
                fmeaPointInputitemMapper.updateStateByIds(1, failIds);
            }
            if (successIds.size() > 0) {
                fmeaPointInputitemMapper.updateStateByIds(0, successIds);
            }
            RsDataQueue rsDataQueue = RsDataQueue.getInstance();
            fmeaIds.forEach(fmeaId ->
                    rsDataQueue.addPatrolMessage(fmeaId, protalData.getCheckUser(), protalData.getName(), protalData.getNodeState()));
        }
        iDataRefreshService.refreshViewData(DataRefreshTypeEum.check.getCode());
        /**
         * 推送巡检数据
         * 影响区域：今日安全，消防安全=>巡检异常，一周安全趋势
         */
        // 今日安全
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        String dateString = formatter.format(new Date());
        String topicOne = String.format("/%s/%s/%s/%s", serviceName, stationName, "data/refresh", "todaySafetyIndex");
        webMqttComponent.publish(topicOne, JSON.toJSONString(view3dService.getSafetyIndexInfoByDate(orgCode, dateString)));

        // 巡检异常
        String topicTwo = String.format("/%s/%s/%s/%s", serviceName, stationName, "data/refresh", "fireSafety");
        webMqttComponent.publish(topicTwo, JSON.toJSONString(view3dService.getSafetyExecuteListTop5("check", orgCode)));

        // 一周安全趋势
        String topicThree = String.format("/%s/%s/%s/%s", serviceName, stationName, "data/refresh", "weekSafetyIndex");
        webMqttComponent.publish(topicThree, JSON.toJSONString(view3dService.getSafetyIndexWeek(orgCode)));

        // 今日巡检
        String topicFour = String.format("/%s/%s/%s/%s", serviceName, stationName, "data/refresh", "todayCheckStatus");
        webMqttComponent.publish(topicThree, JSON.toJSONString(view3dService.getStatisticsCheck(orgCode)));
    }

    /**
     * <pre>
     * @Description: 隐患治理更新State、rpn值
     * </pre>
     *
     * @Throws
     * @Author keyong
     * @Date 2021/2/1 19:50
     */
    @Override
    public void processProtalDataFromDanger(DangerResultBo dangerResultBo) {
        List<FmeaPointInputitem> fmeaPointInputitems = fmeaPointInputitemMapper.listByPointInputItemId(dangerResultBo.getInputItemId());
        if (0 < fmeaPointInputitems.size()) {
            Set<Long> fmeaIds = Sets.newHashSet();
            List<Long> list = Lists.newArrayList();
            fmeaPointInputitems.forEach(x -> {
                list.add(x.getId());
                fmeaIds.add(x.getFmeaId());
            });
            fmeaPointInputitemMapper.updateStateByIds(0, list);
            RsDataQueue rsDataQueue = RsDataQueue.getInstance();
            fmeaIds.forEach(fmeaId -> rsDataQueue.addPatrolMessage(fmeaId, dangerResultBo.getUserName(), null, "1"));
            iDataRefreshService.refreshViewData(DataRefreshTypeEum.handleDanger.getCode());
            // 今日安全
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            String dateString = formatter.format(new Date());
            String topicOne = String.format("/%s/%s/%s/%s", serviceName, stationName, "data/refresh", "todaySafetyIndex");
            webMqttComponent.publish(topicOne, JSON.toJSONString(view3dService.getSafetyIndexInfoByDate(dangerResultBo.getOrgCode(), dateString)));

            // 一周安全趋势
            String topicThree = String.format("/%s/%s/%s/%s", serviceName, stationName, "data/refresh", "weekSafetyIndex");
            webMqttComponent.publish(topicThree, JSON.toJSONString(view3dService.getSafetyIndexWeek(dangerResultBo.getOrgCode())));
        }
    }

    /**
     * 巡检消息规则推送
     *
     * @param protalData
     */
    @Async
    void protalRuleMessagePush(ProtalDataRo protalData, String token, String product, String appKey) {
        String bacthNo = UUID.randomUUID().toString();
        String nodeState = protalData.getNodeState();
        String name = protalData.getName();
        protalData.setBatchNo(bacthNo);
        protalData.setOriginalNodeState(nodeState);
        protalData.setUserName(protalData.getCheckUser());
        protalData.setPointName(name);
        try {
            EquipmentSpecificIndexVo specificIndexVo = new EquipmentSpecificIndexVo();
            specificIndexVo.setId(protalData.getId());
            specificIndexVo.setName(name);
            specificIndexVo.setCode(protalData.getPointNo());
            specificIndexVo.setType("patrol");
            specificIndexVo.setNameKey("patrol");
            if ("2".equals(nodeState) || "3".equals(nodeState)) {
                specificIndexVo.setValue("true");
            } else {
                specificIndexVo.setValue("false");
            }
            //  三维屏巡检点状态推送
            String title = String.format("/%s/%s", serviceName, "data/refresh/indexStatus");
            webMqttComponent.publish(title, JSON.toJSONString(specificIndexVo));

            RequestContext.setToken(token);
            RequestContext.setProduct(product);
            log.info("巡检消息发送规则" + JSONObject.toJSONString(protalData));
            ruleTrigger.publish(protalData, "风险管控/patrol", null);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }


    @Override
    public RiskSourceTreeResponse queryRiskSourceDetailById(Long id) {
        RiskSourceTreeResponse det = riskSourceMapper.findRiskSourceDetatil(id);
        return det;
    }


    @Override
    public Map earlyWarning(Long riskSourceId) {
        Map returnMap = new HashMap();
        Map riskSourceInfo = this.riskSourceMapper.queryForRiskSourceLevel(riskSourceId);
        List<Map> fmeaList = this.fmeaMapper.queryForFmeaList(riskSourceId);
        List<Map> inputitemContent = this.riskSourceMapper.queryForUnqualified(riskSourceId);
        List<Map> equipAlarms = riskSourceMapper.queryForFmeaEquipAlarm(riskSourceId);
        returnMap.put("riskSourceInfo", riskSourceInfo);
        returnMap.put("fmeaList", fmeaList);
        returnMap.put("inputitemContent", inputitemContent);
        returnMap.put("fire_equipment", equipAlarms);
        return returnMap;
    }


    @Override
    public List<HashMap<String, Object>> queryRiskAreaRpn() {
        return riskSourceMapper.queryRiskAreaRpn();
    }

    @Transactional
    public void updateFirePointValue(Long id, String state) {
        fireEquipPointMapper.updateValue(id, state);
    }

    private static final BlockingQueue<AlarmParam> blockingQueue = new LinkedBlockingQueue<AlarmParam>();
    private static ExecutorService executorService = Executors.newSingleThreadExecutor();

    @PostConstruct
    public void start() {
        executorService.execute(new AlarmConsumer());
    }

    class AlarmConsumer implements Runnable {

        /**
         * 1.从队列中取出帧；2.调用业务接口；
         */
        @Override
        public void run() {
            boolean isRunning = true;
            while (isRunning) {
                AlarmParam deviceData = null;
                try {
                    deviceData = blockingQueue.take();
                } catch (Exception e) {
                    log.error("take alarmParam happened error", e);
                }
                // 2.调用业务接口；
                if (deviceData == null) {
                    log.warn("alarmParam is empty!");
                } else {
                    try {

//	                    Toke toke = cacheMap.getValue(TOKE);
//	                    if (toke == null) {
//	                        toke = remoteSecurityService.come();
//	                        Long times = (long) (20 * 24 * 60 * 60);
//	                        cacheMap.setex(TOKE, toke, times);
//	                    }
//	                    log.error("rule token ", toke.toString());
//                        processDeivceData(deviceData);
                    } catch (Exception e) {
                        log.error("parse alarmParam happened error", e);
                        // 失败处理
                    }
                }
            }
        }

    }


//    private void processDeivceData(AlarmParam deviceData) {
//        //处理设备和巡检数据
//        deviceData.setNodeState(deviceData.getState());
//        FireEquipmentPoint fireEquipmentPoint = iFireEquipmentPointDao.findOneByCode(deviceData.getPointCode());
//        if (!ObjectUtils.isEmpty(fireEquipmentPoint)) {
//
//            fireEquipmentPoint.setValue(deviceData.getState());
//            updateFirePointValue(fireEquipmentPoint.getId(), deviceData.getState());//不需要
//
//            String fireEquipmentPointType = null;
//            if (!ObjectUtils.isEmpty(fireEquipmentPoint.getAlarmType())) {
//                Dict dict = dictDao.getOne(fireEquipmentPoint.getAlarmType());
//                fireEquipmentPointType = dict.getDictValue();
//            }
//
//            // 根据监测点获取监测点设备信息
//            Optional<FireEquipment> fireEquipment1 = this.iFireEquipmentDao.findById(fireEquipmentPoint.getFireEquipmentId());
//            FireEquipment fireEquipment = null;
//            if (fireEquipment1.isPresent()) {
//                fireEquipment = fireEquipment1.get();
//            }
//
//            Equipment equipment = null;
//            if (fireEquipment != null) {
//                Toke toke = remoteSecurityService.getServerToken();
//                //保存实时数据
//                // 根据监测点设备信息获取保护的重点装备
//                equipment = impAndFireEquipMapper.queryImpEqumtByFireEquipmt(fireEquipmentPoint.getFireEquipmentId());
//                deviceData.setMonitor(equipment != null ? equipment.getName() : "");
//                deviceData.setId(String.valueOf(fireEquipment.getId()));
//                deviceData.setCode(fireEquipment.getCode());
//                saveFireEquipmentData(fireEquipmentPoint, fireEquipment, deviceData, fireEquipmentPointType, toke);
//                DeviceRo deviceRo = new DeviceRo();
//                deviceRo.setEquipmentId(equipment.getId());
//                deviceRo.setPointCode(deviceData.getPointCode());
//                deviceRo.setValue(deviceData.getState());
//                triggerPlanDevice(deviceRo, equipment, toke);
//                Boolean have = impAndFireEquipMapper.existsAlarmPointByEqpPointIdAndEquipId(fireEquipmentPoint.getId(), equipment.getId());//判断重点设备关联该指标项，需要修改为新查询
//                if (!ObjectUtils.isEmpty(have) && have) {
//                    //动态预案执行
//                    dynamicPlan(deviceData, equipment, fireEquipment, toke);
//                }
//            }
//        }
//
//    }

    /**
     * 预案执行
     *
     * @param deviceData
     * @param equipment
     * @param fireEquipment
     * @param toke
     */
    @Async
    void dynamicPlan(AlarmParam deviceData, Equipment equipment, FireEquipmentBo fireEquipment, Toke toke) {
        Object contingencyRo = redisTemplate.opsForValue().get("contingencyRo");
        String batchNo = null;
//    	if (!ObjectUtils.isEmpty(contingencyRo)) {
//    		batchNo = ((ContingencyRo)contingencyRo).getBatchNo();
//    	} else {
//    		batchNo = UUID.randomUUID().toString();
//    	}
        batchNo = UUID.randomUUID().toString();
        RequestContext.setToken(toke.getToke());
        RequestContext.setProduct(toke.getProduct());
        try {
            alermContingency(batchNo, fireEquipment, equipment);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Async
    public void triggerPlanDevice(DeviceRo deviceRo, Equipment equipment, Toke toke) {
        try {
            RequestContext.setToken(toke.getToke());
            RequestContext.setProduct(toke.getProduct());
            Object result1 = ruleTrigger.publish(deviceRo, equipment.getReservePlan(), ArrayUtils.toArray());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @Override
    @javax.transaction.Transactional
    public String processFireEqumtData(AlarmParam deviceData) throws Exception {
        EquipmentSpecificIndexVo equipmentSpecificIndexVo = impAndFireEquipMapper.findFireEqupmentByCode(deviceData.getPointCode());
        Optional.ofNullable(equipmentSpecificIndexVo).orElseThrow(() -> new Exception("未查询到相关装备"));
        TopicEntityVo topicEntity = new TopicEntityVo();
        topicEntity.setMessage(JSON.toJSONString(equipmentSpecificIndexVo));
        String data = JSON.toJSONString(topicEntity);
        System.out.println(data);
        iEquipmentHandlerService.handlerMqttMessage("", data);
        return "SUCCESS";
    }


    @Override
    @Transactional
    public ReserveEnum startEquipReserve(Long id, String typeCode) {
        int count = equipmentService.countByStatus(NumberEnum.ONE.getValue());
        if (count > NumberEnum.ZERO.getValue()) {
            return ReserveEnum.RUNNING;
        } else {
            List<Object> list = equipmentService.getReserveEquipById(id, typeCode);
            if (!CollectionUtils.isEmpty(list)) {
                EquipmentSpecificIndexVo equipmentSpecificIndexVo = new EquipmentSpecificIndexVo();
                equipmentSpecificIndexVo.setEquipmentSpecificId(Long.parseLong(list.get(NumberEnum.ZERO.getValue()).toString()));
                equipmentSpecificIndexVo.setType(typeCode);

                TopicEntityVo topicEntity = new TopicEntityVo();
                Equipment equipment = equipmentService.queryOne(id);
                topicEntity.setMessage(JSON.toJSONString(equipmentSpecificIndexVo));
                topicEntity.setEquipment(equipment);
                String data = JSON.toJSONString(topicEntity);
                iEquipmentHandlerService.handlerMqttMessage("", data);
                if (equipment != null) {
                    equipment.setStartTime(DateUtil.getDateNow());
                    equipment.setEndTime(null);
                    equipment.setReserveSource(NumberEnum.ONE.getValue());
                    equipment.setStatus(NumberEnum.ONE.getValue());
                    equipmentService.save(equipment);
                    return ReserveEnum.RUN;
                }
                return ReserveEnum.NOEQUIP;
            } else {
                return ReserveEnum.NOFIRE;
            }
        }
    }

    /**
     * webSocket向前台推送消防设备数据
     *
     * @param param
     */
    @Async
    public void sendRiskSourceData(AlarmParam param) {
        try {

            Map<String, Object> map = new HashMap<>();
            map.put("value", param.getState());
            map.put("id", param.getPointCode());
            Map<String, Map<String, Object>> riskSourceMap = new HashMap();
            riskSourceMap.put("equipments", map);//这个需要确认下
//            remoteWebSocketServer.sendMessage("equipmentMode", JSON.toJSONString(riskSourceMap));
//            // 推送设备状态信息
//            Alarm alarm = iAlarmDao.findByStatusTrueAndFireEquipmentPointCode(param.getPointCode());
//            String topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/monitorData");
//            webMqttComponent.publish(topic, JSON.toJSONString(view3dService.getEquipStatusList(alarm.getOrgCode())));
        } catch (Exception e) {
            log.error("推送前端数据失败-->" + JSON.toJSONString(param));
        }
    }


    @Override
    @Async
    public String processFireEqumtData(FireEquimentDataRo deviceData) throws Exception {
        //处理设备和巡检数据
        deviceData.setNodeState(deviceData.getValue());
        String batchNo = UUID.randomUUID().toString();
        deviceData.setBatchNo(batchNo);
//        Optional<FireEquipment> fireEquipment1 = this.iFireEquipmentDao.findById(deviceData.getFireEquimentId());
        FireEquipmentBo fireEquipment = null;

        Equipment equipment = null;
        if (fireEquipment != null) {
            deviceData.setCode(fireEquipment.getCode());
            equipment = impAndFireEquipMapper.queryImpEqumtByFireEquipmt(deviceData.getFireEquimentId());
            if (equipment != null) {
                deviceData.setMonitor(equipment.getName());
                deviceData.setEquimentId(String.valueOf(equipment.getId()));
//                List<RiskSource> riskSources = this.riskSourceMapper.queryByFireEqument(deviceData.getFireEquimentId());
                //asymbleWithParent(batchNo, riskSources, FireEquimentDataRo.class.getSimpleName(), deviceData.getFireEquimentId(), deviceData.getNodeState(), null, null);
                try {
                    alermContingency(deviceData.getBatchNo(), fireEquipment, equipment);
                } catch (Exception e) {
                    log.error("调用规则失败", e);
                }
            }
        }
        return "SUCCESS";
    }

    /**
     * 设备消息规则推送
     */
    @Async
    void fireEquipRuleMessagePush(AlarmParam deviceData, Toke toke) {
        ruleMsgSend(deviceData, toke, log, ruleTrigger);
    }

    static void ruleMsgSend(AlarmParam deviceData, Toke toke, Logger log, RuleTrigger ruleTrigger) {
        String bacthNo = UUID.randomUUID().toString();
        FireEquimentDataRo fireEquimentDataRo = new FireEquimentDataRo();
        deviceData.setBatchNo(bacthNo);
        BeanUtils.copyProperties(deviceData, fireEquimentDataRo);
        try {
            RequestContext.setToken(toke.getToke());
            RequestContext.setProduct(toke.getProduct());
            log.info("设备消息规则推送" + JSONObject.toJSONString(deviceData));
            ruleTrigger.publish(fireEquimentDataRo, "风险管控/fireEquiment", null);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }


//    private void saveFireEquipmentData(FireEquipmentPoint fireEquipmentPoint, FireEquipment fireEquipment, AlarmParam deviceData, String fireEquipmentPointType, Toke toke) {
//        if ("alarm_type_fire".equals(fireEquipmentPointType) || "alarm_type_trouble".equals(fireEquipmentPointType)) {
//            Alarm alarm = iAlarmDao.findByStatusTrueAndFireEquipmentPointCode(deviceData.getPointCode());
//            if (alarm != null) {
//                alarm.setFireEquipmentPointValue(deviceData.getState());
//                if ("false".equals(deviceData.getState())) {
//                    alarm.setRecoveryDate(new Date());
//                    alarm.setStatus(false);
//                } else {
//                    alarm.setFrequency((alarm.getFrequency() + 1));
//                    alarm.setUpdateDate(new Date());
//                }
//                iAlarmDao.save(alarm);
//            } else {
//                if ("true".equals(deviceData.getState())) {
//                    alarm = new Alarm();
//                    alarm.setFireEquipmentCode(fireEquipment.getCode());
//                    alarm.setFireEquipmentId(fireEquipment.getId());
//                    alarm.setFireEquipmentName(fireEquipment.getName());
//                    alarm.setFireEquipmentPointCode(fireEquipmentPoint.getCode());
//                    alarm.setFireEquipmentPointId(fireEquipmentPoint.getId());
//                    alarm.setFireEquipmentPointName(fireEquipmentPoint.getName());
//                    alarm.setFireEquipmentPointValue(deviceData.getState());
//                    alarm.setOrgCode(fireEquipment.getOrgCode());
//                    alarm.setType(fireEquipmentPointType);
//                    iAlarmDao.save(alarm);
//                }
//            }
//            if (alarm != null) {
//                if ("alarm_type_trouble".equals(fireEquipmentPointType)) {
//                    //通知刷新3d页面相关故障数据
//                    notifyAlarm(fireEquipmentPoint, deviceData);
//                    fireEquipRuleMessagePush(deviceData, toke);
//                } else {
//                    //通知刷新3d页面告警数据
//                    iDataRefreshService.refreshViewData(DataRefreshTypeEum.alarm.getCode());
//                    /**
//                     * 推送告警数据
//                     * 影响区域：消防安全=>火灾告警
//                     */
//                    String topic = String.format("/%s/%s/%s/%s", serviceName, stationName, "data/refresh", "fireSafety");
//                    webMqttComponent.publish(topic, JSON.toJSONString(view3dService.getSafetyExecuteListTop5("fire", fireEquipmentPoint.getOrgCode())));
//
//                }
//            }
//        } else {
//            if ("SWITCH".equals(fireEquipmentPoint.getType())) { //保存遥信信号数据到mysql中
//                FireEquipmentData fireEquipmentData = new FireEquipmentData();
//                fireEquipmentData.setEqPointCode(deviceData.getPointCode());
//                fireEquipmentData.seteValue(deviceData.getState());
//                fireEquipmentData.setInformationAddress(deviceData.getInformationAddress());
//                fireEquipmentData.setSoe(deviceData.getSoe());
//                fireEquipmentData.setIsInvalid(deviceData.getIsInvalid());
//                fireEquipmentData.setEqPointName(fireEquipmentPoint.getName());
//                fireEquipmentData.setEqPointUnit(fireEquipmentPoint.getUnit());
//                fireEquipmentData.setFireEquipmentPointId(fireEquipmentPoint.getId());
//                fireEquipmentData.setFireEquipmentId(fireEquipmentPoint.getFireEquipmentId());
//                fireEquipmentData.setType("monitor");
//                fireEquipmentData.setOrgCode(fireEquipment.getOrgCode());
//                iFireEquipmentDataDao.save(fireEquipmentData);
//                Map<String, Object> content = new HashMap<>();
//                content.put("id", fireEquipmentData.getId());
//                content.put("label", fireEquipmentData.getEqPointName());
//                content.put("changeDate", fireEquipmentData.getCreateDate());
//                content.put("orgCode", fireEquipment.getOrgCode());
//                content.put("status", deviceData.getSoe());
//                iDataRefreshService.sendRefreshDataWithArea(View3dRefreshAreaEum.monitor_data.getCode(), content);
//
//                /**
//                 * 推送设备状态
//                 * 影响区域：设备状态
//                 */
//                String topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/monitorData");
//                webMqttComponent.publish(topic, JSON.toJSONString(view3dService.getEquipStatusList(fireEquipment.getOrgCode())));
//            }
//        }
////        String topic = String.format("/%s/%s/%s", serviceName, StationEnum.YINAN.getCode(),"telesignaling");S
////        webMqttComponent.publish(topic, JSON.toJSONString(deviceData));
//
//        List<AlarmParam> list = new ArrayList<>();
//        list.add(deviceData);
//        //保存所有数据（遥测，遥信）到mongo
//        saveData(list, "soe");
//    }


//    @Override
//    public void saveData(List<AlarmParam> deviceDatas, String type) {
//        List<EquipCommunicationData> list = deviceDatas.stream().map(param -> {
//
//            log.debug("pointCode==" + param.getPointCode() + " InformationAddress==" + param.getInformationAddress());
//
//            // 格式化发送数据
//            sendRiskSourceData(param);
//
//            if (ObjectUtils.isEmpty(param.getPointCode())) {
//                EquipCommunicationData data = new EquipCommunicationData();
//                data.setIsInvalid(param.getIsInvalid());
//                data.setInformationAddress(param.getInformationAddress());
//                data.setRecDate(new Date());
//                data.setState(param.getState());
//                data.setSoe(param.getSoe());
//                data.setServiceId(param.getServiceId());
//                return data;
//            }
//            EquipCommunicationData data = equipmentService.findFireEquipmentByPointCode(param.getPointCode());
//            if (ObjectUtils.isEmpty(data)) {
//                return null;
//            }
//            data.setIsInvalid(param.getIsInvalid());
//            data.setInformationAddress(param.getInformationAddress());
//            data.setRecDate(new Date());
//            data.setState(param.getState());
//            data.setSoe(param.getSoe());
//            data.setServiceId(param.getServiceId());
//
//            if ("all".equals(type)) {
//                FireEquipmentPoint fireEquipmentPoint = iFireEquipmentPointDao.findOneByCode(param.getPointCode());
//                Dict dict = null;
//                if (fireEquipmentPoint.getAlarmType() != null) {
//                    Optional<Dict> dict1 = dictDao.findById(fireEquipmentPoint.getAlarmType());
//                    if (dict1.isPresent()) {
//                        dict = dict1.get();
//                    }
//                }
//                if (!param.getState().equals(fireEquipmentPoint.getValue())) {
//                    fireEquipmentPoint.setValue(param.getState());
//                    updateFirePointValue(fireEquipmentPoint.getId(), param.getState());
//                    Equipment equipment = impAndFireEquipMapper.queryImpEqumtByFireEquipmt(Long.valueOf(data.getFireEquipmentId()));
//                    if (!ObjectUtils.isEmpty(equipment)) {
//                        if (dict != null && dict.getDictValue().equals("alarm_type_trouble")) {
//                            notifyAlarm(fireEquipmentPoint, param);
//                        }
//                    }
//                }
//            }
//            if ("ANALOGUE".equals(data.getType())) {
//                sendAnalogue(data);
//            }
//
//            return data;
//        }).filter(param -> !ObjectUtils.isEmpty(param)).collect(Collectors.toList());
////        equipCommunicationDao.saveAll(list);
//    }

    /**
     * 设备告警触发fema的sod值
     */
//    private void notifyAlarm(FireEquipmentPoint fireEquipmentPoint, AlarmParam param) {
//        List<FmeaEquipmentPoint> fmeaEquipmentPoints = fmeaEquipmentPointMapper.listByEquipmentPointId(fireEquipmentPoint.getId());
//        Set<Long> fmeaIds = Sets.newHashSet();
//        List<Long> ids = Lists.newArrayList();
//        fmeaEquipmentPoints.forEach(fmeaEquipmentPoint -> {
//            ids.add(fmeaEquipmentPoint.getId());
//            fmeaIds.add(fmeaEquipmentPoint.getFmeaId());
//        });
//        Integer state = null;
//        if (param.getState().equals("true")) {
//            state = 1;
//        } else if (param.getState().equals("false")) {
//            state = 0;
//        }
//
//        if (state != null) {
//            if (ids.size() > 0) {
//                fmeaEquipmentPointMapper.updateStateByIds(state, ids);
//            }
//            final Integer st = state;
//            String monitor = fireEquipMapper.findById(fireEquipPointMapper.getByCode(param.getPointCode()).getFireEquipmentId()).getName();
//            RsDataQueue rsDataQueue = RsDataQueue.getInstance();
//            fmeaIds.forEach(fmeaId -> rsDataQueue.addEquipmentMessage(fmeaId, monitor, st));
//        }
//    }

    @Value("${autoSys.push.type}")
    private String pushType;
    @Value("${spring.application.name}")
    private String serviceName;

    @Async
    public void sendAnalogue(EquipCommunicationData data) {
        try {
            redisTemplate.opsForHash().put("Analogue", data.getPointCode(), data);
//            remoteWebSocketServer.sendMessage("plan", JSON.toJSONString(data));
            String topic = String.format("/%s/%s/%s", serviceName, stationName, "analogue");
            webMqttComponent.publish(topic, JSON.toJSONString(data));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<HashMap<String, Object>> queryRiskSourceSecondLevel(String compCode) {
        // TODO Auto-generated method stub
        return riskSourceMapper.queryRiskSourceSecondLevel(compCode);
    }

    @Override
    public List<RiskSourceTreeResponse> findRiskSourceEquipStatistics() {
        return riskSourceMapper.getRiskSourcesEquipment();
    }

    @Override
    public List<RiskSourceTreeResponse> findRiskSourceEquipStatistics(String[] type) {
        return riskSourceMapper.getRiskSourcesFireEquipmentByType(type);
    }

    @Override
    public List<RiskSourceTreeResponse> getCheckPointRiskSources() {
        return riskSourceMapper.getCheckPointRiskSource();
    }

    @Override
    public void queryContingencyDeviceStatus(ContingencyDeviceStatus contingencyDeviceStatus) {
//        String alarmType = null;
//
//        switch (contingencyDeviceStatus.getActionName()) {
//            case "确认灾情":
//                redisTemplate.opsForValue().set("equipmentId", contingencyDeviceStatus.getEquipmentId());
//                break;
//            case "断开上级电源":
//                alarmType = "alarm_type_power";
//                redisTemplate.opsForHash().put("currentContingency", "alarmType", alarmType);
//                redisTemplate.opsForHash().put("currentContingency", "contingencyPlan", contingencyDeviceStatus);
//                redisTemplate.opsForValue().set("equipmentId", contingencyDeviceStatus.getEquipmentId());
//                break;
//            case "关停设备": // 换流变
//                alarmType = "alarm_type_rheology";
//                redisTemplate.opsForHash().put("currentContingency", "alarmType", alarmType);
//                redisTemplate.opsForHash().put("currentContingency", "contingencyPlan", contingencyDeviceStatus);
//                redisTemplate.opsForValue().set("equipmentId", contingencyDeviceStatus.getEquipmentId());
//                break;
//            case "应急处置结束": // 换流变
//                redisTemplate.opsForHash().put("currentContingency", "batchNo", null);
//                redisTemplate.opsForHash().put("currentContingency", "contingencyPlan", null);
//                redisTemplate.opsForHash().put("currentContingency", "alarmType", null);
//                redisTemplate.opsForValue().set("equipmentId", null);
//                break;
//            default:
//                redisTemplate.opsForValue().set("equipmentId", contingencyDeviceStatus.getEquipmentId());
//                break;
//        }
//        if (alarmType == null) {
//            return;
//        }
//        contingencyDeviceStatus.setNeedStatus("true");
//        autoProcessContingency(contingencyDeviceStatus, alarmType);
    }

//    private void autoProcessContingency(ContingencyDeviceStatus contingencyDeviceStatus, String alarmType) {
//        if (ObjectUtils.isEmpty(contingencyDeviceStatus)) {
//            return;
//        }
//        int pointCount = fireEquipPointMapper.queryCountByEuipmentIdAndAlarmType(contingencyDeviceStatus.getEquipmentId(), alarmType);
//        int count = fireEquipPointMapper.queryStopCountByEuipmentIdAndAlarmType(contingencyDeviceStatus.getEquipmentId(), alarmType, contingencyDeviceStatus.getNeedStatus());
//        if (pointCount > 0 && pointCount == count) {
//            try {
//                String batchNo = (String) redisTemplate.opsForHash().get("currentContingency", "batchNo");
////                iContingencyInstance.setButtonExecuted(batchNo, contingencyDeviceStatus.getContingencyPlanId(), contingencyDeviceStatus.getButtonCode(), contingencyDeviceStatus.getConfirm());
////                iContingencyInstance.fire(batchNo, contingencyDeviceStatus.getStepCode(), contingencyDeviceStatus.getContingencyPlanId(), contingencyDeviceStatus.getButtonCode(), contingencyDeviceStatus.getConfirm(), contingencyDeviceStatus.getStepState());
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//            return;
//        }
//    }

    @Override
    public List<Map> queryContingencyWater() {
        List<Map> list = riskSourceMapper.queryContingencyWater();
        HashOperations hashOperations = redisTemplate.opsForHash();
        for (Map map : list) {
            double area = 0;
            if (!ObjectUtils.isEmpty(map.get("area"))) {
                area = Double.valueOf(map.get("area").toString());
            }
            String maxlevel = map.get("max_level") != null ? map.get("max_level").toString() : "0.0";
            String level = map.get("value") != null && StringUtil.isNumeric(map.get("value").toString()) ? String.format("%.2f", (Double.valueOf(map.get("value").toString()))) : maxlevel;

            String volume = String.format("%.2f", Double.valueOf(level) * area);
            if (hashOperations.size("Analogue") > 0) {
                if (ObjectUtils.isEmpty(map.get("CODE")) || !hashOperations.hasKey("Analogue", map.get("CODE"))) {
                    map.put("level", level);
                    map.put("volume", volume);
                    continue;
                }
                EquipCommunicationData data = (EquipCommunicationData) hashOperations.get("Analogue", map.get("CODE"));
                map.put("level", StringUtil.isNumeric(data.getState()) ? data.getState() : level);
                map.put("volume", String.format("%.2f", (Double.valueOf(map.get("level").toString()) * area)));
            } else {
                map.put("level", level);
                map.put("volume", volume);
            }
        }
        return list;
    }

    @Override
    public List<Map> queryFmeaByPointId(Long pointId) {
        return riskSourceMapper.queryFmeaByPointId(pointId);
    }

    @Override
    public Integer getChildTypeByPid(Long riskSourceId) {
        Long regionCount = riskSourceMapper.countByParentIdAndIsRegion(riskSourceId, "TRUE");
        if (!regionCount.equals(0L)) {
            //子节点有风险区域
            return 1;
        }
        Long pointCount = riskSourceMapper.countByParentIdAndIsRegion(riskSourceId, "FALSE");
        if (!pointCount.equals(0L)) {
            //子节点有风险点
            return 2;
        }
        return 3;
    }

    /**
     * 修改、添加导致rpn、rpni改变
     */
    @Override
    public void notifyFmeaFromUpdate(String toke, String product, String appKey, Long fmeaId, String nofityType, String userName) {
        Fmea fmea = fmeaMapper.getById(fmeaId);
        if (fmea == null) {
            return;
        }
        if (fmea.getEvaluationOid() != null && fmea.getEvaluationSid() != null && fmea.getEvaluationDid() != null) {
            MsgParamBo msgParamBo = new MsgParamBo();
            BigDecimal oidValue = new BigDecimal(fmea.getOidValue());
            BigDecimal sidValue = new BigDecimal(fmea.getSidValue());
            BigDecimal didValue = new BigDecimal(fmea.getDidValue());
            //1.1计算rpni
            BigDecimal rpni = oidValue.multiply(sidValue).multiply(didValue).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal rpn;
            //1.2未评价过，计算绑定的巡检点项 设备点位故障率
            if (fmea.getNewEvaluationOid() == null) {
                EvaluationModel evaluationModel = this.getEvaluationModel(fmeaId);
                if (evaluationModel != null) {//已经绑定点位或者巡检点项且匹配到风险模型，则更新为计算后的结果
                    BigDecimal newOidValue = new BigDecimal(evaluationModel.getCoefficient());
                    rpn = newOidValue.multiply(sidValue).multiply(didValue).setScale(2, BigDecimal.ROUND_HALF_UP);
                    fmea.setNewEvaluationOid(evaluationModel.getId());
                } else {//未绑定点位或者巡检点项或者匹配不到风险模型，则更新为rpn与rpni一致
                    fmea.setNewEvaluationOid(fmea.getEvaluationOid());
                    rpn = rpni;
                }
            } else {
                BigDecimal newOidValue = new BigDecimal(fmea.getNewOidValue());
                rpn = newOidValue.multiply(sidValue).multiply(didValue).setScale(2, BigDecimal.ROUND_HALF_UP);
            }
            List<RiskLevel> levels = riskLevelDao.findAll();
            RiskLevel newLevel = RpnUtils.getBetweenLevel(rpn, levels);
            JpushMsgBo jpushMsgBo = new JpushMsgBo();
            fmea.setRpni(rpni);
            fmea.setRpn(rpn);
            if (newLevel != null) {
                fmea.setRiskLevelId(newLevel.getId());
                msgParamBo.setAppKey(appKey);
                msgParamBo.setToke(toke);
                msgParamBo.setProduct(product);
                msgParamBo.setFmea(fmea);
                msgParamBo.setManagerLevel(newLevel.getManageLevel());
                msgParamBo.setLevel(newLevel.getName());
                msgParamBo.setUserName(userName);
                msgParamBo.setNotifyType(nofityType);
                jpushMsgBo = this.getJushMessageInfo(msgParamBo);
            }
            //1.3更新fmea
            fmeaMapper.updateRpn(fmea);
            //2.计算上级风险值（风险点及父节点）
            this.notifyRiskSource(newLevel.getOrgCode(), fmeaId, fmea.getRiskSourceId(), nofityType, jpushMsgBo);
            String topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/incidenceSeverityMatrix");
            webMqttComponent.publish(topic, JSON.toJSONString(queryForMatrix()));
        }
    }

    private JpushMsgBo getJushMessageInfo(MsgParamBo msgParam) {
        JpushMsgBo msgBo = new JpushMsgBo();
        Optional<RiskFactor> optional = iRiskFactorDao.findById(msgParam.getFmea().getRiskFactorsId());
        if (optional.isPresent()) {
            JpushMsgContentBo jpushMsgContentBo = new JpushMsgContentBo(optional.get().getName(), msgParam.getNotifyType());
            jpushMsgContentBo.setExecute(msgParam.getUserName());
            jpushMsgContentBo.setLevelIsChange(msgParam.getLevelIsChange());
            jpushMsgContentBo.setLevel(msgParam.getLevel());
            jpushMsgContentBo.setRelationName(msgParam.getRelationName());
            jpushMsgContentBo.setRpn(msgParam.getRpn());
            jpushMsgContentBo.setCheckStatus(msgParam.getCheckStatus());
            msgBo.setTarget(this.getJpushTarget(msgParam));
            msgBo.setMsg(jpushMsgContentBo);
        }
        return msgBo;
    }

    private Set<String> getJpushTarget(MsgParamBo msgParam) {
        Set<String> targets = new LinkedHashSet<>();
        Set<String> userIds = this.getUsersByLevel(msgParam.getManagerLevel(), msgParam.getFmea());
        userIds.forEach(userId -> {
            AgencyUserModel user = remoteSecurityService.getUserById(msgParam.getToke(), msgParam.getProduct(), msgParam.getAppKey(), userId);
            if (user != null) {
                String target = user.getMobile();
                targets.add(target);
            }
        });
        return targets;
    }

    private Set<String> getUsersByLevel(Integer level, Fmea fmea) {
        Set<String> userIds = new HashSet<>();
        if (level.equals(1)) {
            userIds.add(fmea.getCompanyLeader());
            userIds.add(fmea.getDepartmentLeader());
            userIds.add(fmea.getGroupLeader());
            userIds.add(fmea.getPersonLeader());
        } else if (level.equals(2)) {
            userIds.add(fmea.getDepartmentLeader());
            userIds.add(fmea.getGroupLeader());
            userIds.add(fmea.getPersonLeader());
        } else if (level.equals(3)) {
            userIds.add(fmea.getGroupLeader());
            userIds.add(fmea.getPersonLeader());
        } else if (level.equals(4)) {
            userIds.add(fmea.getPersonLeader());
        }
        userIds.remove(null);
        return userIds;
    }

    /**
     * 告警或者不合格项导致fmea的rpn、new_evaluation_oid改变
     */
    @Override
    public void notifyFmeaFromAbnormal(
            String toke, String product, String appKey,
            Long fmeaId, String notifyType, String userName, String relationName, String checkStatus) {
        Fmea fmea = fmeaMapper.getById(fmeaId);
        if (fmea == null) {
            return;
        }
        if (fmea.getEvaluationOid() != null && fmea.getEvaluationSid() != null && fmea.getEvaluationDid() != null) {
            List<FmeaEquipmentPoint> equipmentPoints = fmeaEquipmentPointMapper.listFmeaByFmeaId(fmeaId);
            List<FmeaPointInputitem> pointInputitems = fmeaPointInputitemMapper.listFmeaByFmeaId(fmeaId);
            //1.准备更新数据
            Double maxRate = RpnUtils.getMaxRate(equipmentPoints, pointInputitems);
            if (maxRate != null) {
                //1.1根据设备和巡检数据获取高的故障率
                List<EvaluationModel> oModels = iEvaluationModelDao.findAllByType("O");
                EvaluationModel oEvaluationModel = getBetweenModel(maxRate, oModels);
                if (oEvaluationModel != null) {
                    BigDecimal newOidValue = new BigDecimal(oEvaluationModel.getCoefficient());
                    BigDecimal sidValue = new BigDecimal(fmea.getSidValue());
                    BigDecimal didValue = new BigDecimal(fmea.getDidValue());
                    BigDecimal rpn = newOidValue.multiply(sidValue).multiply(didValue).setScale(2, BigDecimal.ROUND_HALF_UP);
                    List<RiskLevel> levels = riskLevelDao.findAll();
                    RiskLevel newLevel = RpnUtils.getBetweenLevel(rpn, levels);
                    fmea.setRpn(rpn);
                    fmea.setNewEvaluationOid(oEvaluationModel.getId());
                    JpushMsgBo jpushMsgBo = new JpushMsgBo();
                    MsgParamBo msgParamBo = new MsgParamBo();
                    if (newLevel != null) {
                        //1.2根据风险等级对应的责任等级获取责任人
                        fmea.setRiskLevelId(newLevel.getId());
                        msgParamBo.setAppKey(appKey);
                        msgParamBo.setToke(toke);
                        msgParamBo.setProduct(product);
                        msgParamBo.setFmea(fmea);
                        msgParamBo.setManagerLevel(newLevel.getManageLevel());
                        msgParamBo.setLevel(newLevel.getName());
                        msgParamBo.setUserName(userName);
                        msgParamBo.setNotifyType(notifyType);
                        msgParamBo.setCheckStatus(checkStatus);
                        msgParamBo.setRelationName(relationName);
                        msgParamBo.setRpn(rpn);
                        jpushMsgBo = this.getJushMessageInfo(msgParamBo);
                    }
                    //1.3.更新fmea的rpn、风险等级及newOid
                    fmeaMapper.updateRpn(fmea);
                    String topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/incidenceSeverityMatrix");
                    webMqttComponent.publish(topic, JSON.toJSONString(queryForMatrix()));
                    //2.计算风险点rpn、rpni、riskLevelId
                    this.notifyRiskSource(newLevel.getOrgCode(), fmeaId, fmea.getRiskSourceId(), notifyType, jpushMsgBo);
                }
            }
        }
    }

    private void saveRpnLog(Long riskSourceId, Long fmeaId, BigDecimal rpn, BigDecimal rpni, String notifyType) {
        RpnChangeLog rpnChangeLog = new RpnChangeLog();
        rpnChangeLog.setRiskSourceId(riskSourceId);
        rpnChangeLog.setRpn(rpn);
        rpnChangeLog.setRpni(rpni);
        rpnChangeLog.setType(RpnUtils.getChangeType(rpn, rpni));
        rpnChangeLog.setTriggerBy(fmeaId);
        rpnChangeLog.setTriggerType(notifyType);
        rpnChangeLog.setFmeaId(fmeaId);
        rpnChangeLog.setTriggerType(notifyType);
        iRpnChangeLogDao.save(rpnChangeLog);
    }

    private EvaluationModel getBetweenModel(Double maxRate, List<EvaluationModel> oModels) {
        for (EvaluationModel model : oModels) {
            String str = model.getDescribe().replaceAll("O", maxRate.toString());
            if (JexlUtil.convertToCode(str)) {
                return model;
            }
        }
        return null;
    }

    /**
     * fmea的更新导致rpn、rpni的值改变
     */
    @Override
    public void notifyRiskSource(String orgCode, Long fmeaId, Long riskSourceId, String notifyType, JpushMsgBo jpushMsgBo) {
        Optional<RiskSource> riskSource1 = iRiskSourceDao.findById(riskSourceId);
        RiskSource riskSource = null;
        if (riskSource1.isPresent()) {
            riskSource = riskSource1.get();
        } else {
            return;
        }
        List<Fmea> fmeas = fmeaMapper.listByRiskSourceId(riskSourceId);
        if (CollectionUtils.isEmpty(fmeas)) {//fema全部删除
            BigDecimal resetValue = new BigDecimal("0");
            riskSource.setRpn(null);
            riskSource.setRpni(null);
            riskSource.setRiskLevelId(null);
            riskSource.setFlickerFrequency(0);
            //1.更新fmea对应风险点rpn、rpni、level
            riskSourceMapper.updateRpnForNull(riskSource);
            //2.记录风险点rpn变化流水
            this.saveRpnLog(riskSource.getId(), fmeaId, resetValue, resetValue, notifyType);

            //3.更新父节点rpn、rpni、风险等级
            this.updateParentRpn(riskSource.getParentId());
            //4.通知全景监控屏幕数据刷新
            iDataRefreshService.refreshViewData(DataRefreshTypeEum.rpn.getCode());
        } else {//fmea评价、巡检、告警
            RpnCalculationBo rpnValueBo = RpnUtils.calRpnAndRpni(fmeas);
            if (rpnValueBo.isEmpty()) {
                return;
            }
            Fmea caluFmea = fmeaMapper.getById(fmeaId);
            Integer rpnDiffer = 0;
            if (caluFmea != null) {
                rpnDiffer = caluFmea.getRpn().intValue() - caluFmea.getRpni().intValue();
            }
            String checkStatus = "";
            if (jpushMsgBo != null) {
                checkStatus = jpushMsgBo.getMsg().getCheckStatus();
            }
            BigDecimal rpn = rpnValueBo.getRpn();
            BigDecimal rpni = rpnValueBo.getRpni();
            List<RiskLevel> levels = riskLevelDao.findAll();
            RiskLevel newRiskLevel = RpnUtils.getBetweenLevel(rpn, levels);
            RiskLevel oldRiskLevel = RpnUtils.getBetweenLevel(rpni, levels);
            if (newRiskLevel != null && oldRiskLevel != null) {
                riskSource.setRpn(rpn);
                riskSource.setRpni(rpni);
                riskSource.setRiskLevelId(newRiskLevel.getId());
                String changeType = RpnUtils.calChangeTypeByLevel(oldRiskLevel.getLevel(), newRiskLevel.getLevel());
                riskSource.setFlickerFrequency(RpnUtils.calRiskPointFrequency(rpn, rpni, changeType));
                //1.更新fmea对应风险点rpn、rpni、level
                riskSourceMapper.updateRpn(riskSource);
                //2.记录风险点rpn变化流水
                this.saveRpnLog(riskSource.getId(), fmeaId, rpn, rpni, notifyType);

                //3.更新父节点rpn、rpni、风险等级
                this.updateParentRpn(riskSource.getParentId());
                //4.极光推送给手机客户端
                if ("recovery".equals(notifyType) || "fmeaUpdate".equals(notifyType) || ("alarm".equals(notifyType) && rpnDiffer > 0) || ("patrol".equals(notifyType) && rpnDiffer > 0 && CheckStatusEnum.UNQUALIFIED.getName().equals(checkStatus))) {
//                    jpushRiskSourceMessage(jpushMsgBo);
                }
                //5.规则告警（消息）
                if ("recovery".equals(notifyType) || "fmeaUpdate".equals(notifyType) || ("alarm".equals(notifyType) && rpnDiffer > 0) || ("patrol".equals(notifyType) && rpnDiffer > 0 && CheckStatusEnum.UNQUALIFIED.getName().equals(checkStatus))) {
                    notifyRule(riskSourceId, rpn, rpni, notifyType, changeType, jpushMsgBo.getMsg());
                }
                //6.通知全景监控屏幕数据刷新
                iDataRefreshService.refreshViewData(DataRefreshTypeEum.rpn.getCode());
            }
        }
        try {
            String topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/situationMap");
            webMqttComponent.publish(topic, JSON.toJSONString(queryRiskSourceSecondLevel(orgCode)));
            topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/riskDegreeHistogram");
            webMqttComponent.publish(topic, JSON.toJSONString(queryRPNReport()));
            topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/riskDegreePie");
            webMqttComponent.publish(topic, JSON.toJSONString(queryForRiseUp()));
            topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/incidenceSeverityMatrix");
            webMqttComponent.publish(topic, JSON.toJSONString(queryForMatrix()));

            // 今日安全
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            String dateString = formatter.format(new Date());
            if (StringUtils.isEmpty(orgCode)) {
                orgCode = riskSource.getOrgCode();
            }
            String topicOne = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/todaySafetyIndex");
            webMqttComponent.publish(topicOne, JSON.toJSONString(view3dService.getSafetyIndexInfoByDate(orgCode, dateString)));

            // 消防安全
            String topicTow = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/fireSafety");
            webMqttComponent.publish(topicTow, JSON.toJSONString(view3dService.getSafetyExecuteListTop5("risk", orgCode)));
            webMqttComponent.publish(topicTow, JSON.toJSONString(view3dService.getSafetyExecuteListTop5("check", orgCode)));
            webMqttComponent.publish(topicTow, JSON.toJSONString(view3dService.getSafetyExecuteListTop5("fire", orgCode)));

            // 一周安全趋势
            String topicThree = String.format("/%s/%s/%s/%s", serviceName, stationName, "data/refresh", "weekSafetyIndex");
            webMqttComponent.publish(topicThree, JSON.toJSONString(view3dService.getSafetyIndexWeek(orgCode)));

        } catch (Exception e) {
            log.error("数据获取失败", e);
        }

    }

    @Override
    public void notifyFmeaFromDelete(Long riskSourceId, String from) {
        //1.计算风险点风险值信息
        this.notifyRiskSource(null, 0L, riskSourceId, from, null);
    }

    @Override
    public void notifyRiskSourceDelete(Long parentId) {

        Optional<RiskSource> riskSource1 = iRiskSourceDao.findById(parentId);
        RiskSource riskSource = null;
        if (riskSource1.isPresent()) {
            riskSource = riskSource1.get();
        } else {
            return;
        }

        //1.风险点删除触发更新父节点rpn、rpni、风险等级
        this.updateParentRpn(parentId);
        //2.通知全景监控屏幕数据刷新
        iDataRefreshService.refreshViewData(DataRefreshTypeEum.rpn.getCode());


        try {
            String topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/situationMap");
            webMqttComponent.publish(topic, JSON.toJSONString(queryRiskSourceSecondLevel(riskSource.getOrgCode())));
            topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/riskDegreeHistogram");
            webMqttComponent.publish(topic, JSON.toJSONString(queryRPNReport()));
            topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/riskDegreePie");
            webMqttComponent.publish(topic, JSON.toJSONString(queryForRiseUp()));
            topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/incidenceSeverityMatrix");
            webMqttComponent.publish(topic, JSON.toJSONString(queryForMatrix()));

            // 今日安全
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            String dateString = formatter.format(new Date());
            String orgCode = riskSource.getOrgCode();
            if (StringUtils.isEmpty(orgCode)) {
                orgCode = riskSource.getOrgCode();
            }
            String topicOne = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/todaySafetyIndex");
            webMqttComponent.publish(topicOne, JSON.toJSONString(view3dService.getSafetyIndexInfoByDate(orgCode, dateString)));

            // 消防安全
            String topicTow = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/fireSafety");
            webMqttComponent.publish(topicTow, JSON.toJSONString(view3dService.getSafetyExecuteListTop5("risk", orgCode)));
            webMqttComponent.publish(topicTow, JSON.toJSONString(view3dService.getSafetyExecuteListTop5("check", orgCode)));
            webMqttComponent.publish(topicTow, JSON.toJSONString(view3dService.getSafetyExecuteListTop5("fire", orgCode)));

            // 一周安全趋势
            String topicThree = String.format("/%s/%s/%s/%s", serviceName, stationName, "data/refresh", "weekSafetyIndex");
            webMqttComponent.publish(topicThree, JSON.toJSONString(view3dService.getSafetyIndexWeek(orgCode)));

        } catch (Exception e) {
            log.error("数据获取失败", e);
        }

    }

    private void updateParentRpn(long parentId) {
        Optional<RiskSource> riskSource1 = iRiskSourceDao.findById(parentId);
        RiskSource riskSource = null;
        if (riskSource1.isPresent()) {
            riskSource = riskSource1.get();
        }
        if (riskSource != null) {
            List<RiskSource> riskSourceList = new ArrayList<>();
            List<Long> ids = new ArrayList<>();
            riskSourceList = iRiskSourceDao.findByParentId(riskSource.getId());
            //递归获取区域(含子区域)所有点
            this.getAllRiskPoint(ids, riskSourceList);
            if (CollectionUtils.isEmpty(ids)) {//没有风险点，则赋初始值null
                riskSource.setRpn(null);
                riskSource.setRpni(null);
                riskSource.setRiskLevelId(null);
            } else {
                List<Fmea> fmeas = fmeaMapper.listByRiskSourceIds(ids);
                RpnCalculationBo rpnValueBo = RpnUtils.calRpnAndRpni(fmeas);
                if (rpnValueBo.isEmpty()) {
                    riskSource.setRpn(null);
                    riskSource.setRpni(null);
                    riskSource.setRiskLevelId(null);
                    iRiskSourceDao.save(riskSource);
                    return;
                }
                BigDecimal rpn = rpnValueBo.getRpn();
                BigDecimal rpni = rpnValueBo.getRpni();
                List<RiskLevel> levels = riskLevelDao.findAll();
                RiskLevel newRiskLevel = RpnUtils.getBetweenLevel(rpn, levels);
                if (newRiskLevel != null) {
                    riskSource.setRpn(rpn);
                    riskSource.setRpni(rpni);
                    riskSource.setRiskLevelId(newRiskLevel.getId());
                }
            }
            iRiskSourceDao.save(riskSource);
            this.updateParentRpn(riskSource.getParentId());
        }
    }

    /**
     * 获得子节点：巡检点
     *
     * @param ids            返回
     * @param riskSourceList 风险点区域列表
     */
    private void getAllRiskPoint(List<Long> ids, List<RiskSource> riskSourceList) {
        //TODO 递归
        for (RiskSource riskSource : riskSourceList) {
            if (riskSource.getIsRegion().equalsIgnoreCase("TRUE")) {
                List<RiskSource> list = iRiskSourceDao.findByParentId(riskSource.getId());
                if (list != null) {
                    this.getAllRiskPoint(ids, list);
                }
            } else {
                ids.add(riskSource.getId());
            }
        }
    }

    /**
     * 极光推送
     */
    private void jpushRiskSourceMessage(JpushMsgBo jpushMsgBo) {
        if (jpushMsgBo == null) {
            return;
        }
        JpushMsgContentBo jpushMsgContentBo = jpushMsgBo.getMsg();
        Set<String> target = jpushMsgBo.getTarget();
        target.remove(null);
        if (jpushMsgContentBo.getSend()) {
            PushMsgParam pushMsgParam = new PushMsgParam();
            pushMsgParam.setRecivers(Lists.newArrayList(target));
            pushMsgParam.setContent(jpushMsgContentBo.genMessage());
            pushMsgParam.setSubject(jpushMsgContentBo.getSubject());
            pushMsgParam.setType(JPushTypeEnum.ALIAS.getCode());
            appMessagePushService.sendMessage(pushMsgParam);
        }
    }

    /**
     * 规则告警
     */
    private void notifyRule(
            Long id,
            BigDecimal rpnr,
            BigDecimal rpni,
            String notifyType,
            String changeType, JpushMsgContentBo msgContentBo) {
        RiskSourceRuleRo riskSourceRuleRo = new RiskSourceRuleRo();
        riskSourceRuleRo.setId(id);
        riskSourceRuleRo.setRpnr(rpnr);
        riskSourceRuleRo.setRpni(rpni);
        riskSourceRuleRo.setLevelChangeType(changeType);
        riskSourceRuleRo.setType(notifyType);
        riskSourceRuleRo.setContent(msgContentBo.genMessage());
        riskSourceRuleRo.setTitle(msgContentBo.getSubject());
        riskSourceRuleRo.setRg(String.valueOf(rpnr.subtract(rpni).toBigInteger()));
        try {
            log.info("规则告警发送数据为" + JSONObject.toJSONString(riskSourceRuleRo));
            ruleTrigger.publish(riskSourceRuleRo, "风险管控/riskSource", null);// 没有配决策流，processIds传null即可
        } catch (Exception e) {
            log.error("调用规则异常", e);
        }
    }

    @Override
    public List<RegionTreeResponse> findRegionTree(String channelType, String orgCode) {
        List<RegionTreeResponse> regionList = riskSourceMapper.getRegionList(channelType, orgCode);
        return getRiskRegionTree(regionList);
    }

    //区域列表转树
    private static List<RegionTreeResponse> getRiskRegionTree(List<RegionTreeResponse> list) {
        HashMap<Long, RegionTreeResponse> hashMap = new HashMap<>();
        list.forEach(e -> hashMap.put(e.getId(), e));
        List<RegionTreeResponse> treeList = new ArrayList<RegionTreeResponse>();
        list.forEach(r -> {
            Long parentId = r.getParentId();
            if (parentId != null) {
                RegionTreeResponse pRegion = hashMap.get(parentId);
                if (pRegion != null) {
                    pRegion.getChildren().add(r);
                } else {
                    treeList.add(r);
                }
            }
        });
        return treeList;
    }

    @Override
    public HashMap<String, Object> findRegionById(Long id, String orgCode, String channelType) {
        HashMap<String, Object> regionDetail = riskSourceMapper.findRegionById(id, orgCode, channelType);
        if (regionDetail != null) {
            Long isBind = (Long) regionDetail.get("isBind");
            regionDetail.put("isBind", isBind == 0 ? false : true);
            String ue4Location = (String) regionDetail.get("ue4Location");
            regionDetail.put("ue4Location", ue4Location == null ? new JSONArray() : JSON.parseArray(ue4Location));
            String ue4Rotation = (String) regionDetail.get("ue4Rotation");
            regionDetail.put("ue4Rotation", ue4Rotation == null ? new JSONArray() : JSON.parseArray(ue4Rotation));
            String ue4Extent = (String) regionDetail.get("ue4Extent");
            regionDetail.put("ue4Extent", ue4Extent == null ? new JSONArray() : JSON.parseArray(ue4Extent));
        }
        return regionDetail;
    }

    @Override
    public void batchSaveRegionUe4(List<BindRegionBo> regionBoList, String orgCode) {
        riskSourceMapper.batchSaveRegionUe4(regionBoList);
        try {
            String topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/situationMap");
            webMqttComponent.publish(topic, JSON.toJSONString(queryRiskSourceSecondLevel(orgCode)));
            topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/riskDegreeHistogram");
            webMqttComponent.publish(topic, JSON.toJSONString(queryRPNReport()));
            topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/riskDegreePie");
            webMqttComponent.publish(topic, JSON.toJSONString(queryForRiseUp()));
            topic = String.format("/%s/%s/%s", serviceName, stationName, "data/refresh/incidenceSeverityMatrix");
            webMqttComponent.publish(topic, JSON.toJSONString(queryForMatrix()));
        } catch (Exception e) {
            log.error("数据获取失败", e);
        }
    }

    private EvaluationModel getEvaluationModel(Long fmeaId) {
        List<FmeaEquipmentPoint> equipmentPoints = fmeaEquipmentPointMapper.listFmeaByFmeaId(fmeaId);
        List<FmeaPointInputitem> pointInputitems = fmeaPointInputitemMapper.listFmeaByFmeaId(fmeaId);
        Double maxRate = RpnUtils.getMaxRate(equipmentPoints, pointInputitems);
        if (maxRate != null) {
            List<EvaluationModel> oModels = iEvaluationModelDao.findAllByType("O");
            EvaluationModel oEvaluationModel = getBetweenModel(maxRate, oModels);
            return oEvaluationModel;
        }
        return null;
    }

    public List<String> getNumberPlan(Long id) {
        List<String> ruleId = planDetailMapper.getRuleIdByEquipment(id);
        return ruleId;
    }

    @Override
    public RiskSource updateAreaSyn(String userId, String orgCode, RiskSourceSynBo synBo) {
        // 1.根据sourceId查询之前节点，赋值null
        Optional<RiskSource> op = iRiskSourceDao.findBySourceId(synBo.getId());
        if (op.isPresent()) {
            RiskSource riskSource = op.get();
            riskSource.setSourceId(null);
            iRiskSourceDao.save(riskSource);
        }

        // 新增
        RiskSource  riskSource = new RiskSource();
        Bean.copyExistPropertis(synBo, riskSource);
        fillBasicParams(userId, orgCode, synBo.getId(), riskSource);
        riskSource = iRiskSourceDao.save(riskSource);

        return riskSource;
    }

}

