# LotAutoMonitorReqManagerImpl.java

    package com.mycim.server.automonitor.manager.impl;

    import com.fa.sesa.threadlocal.LocalContext;
    import com.mycim.framework.oid.IDGenerators;
    import com.mycim.framework.oid.type.IDNames;
    import com.mycim.framework.oid.type.SequenceNames;
    import com.mycim.framework.utils.lang.StringUtils;
    import com.mycim.framework.utils.lang.collections.CollectionUtils;
    import com.mycim.framework.utils.lang.collections.MapUtils;
    import com.mycim.framework.utils.lang.math.NumberUtils;
    import com.mycim.server.automonitor.dao.LotAutoMonitorReqDao;
    import com.mycim.server.automonitor.manager.AutoMonitorItemInqManager;
    import com.mycim.server.automonitor.manager.LotAutoMonitorInqManager;
    import com.mycim.server.automonitor.manager.LotAutoMonitorReqManager;
    import com.mycim.server.base.manager.TransactionLogManager;
    import com.mycim.server.carrier.manager.CarrierManager;
    import com.mycim.server.carrier.manager.PcdManager;
    import com.mycim.server.prp.manager.WorkflowManager;
    import com.mycim.server.wip.manager.*;
    import com.mycim.utils.CheckRegexUtils;
    import com.mycim.valueobject.ObjectList;
    import com.mycim.valueobject.automonitor.dto.AutoMonitorJobDTO;
    import com.mycim.valueobject.automonitor.entity.*;
    import com.mycim.valueobject.automonitor.util.AutoMonitorOperationConstants;
    import com.mycim.valueobject.automonitor.util.AutoMonitorUtils;
    import com.mycim.valueobject.automonitor.util.MonitorJobStatusConts;
    import com.mycim.valueobject.bas.TransactionLog;
    import com.mycim.valueobject.consts.LotInfoConstants;
    import com.mycim.valueobject.consts.TransactionNames;
    import com.mycim.valueobject.ems.Carrier;
    import com.mycim.valueobject.ems.Equipment;
    import com.mycim.valueobject.wip.*;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.rmi.RemoteException;
    import java.util.*;

    /**
     * @author finatice.yang
     * @date 2021/8/31
     **/
    @Service
    @Transactional
    public class LotAutoMonitorReqManagerImpl implements LotAutoMonitorReqManager {

        @Autowired
        LotAutoMonitorReqDao lotAutoMonitorDao;

        @Autowired
        LotAutoMonitorInqManager lotAutoMonitorInqManager;

        @Autowired
        AutoMonitorItemInqManager autoMonitorItemInqManager;

        @Autowired
        TransactionLogManager transactionLogManager;

        @Autowired
        LotManager lotManager;

        @Autowired
        LotQueryManager lotQueryManager;

        @Autowired
        LotInqManager lotInqManager;

        @Autowired
        LotReqManager lotReqManager;

        @Autowired
        LotTransHistoryReqManager lotTransHistoryReqManager;

        @Autowired
        LotStepHistoryReqManager lotStepHistoryReqManager;

        @Autowired
        UnitManager unitManager;

        @Autowired
        UnitQueryManager unitQueryManager;

        @Autowired
        PcdManager pcdManager;

        @Autowired
        CarrierManager carrierManager;

        @Autowired
        WorkflowManager workflowManager;

        @Autowired
        WipWorkflowQueryManager wipWorkflowQueryManager;

        @Override
        public void insertLotMonitorJobStore(TransactionLog transactionLog, LotMonitorJobStore store) {
            lotAutoMonitorDao.insertLotMonitorJobStore(store);
            lotAutoMonitorDao.insertLotMonitorJobStoreHistory(transactionLog, store);
        }

        @Override
        public void updateMonitorJobStatus(TransactionLog transactionLog, Long lotRrn, String jobStatus) {
            LotMonitorJobStore store = new LotMonitorJobStore();
            store.setLotRrn(lotRrn);
            store.setJobStatus(jobStatus);
            lotAutoMonitorDao.updateLotMonitorJobStore(store);

            store = lotAutoMonitorInqManager.getLotMonitorJobStore(lotRrn);
            lotAutoMonitorDao.insertLotMonitorJobStoreHistory(transactionLog, store);
        }

        @Override
        public void insertLotMonitorStepEdcInfo(List<LotMonitorJobStepEdcInfo> stepEdcInfoList) {
            lotAutoMonitorDao.insertLotMonitorStepEdcInfo(stepEdcInfoList);
        }

        @Override
        public void insertMonitorCarrierMapping(List<MonitorCarrierMapping> monitorCarrierMappings) {
            lotAutoMonitorDao.insertMonitorCarrierMapping(monitorCarrierMappings);
        }

        @Override
        public void updateMonitorCarrierMapping(List<MonitorCarrierMapping> monitorCarrierMappings,
                                                Long monitorCarrierRrn) {
            lotAutoMonitorDao.deleteMonitorCarrierMappingByCarrier(monitorCarrierRrn);
            lotAutoMonitorDao.insertMonitorCarrierMapping(monitorCarrierMappings);
        }

        @Override
        public void deleteMonitorCarrierMappingByLot(Long lotRrn) {
            lotAutoMonitorDao.deleteMonitorCarrierMappingByLot(lotRrn);
        }

        @Override
        public void amfinishLot(Lot lot) {
            TransactionLog transactionLog = transactionLogManager
                    .startTransactionLog(LocalContext.getUserId(), TransactionNames.AUTO_MONITOR_AMFINISH);

            Lot updateLot = new Lot(lot.getLotRrn());
            updateLot.setEqptRrn(NumberUtils.LONG_ZERO);
            updateLot.setBeforeStatus(lot.getLotStatus());
            updateLot.setLotStatus(LotStatus.AUTO_MONITOR_JOB_FINISH);

            // 将mother lot的merge info填入lot 中
            LotMonitorJobStore jobStore = lotAutoMonitorInqManager.getLotMonitorJobStore(lot.getLotRrn());
            if (Objects.nonNull(jobStore)) {
                updateLot.setFlowSeq(wipWorkflowQueryManager.getFlowSeqByWflStep(jobStore.getMergeWflStep()));
            }
            updateLot.setStageId(AutoMonitorOperationConstants.PARENT_MERGE_STAGE);
            lotReqManager.updateLot(updateLot);

            updateLot = lotInqManager.getLot(lot.getLotRrn());
            lotTransHistoryReqManager.createLotTransHistory(transactionLog, updateLot, StringUtils.EMPTY);

            updateMonitorJobStatus(transactionLog, lot.getLotRrn(), MonitorJobStatusConts.FINISH_KEY);

            transactionLogManager.markTransactionLog(transactionLog);
        }

        @Override
        public boolean synAutoMonitorJobInfo(LotAutoMonitorInfo monitorInfo, String transId) {
            if (Objects.isNull(monitorInfo)) {
                return false;
            }
            if (AutoMonitorUtils.checkJobStatusIsFixed(monitorInfo.getJobStatus())) {
                return false;
            }

            TransactionLog transactionLog = transactionLogManager
                    .startTransactionLog(LocalContext.getUserId(), transId);
            Long lotRrn = monitorInfo.getLotRrn();

            if (StringUtils.equals(AutoMonitorOperationConstants.STEP_TYPE_MAIN, monitorInfo.getEqptType())) {
                updateMonitorJobStatus(transactionLog, lotRrn, MonitorJobStatusConts.WAIT_PROCESS_KEY);
            } else if (StringUtils.equals(MonitorJobStatusConts.WAIT_PROCESS_KEY, monitorInfo.getJobStatus())) {
                updateMonitorJobStatus(transactionLog, lotRrn, MonitorJobStatusConts.PROCESSED_KEY);
            }

            return true;
        }

        @Override
        public boolean synAutoMonitorJobInfo(TransactionLog transactionLog, LotAutoMonitorInfo monitorInfo) {
            if (Objects.isNull(monitorInfo)) {
                return false;
            }
            if (AutoMonitorUtils.checkJobStatusIsFixed(monitorInfo.getJobStatus())) {
                return false;
            }

            Long lotRrn = monitorInfo.getLotRrn();
            if (StringUtils.equals(AutoMonitorOperationConstants.STEP_TYPE_MAIN, monitorInfo.getEqptType())) {
                updateMonitorJobStatus(transactionLog, lotRrn, MonitorJobStatusConts.WAIT_PROCESS_KEY);
            } else if (StringUtils.equals(MonitorJobStatusConts.WAIT_PROCESS_KEY, monitorInfo.getJobStatus())) {
                updateMonitorJobStatus(transactionLog, lotRrn, MonitorJobStatusConts.PROCESSED_KEY);
            }

            return true;
        }

        @Override
        public void splitLotByAutoMonitor(TransactionLog transactionLog, AutoMonitorJobDTO monitorJobDTO) {
            Lot childLot = monitorJobDTO.getChildLot();
            Lot parentLot = monitorJobDTO.getParentLot();

            childLot = createChildLotByAutoMonitor(transactionLog, monitorJobDTO);

            Integer parentQty = parentLot.getInt_qty1().intValue() - monitorJobDTO.getUnitList().size();
            parentLot.setQty1(parentQty.doubleValue());
            lotManager.updateLotQty(parentLot);

            lotTransHistoryReqManager.createLotTransHistory(transactionLog, parentLot, childLot.getLotId());
        }

        @Override
        public void mergeLotByAutoMonitor(TransactionLog transactionLog, Lot parentLot, List<Lot> childLotList) {
            List<Map> newUnits = new ArrayList<>();

            List<Map<String, Object>> childLots = new ArrayList<>();
            for (Lot childLot : childLotList) {
                List<Unit> unitList = unitQueryManager.getUnitList(childLot.getLotRrn());
                List<Map<String, Object>> units = buildUnits(unitList, childLot.getLotId(), false);
                childLot.setUnitsInfo(units);
            }

            TransReason transReason = new TransReason();
            transReason.setReasonCode(StringUtils.EMPTY);
            transReason.setResponsibility(LocalContext.getUserId());
            transReason.setReason(transactionLog.getComments());

            mergeLot(transactionLog, parentLot, childLotList, transReason);
        }

        @Override
        public void exchangeAutoMonitorLotCarrier(TransactionLog transactionLog, LotAutoMonitorInfo lotAutoMonitorInfo,
                                                  Long targetCarrierRrn) {
            String userId = LocalContext.getUserId();
            Long facilityRrn = LocalContext.getFacilityRrn();

            String transId = transactionLog.getTransId();

            // update target Carrier info
            List<Lot> targetLotList = lotInqManager.getLotListByCarrierRrn(targetCarrierRrn);
            long targetQty = NumberUtils.LONG_ZERO.longValue();
            for (Lot targetLot : targetLotList) {
                targetQty += targetLot.getInt_qty1().longValue();
            }

            Carrier targetCarrier = carrierManager.getCarrier(targetCarrierRrn);
            pcdManager.changeStatusFromFreeOrAssemblyToInUse(facilityRrn, userId, targetCarrierRrn, StringUtils.EMPTY);

            // update lot carrierRrn
            Lot updateLot = new Lot(lotAutoMonitorInfo.getLotRrn());
            updateLot.setCarrierRrn(targetCarrierRrn);
            updateLot.setCarrierSharedFlag(lotAutoMonitorInfo.getLotRrn() + "");
            lotReqManager.updateLot(updateLot);

            // update unit to new carrierRrn
            List<MonitorCarrierMapping> carrierMappingList = lotAutoMonitorInqManager
                    .getMonitorCarrierMappings(lotAutoMonitorInfo.getMonitorCarrierRrn());
            List<Unit> unitList = new ArrayList<>();
            for (MonitorCarrierMapping carrierMapping : carrierMappingList) {
                if (carrierMapping.getLotRrn().longValue() == lotAutoMonitorInfo.getLotRrn()) {
                    Unit unit = new Unit();
                    unit.setUnitRrn(carrierMapping.getUnitRrn());
                    if (StringUtils.equals(TransactionNames.AUTO_MONITOR_MERGE, transId)) {
                        unit.setPositionInCarrier(carrierMapping.getSourcePosition());
                    } else {
                        unit.setPositionInCarrier(carrierMapping.getPosition());
                    }
                    unit.setCarrierRrn(targetCarrierRrn);
                    unitList.add(unit);
                }
            }
            if (CollectionUtils.isNotEmpty(unitList)) {
                unitManager.updateUnitListWithChangeCarrier(unitList);
            }

            // merge check carrier to FREE
            if (StringUtils.equals(TransactionNames.AUTO_MONITOR_MERGE, transId)) {
                Long oldCarrierRrn = lotAutoMonitorInfo.getCarrierRrn();
                List<Lot> monitorCarrierLotList = lotInqManager.getLotListByCarrierRrn(oldCarrierRrn);
                if (CollectionUtils.isEmpty(monitorCarrierLotList)) {
                    pcdManager.changeStatusFromInUseToFreeOrAssembly(facilityRrn, userId, oldCarrierRrn, StringUtils.EMPTY);
                }
            }

            Lot lot = lotInqManager.getLot(lotAutoMonitorInfo.getLotRrn());
            if (lotAutoMonitorInfo.isBySort()){
                lot.setSorterFlag(true);
                lot.setLocation(lotAutoMonitorInfo.getSorterEqptId());
                lot.setEqptRrn(lotAutoMonitorInfo.getSorterEqptRrn());
            }
            lotTransHistoryReqManager.createLotTransHistory(transactionLog,lot,StringUtils.EMPTY);
        }

        @Override
        public void insertAutoMonitorUnit(List<AutoMonitorUnitInfo> unitInfoList) {
            lotAutoMonitorDao.insertAutoMonitorUnit(unitInfoList);
        }

        private void mergeLot(TransactionLog transactionLog, Lot parentLot, List<Lot> childLotList,
                              TransReason transReason) {
            String userId = LocalContext.getUserId();
            Long facilityRrn = LocalContext.getFacilityRrn();

            List<Unit> targetParentUnits = unitQueryManager.getUnitList(parentLot.getLotRrn());

            double mergeQty1 = 0;
            double mergeQty2 = 0;

            for (Lot childLot : childLotList) {
                Double qty1 = childLot.getInt_qty1().doubleValue();
                Double qty2 = childLot.getInt_qty2().doubleValue();

                List<Unit> targetChildUnitList = unitQueryManager.getUnitList(childLot.getLotRrn());

                Carrier carrier = carrierManager.setCarrierForVirtual(userId, facilityRrn, childLot.getLotId(), qty1);
                Carrier virtualCarrier = carrierManager.getCarrier(carrier);
                Long virtualCstRrn = Objects.isNull(virtualCarrier) ? carrierManager.insertCarrier(carrier) : virtualCarrier
                        .getInstanceRrn();
                carrier.setInstanceRrn(virtualCstRrn);
                carrier = carrierManager.getCarrier(carrier);

                childLot.setTransPerformedby(transactionLog.getTransPerformedBy());
                childLot.setTransId(transactionLog.getTransId() + "_" + TransactionNames.VIRTUAL_KEY);
                childLot.setLotComments(
                        "After merge Lot,the Casstte is released,The initial Casstte Id is：" + parentLot.getCarrierId());
                carrierManager.createCarrierMapping(transactionLog.getTransRrn(), carrier, childLot.getUnitsInfo());

                Lot updateLot = new Lot(childLot.getLotRrn());
                updateLot.setBeforeStatus(childLot.getLotStatus());
                updateLot.setLotStatus(LotStatus.TERMINATED);
                updateLot.setCarrierRrn(carrier.getInstanceRrn());
                updateLot.setJobRrn(NumberUtils.LONG_ZERO);
                updateLot.setQty1(NumberUtils.DOUBLE_ZERO);
                lotReqManager.updateLot(updateLot);

                // setp3-2: create lot_trans_h
                lotTransHistoryReqManager.createLotTransHistory(transactionLog, childLot, transReason.getReason());

                mergeQty1 += qty1.doubleValue();
                mergeQty2 += qty2.doubleValue();
                targetParentUnits.addAll(targetChildUnitList);
            }

            double parentQty1 = parentLot.getInt_qty1().doubleValue() + mergeQty1;
            double parentQty2 = parentLot.getInt_qty2().doubleValue() + mergeQty2;
            parentLot.setQty1(parentQty1);
            parentLot.setQty2(parentQty2);
            lotTransHistoryReqManager.createLotTransHistory(transactionLog, parentLot, transReason.getReason());

            // step5:update th lot qty
            Lot updateLot = new Lot(parentLot.getLotRrn());
            updateLot.setQty1(parentQty1);
            updateLot.setQty2(parentQty2);
            lotReqManager.updateLot(updateLot);

            // create unit step range history
            unitManager.transferUnitInALot(transactionLog, parentLot, targetParentUnits);
            unitManager.createUnitStepRangeHistory(transactionLog, parentLot, targetParentUnits);

            // step7:update lot step hitory
            LotStepHistory lotStepHistory = new LotStepHistory(parentLot.getLotRrn(), parentLot.getStepSequence());
            lotStepHistory.setMergeQty1(new Double(parentQty1).intValue());
            lotStepHistory.setMergeQty2(new Double(parentQty2).intValue());
            lotStepHistoryReqManager.updateLotStepHistory(lotStepHistory);

            lotManager.insertTransReason(transactionLog.getTransRrn(), parentLot.getLotRrn(), transReason,
                                         NumberUtils.INTEGER_ONE);
        }

        private List<Map<String, Object>> buildUnits(List<Unit> unitList, String lotId, Boolean rePosition) {
            List<Map<String, Object>> units = new ArrayList<>();
            for (Unit unit : unitList) {
                Map<String, Object> map = MapUtils.newHashMap();
                if (rePosition) {
                    map.put("position", StringUtils.substringAfter(unit.getUnitId(), "#"));
                } else {
                    map.put("position", unit.getPositionInCarrier() + "");
                }

                map.put("unitId", unit.getUnitId());
                map.put("unitRrn", unit.getUnitRrn() + "");
                map.put("dummyflag", unit.getDummyFlag());
                map.put("available", CheckRegexUtils.FLAG_ON);
                map.put("lotid", lotId);

                units.add(map);
            }
            return units;
        }

        private Lot createChildLotByAutoMonitor(TransactionLog transactionLog, AutoMonitorJobDTO monitorJobDTO) {
            Lot childLot = monitorJobDTO.getChildLot();
            Lot parentLot = monitorJobDTO.getParentLot();

            AutoMonitorItem monitorItem = monitorJobDTO.getMonitorItem();
            Long workflowRrn = monitorItem.getWorkflowRrn();
            Integer workflowVersion = monitorItem.getWorkflowVersion();

            // step-1 : get split runcard workflow
            String stepNumber = workflowManager.getFirstWflStepInWorkflow(workflowRrn, workflowVersion);
            childLot = lotManager.buildLotProcessStepInfo(childLot, workflowRrn, workflowVersion, stepNumber);
            childLot.setProcessRrn(parentLot.getProcessRrn());
            childLot.setProcessId(parentLot.getProcessId());
            childLot.setProcessVersion(parentLot.getProcessVersion());
            childLot.setRouteRrn(null);
            childLot.setRouteId(null);
            childLot.setBeforeStatus(StringUtils.EMPTY);
            childLot.setStartedFlag(CheckRegexUtils.FLAG_ON);
            childLot.setDummyFlag(CheckRegexUtils.FLAG_ON);
            childLot.setLotRrn(createNewRrn());
            childLot.setBasedLotRrn(parentLot.getLotRrn());
            childLot.setCreatedTimestamp(transactionLog.getTransStartTimestamp());
            childLot.setCarrierSharedFlag(childLot.getLotId());

            AutoMonitorItemStep stepInfo = autoMonitorItemInqManager
                    .getAutoMonitorItemStep(workflowRrn, workflowVersion, childLot.getOperationRrn());
            if (Objects.nonNull(stepInfo)) {
                childLot.setStepType(stepInfo.getEqptType());
                childLot.setOperationDesc(stepInfo.getOperationDesc());
                childLot.setFlowSeq(stepInfo.getFlowSeq());
                childLot.setStageId(stepInfo.getStageId());
            }

            childLot.setIsDummyLot(Boolean.TRUE);
            childLot.setSysType(LotInfoConstants.SysType.AUTOMONITOR.toString());

            lotReqManager.insertLot(childLot);

            // step 2: create carrier mapping
            // 清洗时间超出,晶舟不能使用
            Carrier carrier = carrierManager.getCarrier(childLot.getCarrierRrn());
            childLot.setCarrierMapRrn(carrier.getCarrierMapRrn());

            List<Unit> childUnitList = monitorJobDTO.getUnitList();

            // step 3: insert into lot transaction table
            lotTransHistoryReqManager.createLotTransHistory(transactionLog, childLot, StringUtils.EMPTY);

            // step 4: start lot step history
            startChildLot(transactionLog, childLot, childUnitList);

            return childLot;
        }

        private void startChildLot(TransactionLog transactionLog, Lot childLot, List<Unit> childUnitList) {
            // step1: update lot table
            lotManager.start(childLot.getLotRrn());
            // step2: create lot step history
            lotStepHistoryReqManager.createLotStepHistory(childLot);

            unitManager.transferUnitInALot(transactionLog, childLot, childUnitList);
            unitManager.createUnitStepRangeHistory(transactionLog, childLot, childUnitList);
        }

        private long createNewRrn() {
            return Long.parseLong(IDGenerators.get(IDNames.SEQUENCE).generateId(SequenceNames.MODULE_SEQ_OBJECT_RRN));
        }

    }