| package com.zy.acs.manager.core.service; | 
|   | 
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | 
| import com.zy.acs.common.utils.GsonUtils; | 
| import com.zy.acs.common.utils.Utils; | 
| import com.zy.acs.framework.common.Cools; | 
| import com.zy.acs.framework.common.SnowflakeIdWorker; | 
| import com.zy.acs.framework.exception.CoolException; | 
| import com.zy.acs.manager.common.utils.MapDataUtils; | 
| import com.zy.acs.manager.core.constant.MapDataConstant; | 
| import com.zy.acs.manager.core.domain.BlockVehicleDto; | 
| import com.zy.acs.manager.core.domain.TaskPosDto; | 
| import com.zy.acs.manager.core.domain.type.BlockSeverityType; | 
| import com.zy.acs.manager.core.service.astart.MapDataDispatcher; | 
| import com.zy.acs.manager.core.service.astart.NavigateNode; | 
| import com.zy.acs.manager.core.service.astart.RetreatNavigateNode; | 
| import com.zy.acs.manager.core.service.astart.WaveNodeType; | 
| import com.zy.acs.manager.manager.entity.*; | 
| import com.zy.acs.manager.manager.enums.JamStateType; | 
| import com.zy.acs.manager.manager.enums.SegmentStateType; | 
| import com.zy.acs.manager.manager.enums.TaskTypeType; | 
| import com.zy.acs.manager.manager.service.*; | 
| import lombok.extern.slf4j.Slf4j; | 
| import org.springframework.beans.factory.annotation.Autowired; | 
| import org.springframework.stereotype.Component; | 
| import org.springframework.transaction.annotation.Transactional; | 
| import org.springframework.transaction.interceptor.TransactionAspectSupport; | 
|   | 
| import java.util.ArrayList; | 
| import java.util.Arrays; | 
| import java.util.Date; | 
| import java.util.List; | 
| import java.util.stream.Collectors; | 
|   | 
| /** | 
|  * Wavefront | 
|  * Created by vincent on 6/25/2024 | 
|  */ | 
| @Slf4j | 
| @Component | 
| public class TrafficService { | 
|   | 
|     @Autowired | 
|     private AgvService agvService; | 
|     @Autowired | 
|     private AgvDetailService agvDetailService; | 
|     @Autowired | 
|     private CodeService codeService; | 
|     @Autowired | 
|     private TravelService travelService; | 
|     @Autowired | 
|     private SegmentService segmentService; | 
|     @Autowired | 
|     private MainService mainService; | 
|     @Autowired | 
|     private MainLockWrapService mainLockWrapService; | 
|     @Autowired | 
|     private MapService mapService; | 
|     @Autowired | 
|     private MapDataDispatcher mapDataDispatcher; | 
|     @Autowired | 
|     private SnowflakeIdWorker snowflakeIdWorker; | 
|     @Autowired | 
|     private AgvModelService agvModelService; | 
|     @Autowired | 
|     private RetreatNavigateService retreatNavigateService; | 
|     @Autowired | 
|     private TaskService taskService; | 
|     @Autowired | 
|     private JamService jamService; | 
|     @Autowired | 
|     private AvoidWaveCalculator avoidWaveCalculator; | 
|   | 
|     @Transactional | 
|     public synchronized void trigger(Segment segment) { | 
|         try { | 
|             Date now = new Date(); | 
|             Travel travel = travelService.getById(segment.getTravelId()); | 
|             Agv agv = agvService.getById(travel.getAgvId()); | 
|             AgvDetail agvDetail = agvDetailService.selectByAgvId(travel.getAgvId()); | 
|             long endNode = segment.getEndNode(); | 
|   | 
|             // valid ---------------------------------------------------- | 
|             if (!agvService.judgeEnable(agv.getId())) { | 
|                 return; | 
|             } | 
|             if (!Cools.isEmpty(segmentService.getByAgvAndState(agv.getId(), SegmentStateType.RUNNING.toString()))) { | 
|                 return; | 
|             } | 
|             List<Segment> waitingSegList = segmentService.getByAgvAndState(agv.getId(), SegmentStateType.WAITING.toString()); | 
|             if (!Cools.isEmpty(waitingSegList)) { | 
|                 for (Segment waitingSeg : waitingSegList) { | 
|                     if (!waitingSeg.getId().equals(segment.getId())) { | 
| //                        log.error("AGV[{}] 任务异常,服务器错误!!!", agv.getUuid()); | 
|                         return; | 
|                     } | 
|                 } | 
|             } | 
|   | 
|             // dead lane | 
|             if (jamService.count(new LambdaQueryWrapper<Jam>() | 
|                     .eq(Jam::getJamAgv, agv.getId()) | 
|                     .eq(Jam::getJamSeg, segment.getId()) | 
|                     .eq(Jam::getCycleAvo, 1) | 
|                     .eq(Jam::getCycleCode, endNode) | 
|                     .eq(Jam::getState, JamStateType.RUNNING.toString()) | 
|             ) > 0) { | 
|                 return; | 
|             } | 
|   | 
|             // deprecate jam | 
|             if (this.isJamBeDeprecatedByAvo(segment.getId())) { | 
|                 if (this.skipCurrSegment(segment)) { | 
|                     return; | 
|                 } | 
|             } | 
|   | 
|             // execute ----------------------------------------------- | 
|             //        ArrayList<List<TaskPosDto>> list = JSON.parseObject(travel.getTaskContent(), new TypeReference<ArrayList<List<TaskPosDto>>>() {}); | 
|   | 
|             // get path list | 
|             avoidWaveCalculator.calcWaveScope();    // * sync wave scope | 
|   | 
|             // checkout path | 
|             Code startCode = codeService.getById(agvDetail.getRecentCode()); | 
|             Code endCode = codeService.getById(endNode); | 
|             List<String> pathList = this.checkoutPath(agv, startCode, endCode, segment); | 
|             if (Cools.isEmpty(pathList)) { | 
|                 return; | 
|             } | 
|   | 
|             List<Segment> segmentList = new ArrayList<>(); | 
|             segmentList.add(segment); | 
|   | 
|             String lastCodeData = pathList.get(pathList.size() - 1); | 
|             if (!endCode.getData().equals(lastCodeData)) { | 
|                 // slice | 
|                 Code lastCode = codeService.selectByData(lastCodeData); | 
|   | 
| //                if (pathList.size() <= MIN_SLICE_PATH_LENGTH) { | 
| //                    return; | 
| //                } | 
|   | 
|                 // revert | 
|                 segment.setState(SegmentStateType.INIT.toString()); | 
|                 segment.setUpdateTime(now); | 
|                 if (!segmentService.updateById(segment)) { | 
|                     log.error("Segment [{}] failed to update !!!", segment.getGroupId() + " - " + segment.getSerial()); | 
|                 } | 
|                 segmentList.clear(); | 
|   | 
|                 // new move seg | 
|                 Segment insertSeg = new Segment(); | 
|                 insertSeg.setUuid(String.valueOf(snowflakeIdWorker.nextId()).substring(3)); | 
|                 insertSeg.setTravelId(travel.getId()); | 
|                 insertSeg.setAgvId(agv.getId()); | 
|                 insertSeg.setTaskId(segment.getTaskId()); | 
|                 insertSeg.setSerial(segment.getSerial() - 1); | 
|                 insertSeg.setEndNode(lastCode.getId()); | 
|                 insertSeg.setPosType(TaskPosDto.PosType.MOVE.toString()); | 
|                 insertSeg.setState(SegmentStateType.WAITING.toString()); | 
|                 if (!segmentService.save(insertSeg)) { | 
|                     log.error("Segment [{}] failed to save !!!", segment.getTravelId() + " - " + segment.getSerial()); | 
|                 } | 
|                 segmentList.add(insertSeg); | 
|   | 
|             } else { | 
|   | 
|                 // complete first segment then merge behind segment | 
|                 int serial = segment.getSerial(); | 
|                 boolean interrupt = false; | 
|                 while (!interrupt) { | 
|   | 
|                     Segment nextStep = segmentService.getNextStepOfInit(travel.getId(), serial); | 
|                     serial ++; | 
|                     if (null == nextStep) { | 
|                         interrupt = true; | 
|                     } else { | 
|                         if (nextStep.getEndNode() == endNode) { | 
|   | 
|                             segmentList.add(nextStep); | 
|                         } else { | 
|                             interrupt = true; | 
|                         } | 
|                     } | 
|   | 
|                 } | 
|             } | 
|   | 
|             mapService.lockPath(null, pathList, agv.getUuid()); | 
|   | 
|             mainService.generateAction(segment.getAgvId(), segmentList, pathList); | 
|   | 
|         } catch (Exception e) { | 
|             log.error("TrafficService.trigger", e); | 
|             TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); | 
|   | 
|         } | 
|     } | 
|   | 
|     private List<String> checkoutPath(Agv agv, Code startCode, Code endCode, Segment segment) { | 
|         Integer lev = null; | 
|         String agvNo = agv.getUuid(); | 
|         Date now = new Date(); | 
|         Jam jam = jamService.getJam(agv.getId(), startCode.getId(), segment.getId()); | 
|         BlockSeverityType blockSeverity = BlockSeverityType.query(null == jam ? null : jam.getDuration()); | 
|         // judge avoid of jam 如果已经在避让点(因为当前车执行了避让任务),那么则不能再去检索之前的阻塞路径 | 
|         List<Jam> unfinishedOriginJamByCurrAgv = jamService.getUnfinishedOriginJamByAvo(agv.getId(), startCode.getId(), segment.getId()); | 
|         List<String> blackPath = this.getBlackPathList(unfinishedOriginJamByCurrAgv); | 
|   | 
|         // 结果集 | 
|         List<String> pathList = new ArrayList<>(); | 
|   | 
|         // 无障碍解 | 
|         List<String> unlockPathList = mapService.checkoutPath(agvNo, startCode, endCode, false, blackPath, segment); | 
|         // 避让解 | 
|         List<String> lockPathList = mapService.checkoutPath(agvNo, startCode, endCode, true, blackPath, segment); | 
|   | 
|         if (!Cools.isEmpty(lockPathList) && // 存在避让解 | 
|             Math.abs(lockPathList.size() - unlockPathList.size()) <= Arrays.stream(mapDataDispatcher.getCodeMatrix(lev)).mapToInt(row -> row.length).sum() / 10 | 
|         ) { | 
|   | 
|             pathList = lockPathList; | 
|         } else { | 
|   | 
|             // preview path | 
|             List<String> draftPath = new ArrayList<>(unlockPathList); | 
|             if (blockSeverity.equals(BlockSeverityType.SEVERE)) { | 
|                 unlockPathList.remove(endCode.getData()); | 
|                 blackPath.addAll(unlockPathList); | 
|                 List<String> newUnlockPathList = mapService.checkoutPath(agvNo, startCode, endCode, false, blackPath, segment); | 
|                 if (!Cools.isEmpty(newUnlockPathList)) { | 
|                     draftPath = newUnlockPathList; | 
|                 } | 
|             } | 
|             // 可走行路径集合计算 | 
|             List<BlockVehicleDto> blockVehicleList = this.slicePathAndReturnBlockVehicleList(lev, draftPath, agvNo, pathList);    // jamAgvNo may was wave | 
|   | 
|             if (!Cools.isEmpty(pathList)) { | 
|   | 
|                 if (!pathList.get(pathList.size() - 1).equals(endCode.getData())) { | 
|                     assert !Cools.isEmpty(blockVehicleList); | 
|   | 
|                     boolean hasUnavoidableBlocks = blockVehicleList.stream().anyMatch(blockVehicleDto -> !blockVehicleDto.isAvoidable()); | 
|                     if (hasUnavoidableBlocks && pathList.size() <= MapDataConstant.MIN_SLICE_PATH_LENGTH) { | 
|                         log.info("AGV[{}] waiting in place, because the path list is too short...", agvNo); | 
|                         pathList.clear(); | 
|                     } | 
|   | 
|                     boolean hasCycleJam = blockVehicleList.stream().anyMatch( | 
|                             blockVehicleDto -> null != jamService.getCycleJam(agv.getId(), segment.getId(), blockVehicleDto.getVehicle()) | 
|                     ); | 
|                     if (hasCycleJam) { | 
|                         log.info("AGV[{}] waiting in place, because has cycle jam...", agvNo); | 
|                         pathList.clear(); | 
|                     } | 
|                 } | 
|   | 
|             // 无可走行路径 | 
|             } else { | 
|   | 
|                 if (Cools.isEmpty(blockVehicleList)) { | 
|                     log.warn("AGV[{}] can't reach to code: {}, because there is too many vehicle in the lane...", agvNo, endCode.getData()); | 
|                 } else { | 
|   | 
|                     assert !Cools.isEmpty(blockVehicleList); | 
|                     Integer maxJamTimeoutFactor = null; | 
|   | 
|                     // persist jam data | 
|                     jam = this.createOrUpdateJam(agv, startCode, segment, jam, draftPath); | 
|   | 
|                     // ? has unAvoidable block vehicles | 
|                     if (blockVehicleList.stream().anyMatch(blockVehicleDto -> !blockVehicleDto.isAvoidable())) { | 
|   | 
|                         // set factor of jam timeout | 
|                         maxJamTimeoutFactor = 1; | 
|                     } else { | 
|   | 
|                         // ? already do notify to avoid | 
|                         if (!Cools.isEmpty(jam.getAvoAgv()) | 
|                                 && BlockVehicleDto.customContain(blockVehicleList, agvService.getById(jam.getAvoAgv()).getUuid())) { | 
|   | 
|                             maxJamTimeoutFactor = 5; | 
|   | 
|                         } else { | 
|   | 
|                             // select optimal block vehicle | 
|                             String blockAgvNo = this.checkoutBestSolutionOfBlocks(blockVehicleList, segment); | 
|                             if (Cools.isEmpty(blockAgvNo)) { | 
|   | 
|                                 maxJamTimeoutFactor = 2; | 
|   | 
|                             } else { | 
|   | 
|                                 // block vehicle info | 
|                                 Agv blockAgv = agvService.selectByUuid(blockAgvNo); | 
|                                 String blockAgvCode = codeService.getById(agvDetailService.selectByAgvId(blockAgv.getId()).getRecentCode()).getData(); | 
|   | 
|                                 // create new jam if already notify the avoid vehicle | 
|                                 if (!Cools.isEmpty(jam.getAvoAgv(), jam.getAvoSeg()) && !blockAgv.getId().equals(jam.getAvoAgv())) { | 
|                                     jam = this.setupNewJam(jam, agv, startCode, segment, draftPath); | 
|                                 } | 
|   | 
|                                 do { | 
|   | 
|                                     // 阻塞车辆正在原地作业,等待 ===>> 超过等待时间,绕路 | 
|                                     List<Segment> runningSegList = segmentService.getByAgvAndState(blockAgv.getId(), SegmentStateType.RUNNING.toString()); | 
|                                     if (!Cools.isEmpty(runningSegList)) { | 
|                                         maxJamTimeoutFactor = 1; | 
|                                         break; | 
|                                     } | 
|   | 
|                                     // 判断下个任务是否为原地任务,如果是则等待 ===>> 超过等待时间,绕路;如果不是,让阻塞车辆避让 | 
|                                     List<Segment> waitingSegList = segmentService.getJustWaitingSeg(blockAgv.getId()); | 
|                                     if (null != waitingSegList | 
|                                             && waitingSegList.stream().anyMatch( | 
|                                             waitingSeg -> waitingSeg.getEndNode().equals(codeService.selectByData(blockAgvCode).getId()) | 
|                                     )) { | 
|                                         maxJamTimeoutFactor = 1; | 
|                                         break; | 
|                                     } | 
|   | 
|                                     // notify block vehicle to avoid | 
|                                     if (this.notifyVehicleAvoid(blockAgvNo, blockAgvCode, draftPath, agvNo, jam)) { | 
|                                         if (jam.getCycleAvo() == 1) { | 
|                                             jam.setCycleCode(endCode.getId()); | 
|                                         } | 
|                                         jam.setAvoAgv(blockAgv.getId()); | 
|                                         jam.setNotifyTime(new Date()); | 
|                                         if (!jamService.updateById(jam)) { | 
|                                             throw new CoolException(jam.getUuid() + "-jam failed to update!!!"); | 
|                                         } | 
|                                     } else { | 
|   | 
|                                         maxJamTimeoutFactor = 1; | 
|                                     } | 
|   | 
|                                 } while (false); | 
|                             } | 
|   | 
|                         } | 
|   | 
|                     } | 
|   | 
|                     // handle jam timeout | 
|                     if (null != maxJamTimeoutFactor) { | 
|                         if (System.currentTimeMillis() - jam.getStartTime().getTime() > MapDataConstant.MAX_JAM_TIMEOUT * maxJamTimeoutFactor) { | 
|   | 
|                             if (!Cools.isEmpty(lockPathList)) { | 
|   | 
|                                 pathList = lockPathList; | 
|                             } else { | 
|                                 log.error("{}号车辆检索[{}] ===>> [{}]路径失败,原因:{}" | 
|                                         , agvNo, startCode.getData(), endCode.getData(), "路径阻塞超时"); | 
|                             } | 
|                         } else { | 
|                             log.warn("{}号车辆正在等待交通堵塞,阻塞车辆:【{}】" | 
|                                     , agvNo | 
|                                     , blockVehicleList.stream().map(BlockVehicleDto::getVehicle).collect(Collectors.toList()).toString() | 
|                             ); | 
|                         } | 
|                     } | 
|   | 
|                 } | 
|   | 
|             } | 
|         } | 
|   | 
|         if (!Cools.isEmpty(pathList)) { | 
|   | 
|             if (null != jam) { | 
|                 boolean beDeprecate = false; | 
|                 if (blockSeverity.equals(BlockSeverityType.SEVERE) && !Cools.isEmpty(jam.getJamPath())) { | 
|                     List<String> jamPath = GsonUtils.fromJsonToList(jam.getJamPath(), String.class); | 
|                     if (!this.comparePathLists(jamPath, pathList)) {    // jamPath >= pathList | 
|                         beDeprecate = true; | 
|                     } | 
|                 } | 
|                 jam.setEndTime(now); | 
|                 jam.setUpdateTime(now); | 
|                 jam.setState(beDeprecate ? JamStateType.DEPRECATED.toString() : JamStateType.FINISH.toString()); | 
|                 if (jamService.updateById(jam)) { | 
|                     if (beDeprecate) { | 
|                         // search previous jam that jamSeg from this segment | 
|                         List<Jam> previousJams = jamService.list(new LambdaQueryWrapper<Jam>() | 
|                                 .eq(Jam::getJamSeg, segment.getId()) | 
|                                 .eq(Jam::getState, JamStateType.FINISH.toString()) | 
|                         ); | 
|                         for (Jam previousJam : previousJams) { | 
|                             previousJam.setState(JamStateType.DEPRECATED.toString()); | 
|                             previousJam.setUpdateTime(now); | 
|                             if (!jamService.updateById(previousJam)) { | 
|                                 log.error("Jam[{}] failed to update!!!", previousJam.getUuid()); | 
|                             } | 
|                         } | 
|                     } | 
|                 } else { | 
|                     log.error("Jam[{}] failed to update!!!", jam.getUuid()); | 
|                 } | 
|             } | 
|             // deal expired jam | 
|             for (Jam expiredJam : jamService.list(new LambdaQueryWrapper<Jam>() | 
|                     .eq(Jam::getJamAgv, agv.getId()) | 
|                     .eq(Jam::getState, JamStateType.RUNNING.toString()))) { | 
|                 expiredJam.setEndTime(now); | 
|                 expiredJam.setUpdateTime(now); | 
|                 expiredJam.setState(JamStateType.DEPRECATED.toString()); | 
|                 if (!jamService.updateById(expiredJam)) { | 
|                     log.error("Jam[{}] failed to update!!!", expiredJam.getUuid()); | 
|                 } | 
|             } | 
|   | 
|         } | 
|   | 
|         return pathList; | 
|     } | 
|   | 
|     private List<BlockVehicleDto> slicePathAndReturnBlockVehicleList(Integer lev, List<String> fullPathList, String agvNo, List<String> pathList) { | 
|         List<BlockVehicleDto> blockVehicleList = new ArrayList<>(); | 
|   | 
| //        DynamicNode[][] dynamicMatrix = mapDataDispatcher.getDynamicMatrix(lev); | 
|         String[][] waveMatrix = mapDataDispatcher.getWaveMatrix(lev); | 
|         for (String code : fullPathList) { | 
|             int[] node = mapDataDispatcher.getCodeMatrixIdx(lev, code); | 
|   | 
|             String waveNode = waveMatrix[node[0]][node[1]]; | 
|             assert !waveNode.equals(WaveNodeType.DISABLE.val); | 
|             if (!waveNode.equals(WaveNodeType.ENABLE.val)) { | 
|                 List<String> waveNodeList = MapDataUtils.parseWaveNode(waveNode); | 
|                 List<String> otherWaveList = MapDataUtils.hasOtherWave(waveNodeList, agvNo); | 
|                 if (!Cools.isEmpty(otherWaveList)) { | 
|                     for (String otherWave : otherWaveList) { | 
|                         if (1 < mapDataDispatcher.queryCodeListFromDynamicNode(lev, otherWave).size()) { | 
|                             blockVehicleList.add(new BlockVehicleDto(otherWave, false)); | 
|                         } else { | 
|                             blockVehicleList.add(new BlockVehicleDto(otherWave, true)); | 
|                         } | 
|                     } | 
|                     break; | 
|                 } | 
|             } | 
|   | 
| //            DynamicNode dynamicNode = dynamicMatrix[node[0]][node[1]]; | 
| //            String vehicle = dynamicNode.getVehicle(); | 
| //            assert !vehicle.equals(DynamicNodeType.BLOCK.val); | 
| //            if (!vehicle.equals(DynamicNodeType.ACCESS.val) && !vehicle.equals(agvNo)) { | 
| //                blockVehicleList.add(vehicle); | 
| //                break; | 
| //            } | 
|   | 
|             pathList.add(code); | 
|         } | 
|   | 
|         if (pathList.size() <= 1) { | 
|             pathList.clear(); | 
|         } | 
|   | 
|         return blockVehicleList.stream().distinct().collect(Collectors.toList()); | 
|     } | 
|   | 
|     /** | 
|      * avoidPathList include wave node and dynamic node | 
|      */ | 
|     private boolean notifyVehicleAvoid(String agvNo, String agvPosCode, List<String> avoidPathList, String sponsor, Jam jam) { | 
|         Agv agv = agvService.selectByUuid(agvNo); | 
|         if (!Cools.isEmpty(segmentService.getByAgvAndState(agv.getId(), SegmentStateType.RUNNING.toString()))) { | 
|             log.warn("{}号车辆避让失败,存在进行中任务!!!", agvNo); | 
|             return false; | 
|         } | 
|   | 
|         int[] startMapIdx = mapDataDispatcher.getCodeMatrixIdx(null, agvPosCode); | 
|         RetreatNavigateNode startNode = new RetreatNavigateNode(startMapIdx[0], startMapIdx[1], agvPosCode); | 
|   | 
|         assert avoidPathList.size() >= 2; | 
|         RetreatNavigateNode finalNode = retreatNavigateService.execute(agvNo, startNode, avoidPathList, sponsor, jam); | 
|         if (null == finalNode) { | 
|             log.warn("{}号车辆避让失败,检索避让点失败!!!", agvNo); | 
|             return false; | 
|         } | 
|   | 
|         String endCodeData = finalNode.getCodeData(); | 
|         Code endCode = codeService.selectByData(endCodeData); | 
|   | 
|         List<Segment> waitingSegList = segmentService.getByAgvAndState(agv.getId(), SegmentStateType.WAITING.toString()); | 
|         if (!Cools.isEmpty(waitingSegList)) { | 
|   | 
|             if (waitingSegList.size() > 1) { | 
|                 log.error("避让通知失败,{}号车辆存在多个等待中的Segment!!!", agvNo); | 
|                 return false; | 
|             } | 
|             // revert | 
|             Date now = new Date(); | 
|             for (Segment seg : waitingSegList) { | 
|                 seg.setState(SegmentStateType.INIT.toString()); | 
|                 seg.setUpdateTime(now); | 
|                 if (!segmentService.updateById(seg)) { | 
|                     log.error("Segment [{}] 更新失败 !!!", seg.getTravelId() + " - " + seg.getSerial()); | 
|                 } | 
|             } | 
|             Segment segment = waitingSegList.get(0); | 
|   | 
|             Segment insertSeg = new Segment(); | 
|             insertSeg.setUuid(String.valueOf(snowflakeIdWorker.nextId()).substring(3)); | 
|             insertSeg.setTravelId(segment.getTravelId()); | 
|             insertSeg.setAgvId(agv.getId()); | 
|             insertSeg.setTaskId(segment.getTaskId()); | 
|             insertSeg.setSerial(segment.getSerial() - 1); | 
|             insertSeg.setEndNode(endCode.getId()); | 
|             insertSeg.setPosType(TaskPosDto.PosType.MOVE.toString()); | 
|             insertSeg.setState(SegmentStateType.WAITING.toString()); | 
|             if (!segmentService.save(insertSeg)) { | 
|                 log.error("Segment [{}] 保存失败 !!!", segment.getTravelId() + " - " + segment.getSerial()); | 
|                 return false; | 
|             } else { | 
|                 jam.setAvoSeg(insertSeg.getId()); | 
|                 jam.setAvoCode(endCode.getId()); | 
|             } | 
|   | 
|         } else { | 
|   | 
|             return mainLockWrapService.buildMinorTask(agv, TaskTypeType.MOVE, endCodeData, jam); | 
|         } | 
|   | 
|         return true; | 
|     } | 
|   | 
|     private Jam createOrUpdateJam(Agv agv, Code startCode, Segment segment, Jam jam, List<String> jamPath) { | 
|         if (jam == null) { | 
|             jam = new Jam(); | 
|             jam.setUuid(String.valueOf(snowflakeIdWorker.nextId()).substring(3)); | 
|             jam.setJamAgv(agv.getId()); | 
|             jam.setJamCode(startCode.getId()); | 
|             jam.setJamSeg(segment.getId()); | 
|             jam.setJamPath(GsonUtils.toJson(jamPath)); | 
|             jam.setStartTime(new Date()); | 
|             jam.setState(JamStateType.RUNNING.toString()); | 
|             if (!jamService.save(jam)) { | 
|                 log.error("AGV[{}] failed to save jam", agv.getUuid()); | 
|                 throw new CoolException("failed to save jam"); | 
|             } | 
|         } else { | 
|             jam.setDuration(System.currentTimeMillis() - jam.getStartTime().getTime()); | 
|             if (!jamService.updateById(jam)) { | 
|                 log.error("AGV[{}] failed to update jam", agv.getUuid()); | 
|             } | 
|         } | 
|         return jam; | 
|     } | 
|   | 
|     private Jam setupNewJam(Jam originJam, Agv agv, Code startCode, Segment segment, List<String> draftPath) { | 
|         originJam.setUpdateTime(new Date()); | 
|         originJam.setState(JamStateType.FINISH.toString()); | 
|         if (!jamService.updateById(originJam)) { | 
|             log.error("Jam[{}] failed to update", originJam.getUuid()); | 
|             return originJam; | 
|         } else { | 
|             return this.createOrUpdateJam( | 
|                     agv | 
|                     , startCode | 
|                     , segment | 
|                     , null | 
|                     , draftPath | 
|             ); | 
|         } | 
|     } | 
|   | 
|     private List<String> getBlackPathList(List<Jam> unfinishedOriginJamByCurrAgv) { | 
|         List<String> blackPathList = new ArrayList<>(); | 
|         Integer lev = MapDataDispatcher.MAP_DEFAULT_LEV; | 
|         if (!Cools.isEmpty(unfinishedOriginJamByCurrAgv)) { | 
|             for (Jam jam : unfinishedOriginJamByCurrAgv) { | 
|                 if (!Cools.isEmpty(jam.getJamPath())) { | 
|   | 
|                     List<String> list = GsonUtils.fromJsonToList(jam.getJamPath(), String.class); | 
|   | 
|                     Agv jamAgv = agvService.getById(jam.getJamAgv()); | 
|                     List<String> jamDynamicNodes = mapDataDispatcher.queryCodeListFromDynamicNode(lev, jamAgv.getUuid()); | 
|                     // jamDynamicNodes has sorted | 
|                     String firstCodeNode = jamDynamicNodes.stream().findFirst().orElse(null); | 
|   | 
|                     if (!Cools.isEmpty(firstCodeNode)) { | 
|                         int idx = list.indexOf(firstCodeNode); | 
|                         if (idx != -1) { | 
|                             list = new ArrayList<>(list.subList(idx, list.size())); | 
|   | 
|                             // the wave of first node | 
|                             Double avoidDistance = MapDataUtils.getVehicleWaveSafeDistance( | 
|                                     agvModelService.getById(jamAgv.getAgvModel()).getDiameter(), | 
|                                     MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR | 
|                             ); | 
|                             List<String> waveCodeList = mapService.getWaveScopeByCode(lev, firstCodeNode, avoidDistance) | 
|                                     .stream().map(NavigateNode::getCodeData).distinct().collect(Collectors.toList()); | 
|                             list.addAll(waveCodeList); | 
|                         } | 
|                     } | 
|   | 
|                     blackPathList.addAll(list); | 
|                 } | 
|             } | 
|         } | 
|         return blackPathList.stream().distinct().collect(Collectors.toList()); | 
|     } | 
|   | 
|     private String checkoutBestSolutionOfBlocks(List<BlockVehicleDto> blockVehicleList, Segment segment) { | 
|         assert !Cools.isEmpty(blockVehicleList); | 
|         for (BlockVehicleDto blockVehicleDto : blockVehicleList) { | 
|             if (!blockVehicleDto.isAvoidable()) { | 
|                 continue; | 
|             } | 
|             // 当前vehicle正在进行避让作业 | 
|             if (!Cools.isEmpty(jamService.getUnfinishedAvoSegByAvo(blockVehicleDto.getVehicle(), null))) { | 
|                 continue; | 
|             } | 
|             return blockVehicleDto.getVehicle(); | 
|         } | 
|         return null; | 
|     } | 
|   | 
|     public boolean comparePathLists(List<String> list1, List<String> list2) { | 
|         if (list1.equals(list2)) { | 
|             return true; | 
|         } | 
|         if (list1.containsAll(list2)) { | 
|             return true; | 
|         } | 
|         return false; | 
|     } | 
|   | 
|     private boolean isJamBeDeprecatedByAvo(Long avoSeg) { | 
|         return 0 < jamService.count(new LambdaQueryWrapper<Jam>() | 
| //                .eq(Jam::getAvoAgv, avoAgv) | 
|                 .eq(Jam::getAvoSeg, avoSeg) | 
|                 .eq(Jam::getState, JamStateType.DEPRECATED.toString()) | 
|         ); | 
|     } | 
|   | 
|     private boolean skipCurrSegment(Segment currSegment) { | 
|         currSegment.setState(SegmentStateType.FINISH.toString()); | 
|         currSegment.setUpdateTime(new Date()); | 
|         if (!segmentService.updateById(currSegment)) { | 
|             log.error("Segment [{}] failed to update !!!", currSegment.getTravelId() + " - " + currSegment.getSerial()); | 
|             return false; | 
|         } | 
|         segmentService.processNext(Utils.singletonList(currSegment)); | 
|         return true; | 
|     } | 
|   | 
| } |