CarrierPortalAction.java

package com.mycim.webapp.actions.carrier.carrierportal;

import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.exception.SystemIllegalArgumentException;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.utils.lang.ObjectUtils;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.collections.CollectionUtils;
import com.mycim.framework.utils.lang.time.DateUtils;
import com.mycim.framework.utils.msg.JsonUtils;
import com.mycim.utils.CheckRegexUtils;
import com.mycim.utils.WipUtils;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.SystemConstant;
import com.mycim.valueobject.consts.*;
import com.mycim.valueobject.ems.Carrier;
import com.mycim.valueobject.ems.PcdClean;
import com.mycim.valueobject.sys.ReferenceFile;
import com.mycim.valueobject.sys.ReferenceFileDetail;
import com.mycim.valueobject.wip.Lot;
import com.mycim.webapp.TemplateLocation;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.CarrierSetupAction;
import org.apache.commons.collections.MapUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.springframework.util.StopWatch;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

/**
 * @author yanbing.chen
 * @date 2019/8/27
 * @since 1.8
 **/
public class CarrierPortalAction extends CarrierSetupAction {

    public final static int PCD_ID_LENGTH = 7;

    public final static int CLEAN_CYCLE_NUM_SIX = 6;

    public final static int CARRIER_ID_MAXLENGTH = 64;

    public final static int DESCRIPTION_MAXLENGTH = 128;

    public final static String CARRIER_ID = "carrierId";

    public final static String CARRIER_STATUS = "carrierStatus";

    public final static String CARRIER_ALLOWABLE_EVENT = "carrierAllowableEvent";

    public final static String CARRIER_CATEGORY = "carrierCategory";

    public final static String CARRIER_CLEAN_CYLE = "carrierCleanCycle";


    public final static String CARRIERDESC = "carrierDesc";

    public volatile Set<CountDownProp> countDownPropList = Collections.synchronizedSortedSet(new TreeSet<>());


    @Override
    public ActionForward init(ActionMapping mapping, ActionForm theform, HttpServletRequest request,
                              HttpServletResponse response) {
        if (StringUtils.equalsIgnoreCase(getInstanceId(LocalContext.getFacilityRrn()), "LAB_R")) {
            return mapping.findForward("carrierPortal4LabR");
        }
        return mapping.findForward("carrierPortal");
    }

    public void changePcdStatus(Map map) {
        String user = LocalContext.getUserId();
        long facilityRrn = LocalContext.getFacilityRrn();
        String pcdId = map.get("pcdId").toString();
        String pcdType = map.get("pcdType").toString();
        String eventId = map.get("eventId").toString();
        String comments = map.get("commentsVal").toString();
        String targetStatus = map.get("targetStatus").toString();
        String currentStatus = map.get("currentStatus").toString();

        Assert.isTrue(
                StringUtils.isNotBlank(pcdId) && StringUtils.isNotBlank(pcdType) && StringUtils.isNotBlank(eventId) &&
                        StringUtils.isNotBlank(comments),
                Errors.create().key(MessageIdList.CARRIER_COMMENTS_EMPTY).content("备注不能为空!").build());
        statusService.changePcdStatusByLogEvent(facilityRrn, user, pcdId, pcdType, eventId, comments, targetStatus,
                                                currentStatus, StringUtils.EMPTY);

    }


    /**
     * 根据pcdId获取log event信息
     */
    public Map getEventInfo(Map map) {
        long facilityRrn = LocalContext.getFacilityRrn();
        String pcdId = map.get("pcdId").toString();
        String pcdType = map.get("pcdType").toString();
        String targetStatus = map.get("targetStatus").toString();

        if (StringUtils.isNotBlank(pcdId) && StringUtils.isNotBlank(pcdType) && StringUtils.isNotBlank(targetStatus)) {
            Map<String, Object> eventMap = carrierService
                    .getEventInfoByPcdId(facilityRrn, pcdId, pcdType, StringUtils.trimToUpperCase(targetStatus));
            return eventMap;
        }
        return null;
    }

    public ActionForward exportCarrierQuery(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String fileName = "carrierListInfo_" + DateUtils.getNowTime(DateUtils.DATE_FORMAT4DAYD) + ".xlsx";
        Map<String, Object> titles = WebUtils.getExportTitles(request);
        List<Map<String, Object>> data = (List<Map<String, Object>>) WebUtils.getExportDatas(request);
        titles.put("title", "carrierListInfo");
        int i = 0;
        for (Map<String, Object> m : data) {
            i++;
            m.put("seq", i);
        }

        WebUtils.exportExcel(fileName, titles, data, TemplateLocation.CARRIER_INFO_LIST, response);
        return WebUtils.NULLActionForward;
    }

    public String listenExportAll(Map<String, Object> params) throws InterruptedException {
        Iterator<CountDownProp> iterator = countDownPropList.iterator();
        while (iterator.hasNext()) {
            CountDownProp next = iterator.next();
            if (next.getCountDownLatch().getCount() == 0) {
                iterator.remove();
                continue;
            }
            if (next.getCountDownKey() + 15 * 60 * 1000 < (new Date()).getTime()) {
                next.getCountDownLatch().countDown();
                iterator.remove();
                continue;
            }
        }
        long countDownKey = com.mycim.framework.utils.lang.collections.MapUtils.getLongValue(params, "timestamp");
        CountDownLatch countDownLatch = new CountDownLatch(1);
        CountDownProp prop = new CountDownProp(countDownKey, countDownLatch);
        countDownPropList.add(prop);
        countDownLatch.await();
        return "success";
    }

    public ActionForward exportAll(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String strVal = request.getParameter("strVal");
        HashMap params = JsonUtils.getValue2Bean(strVal, HashMap.class);
        long countDownKey = MapUtils.getLongValue(params, "timestamp");
        long tempTime = (new Date()).getTime();
        CountDownProp prop = null;
        while (true) {
            boolean finded = false;
            for (CountDownProp prop1 : countDownPropList) {
                if (prop1.getCountDownKey() == countDownKey) {
                    prop = prop1;
                    finded = true;
                    break;
                }
            }
            if (finded) {
                break;
            }
            if (tempTime + 2 * 1000 < (new Date()).getTime()) {
                break;
            }
        }
        try {
            StopWatch sw = new StopWatch("carrier exportAll action");
            String fileName = "carrierListInfo_" + DateUtils.getNowTime(DateUtils.DATE_FORMAT4DAYD) + ".xlsx";
            Map<String, Object> titles = WebUtils.getExportTitles(request);
            long facilityRrn = LocalContext.getFacilityRrn();
            Map<String, Object> argMap = new HashMap<String, Object>(20);
            argMap.put("startRow", "0");
            argMap.put("limit", Integer.MAX_VALUE);
            argMap.put("pageSize", Integer.MAX_VALUE);
            argMap.put("status", "");
            argMap.put("type", "");
            argMap.put("category", "");
            argMap.put("page", "1");
            argMap.put("facility", facilityRrn);
            sw.start("query");
            Map<String, Object> dataMap = carrierService.qryCarrierListByPage(argMap);
            List<Map<String, Object>> results = (List<Map<String, Object>>) dataMap.get("data");
            sw.stop();
            titles.put("title", "carrierListInfo");
            WebUtils.exportExcel(fileName, titles, results, TemplateLocation.CARRIER_INFO_LIST, response);
            if (prop != null) {
                prop.getCountDownLatch().countDown();
            }
        } catch (Exception e) {
            LOGGER.error(e);
            if (prop != null && prop.getCountDownLatch().getCount() != 0) {
                prop.getCountDownLatch().countDown();
            }
            throw new SystemIllegalArgumentException(Errors.create().content(e.getMessage()).build());
        }
        return WebUtils.NULLActionForward;
    }

    public Map getCarrierInfoDetail(Map map) {
        long facilityRrn = LocalContext.getFacilityRrn();
        String carrierId = map.get("carrierId").toString();
        Map<String, Object> dataMap = new HashMap<String, Object>(20);
        if (StringUtils.isNotBlank(carrierId)) {
            String namedSpace = baseService.getNamedSpace(facilityRrn, ObjectList.ENTITY_KEY);
            dataMap = carrierService.getCarrierInfoDetailById(carrierId, namedSpace);
            PcdClean cleanInfo = carrierService.getPcdCleanInfo(MapUtils.getLong(dataMap, "carrierRrn"));
            if (cleanInfo != null && cleanInfo.getInstanceRrn() > 0) {
                dataMap.put("cleanCycle", cleanInfo.getCleanCycle());
                dataMap.put("cleanEqpt", cleanInfo.getCleanEqptId());
            }
            Map<String, Object> btnMap = queryButtonAvailabilityInfo(dataMap);
            dataMap.put("btnPermissionByEvent", btnMap);
        }
        return dataMap;
    }

    private Map<String, Object> queryButtonAvailabilityInfo(Map<String, Object> dataMap) {
        // check是否拥有从当前状态切换为目标状态的权限
        Map<String, Object> btnMap = carrierService
                .checkPcdChangeStatusButton(LocalContext.getFacilityRrn(), MapUtils.getLong(dataMap, "carrierRrn"),
                                            MapUtils.getString(dataMap, "carrierStatus"));
        // // #45007 PCD 组合规则定义
        ReferenceFile referenceFile = new ReferenceFile(ReferenceDetailNames.CARRIER_TYPE, getNamedSpace(ObjectList.REFERENCE_FILE_KEY, LocalContext.getFacilityRrn()),
                                                        ObjectList.REFERENCE_FILE_KEY);
        referenceFile = sysService.getReferenceFile(referenceFile);
        if (CollectionUtils.isNotEmpty(referenceFile.getValuesItems())) {
            List<ReferenceFileDetail> referenceFileDetailList = (List<ReferenceFileDetail>)referenceFile.getValuesItems();
            List<ReferenceFileDetail> referenceFileDetail = referenceFileDetailList.stream()
                                                                                   .filter(referenceDetail -> StringUtils
                                                                                           .equalsIgnoreCase(referenceDetail.getKey1Value(), MapUtils.getString(dataMap, "carrierType")))
                                                                                   .collect(Collectors.toList());
            // 默认不显示
            btnMap.put("toAssemblyBtn", Boolean.TRUE);
            btnMap.put("toPodBtn", Boolean.TRUE);
            btnMap.put("toDoorBtn", Boolean.TRUE);

            String data3Value = referenceFileDetail.get(0).getData3Value();
            // 若果PCDFlag=1,已CDFlag为主,不管pcdType填的什么
            if (StringUtils.equalsIgnoreCase(referenceFileDetail.get(0).getData2Value(), SystemConstant.Str.ONE)) {
                btnMap.put("toPodBtn", Boolean.FALSE);
            } else if (StringUtils.isNotBlank(data3Value)) {
                Boolean isPcdType = Boolean.FALSE;
                if (data3Value.matches("^[CPD]{1}+,+[CPD]{1}")) {
                    isPcdType = Boolean.TRUE;
                }
                if (data3Value.matches("^[CPD]{1}+,+[CPD]{1}+,+[CPD]{1}")) {
                    isPcdType = Boolean.TRUE;
                }
                if (!data3Value.contains("C")) {
                    isPcdType = Boolean.FALSE;
                }
                if (isPcdType) {
                    List<String> charList = Arrays.asList(data3Value.split(StringUtils.COMMA_SIGN));
                    long count = charList.stream().distinct().count();
                    if (charList.size() != count) {
                        isPcdType = Boolean.FALSE;
                    }
                }

                if (!isPcdType) {
                    btnMap.put("toAssemblyBtn", Boolean.FALSE);
                } else {
                    List<String> pcdTypes = Arrays.asList(data3Value.split(StringUtils.COMMA_SIGN));
                    for (String pcd: pcdTypes) {
                        if (StringUtils.equalsIgnoreCase(pcd, "P")) {
                            btnMap.put("toPodBtn", Boolean.FALSE);
                        }
                        if (StringUtils.equalsIgnoreCase(pcd, "D")) {
                            btnMap.put("toDoorBtn", Boolean.FALSE);
                        }
                    }
                }
            } else {
                btnMap.put("toAssemblyBtn", Boolean.FALSE);
            }
        }
        return btnMap;
    }

    public Map queryCarrierByPage(Map map) {
        long facilityRrn = LocalContext.getFacilityRrn();
        Map<String, Object> argMap = new HashMap<String, Object>(20);
        argMap.put("startRow", map.get("start"));
        argMap.put("limit", map.get("limit"));
        argMap.put("pageSize", map.get("limit"));
        argMap.put("carrierId", StringUtils.trim(map.get("CARRIER").toString()));
        argMap.put("status", StringUtils.trim(map.get("formCarrierStatus").toString()));
        argMap.put("type", StringUtils.trim(map.get("formCarrierType").toString()));
        argMap.put("category", StringUtils.trim(map.get("formCarrierCategory").toString()));
        argMap.put("facility", facilityRrn);
        return carrierService.qryCarrierListByPage(argMap);
    }

    public Carrier queryCarrierDetail(Map map) {
        long facilityRrn = LocalContext.getFacilityRrn();
        String carrierId = map.get("carrierId").toString();
        Carrier carrier = new Carrier();
        Assert.isFalse(StringUtils.isBlank(carrierId),
                       Errors.create().key(MessageIdList.CARRIER_CASSETTE_EMPTY).content("晶舟号不能为空!").build());
        long carrierRrn = baseService
                .getNamedObjectRrn(carrierId, this.getNamedSpace(ObjectList.ENTITY_KEY, facilityRrn),
                                   ObjectList.ENTITY_KEY, ObjectList.CARRIER_KEY);

        Assert.isFalse(carrierRrn < 1,
                       Errors.create().key(MessageIdList.CARRIER_CASSETTE_ID_MISSING).content("No such Cassette ID!")
                             .build());
        carrier = carrierService.getCarrier(carrierRrn);
        PcdClean carrierCleanInfo = carrierService.getPcdCleanInfo(carrier.getInstanceRrn());
        if (carrierCleanInfo != null && carrierCleanInfo.getInstanceRrn() > 0) {
            carrier.setCleanCycle(carrierCleanInfo.getCleanCycle());
        }
        return carrier;
    }

    public void delete(Map map) {
        String user = LocalContext.getUserId();
        long facilityRrn = LocalContext.getFacilityRrn();
        String carrierId = map.get("winCarrierId").toString();
        Assert.isFalse(StringUtils.isBlank(carrierId),
                       Errors.create().key(MessageIdList.CARRIER_CASSETTE_EMPTY).content("晶舟号不能为空!").build());
        carrierService.deleteCarrierEntity(carrierId, facilityRrn, user);
    }

    /**
     * Action方法:获取$CARRIER_TYPE的default value
     *
     * @param code CODE
     * @return Default Value
     */
    public String getSlotCount(String code) {
        List<String> values = sysService.getRefFileValues("$CARRIER_TYPE", code, "DATA_4_VALUE");
        String value = "25";
        if (CollectionUtils.isNotEmpty(values)) {
            value = values.get(0);
        }
        return value;
    }

    public List<Map> combobxData(HttpServletRequest request) {
        List<Map> list = putDefaultData();

        String type = request.getParameter("type");
        List<ReferenceFileDetail> comboData = queryComboDataList(type);

        for (ReferenceFileDetail detail : comboData) {
            Map jo = new HashMap(10);
            jo.put("value", detail.getKey1Value()); // 实际传递的值
            jo.put("key", detail.getData1Value()); // 显示在页面的值
            list.add(jo);
        }
        return list;
    }

    /**
     * 根据选择的category获取默认清洗周期
     */
    public Map getDefaultCleanCycle(Map map) {
        long facilityRrn = LocalContext.getFacilityRrn();
        String category = map.get("category").toString();
        String type = map.get("type").toString();
        Map result = new HashMap(20);
        double defaultCleanCycle = 0;
        if (StringUtils.isNotBlank(category)) {
            defaultCleanCycle = carrierService.getDefaultCleanCycle(category, type, facilityRrn);
        }
        result.put("defaultCleanCycle", defaultCleanCycle);
        return result;
    }

    /**
     * 根据选择的category获取晶舟号
     */
    public Map generateCarrierId(Map map) {
        String category = MapUtils.getString(map, "category");
        String carrierSize = MapUtils.getString(map, "carrierSize");
        String type = "P";
        //如果类型是PE,则参与命名的时候只显示P
        if (StringUtils.equalsIgnoreCase("PE", category)) {
            category = "P";
            //如果carrierSize为6 按原来naming role进行 若为8 命名以T开头
            if (StringUtils.equalsIgnoreCase("8", carrierSize)) {
                category = "T";
            }
        }

        Map result = new HashMap(20);
        String CarrierId = "";
        if (StringUtils.isNotBlank(category)) {
            CarrierId = carrierService.generateCarrierId(category + type);
        }
        result.put("defaultCarrierId", CarrierId);
        return result;
    }

    /**
     * 根据选择的category获取晶舟号, 针对 LAB_R
     */
    public Map generateCarrierId4LabR(Map map) {
        Map result = new HashMap(20);
        String labMark = "R";
        String category = MapUtils.getString(map, "category");
        String waferSize = MapUtils.getString(map, "waferSize");
        String carrierid = "";
        if (StringUtils.isNotBlank(category) && StringUtils.isNotBlank(waferSize)) {
            //LAB_R晶舟号生成规则:R + WaferSize() + Type(代码中category) + 5位数的流水号
            String prefix = labMark + StringUtils.trim(waferSize) + StringUtils.trim(category);
            int serialLength = 5;
            carrierid = carrierService.generateCarrierId(prefix.toUpperCase(), serialLength);
        }
        result.put("defaultCarrierId", carrierid);
        return result;
    }

    /**
     * 检查输入的carrierid是否已经存在
     */
    public Map checkCarrier(Map map) {
        long facilityRrn = LocalContext.getFacilityRrn();
        Map result = new HashMap(20);
        String carrierId = map.get("winCarrierId").toString();
        Assert.isTrue(StringUtils.isNotBlank(carrierId),
                      Errors.create().key(MessageIdList.CARRIER_CASSETTE_EMPTY).content("晶舟号不能为空!").build());
        carrierId = StringUtils.trimToUpperCase(carrierId);

        checkNamedObjectIdRule(carrierId, "Cassette");

        long carrierRrn = baseService.getNamedObjectRrn(
                carrierId, baseService.getNamedSpace(facilityRrn, ObjectList.ENTITY_KEY),ObjectList.ENTITY_KEY, ObjectList.CARRIER_KEY);

        if (carrierRrn < 1) {
            long namedObjectRrn = baseService.getNamedObjectRrn(
                    carrierId, baseService.getNamedSpace(facilityRrn, ObjectList.ENTITY_KEY),ObjectList.ENTITY_KEY);
            Assert.isTrue(namedObjectRrn < 1,
                          Errors.create().key(MessageIdList.CARRIER_ID_EXISTS).content("系统中已存在此ID!").build());

            Map<String, Object> allowableMap = baseService.getAllowableEventSetFirst(
                    baseService.getNamedSpace(facilityRrn, ObjectList.ALLOWABLEEVENTSET_KEY), ObjectList.CARRIER_KEY);

            result.put("carrierId", carrierId);
            result.put("defaultColor", "0");
            result.put("allowableEvent", allowableMap.get("allwoableEventId"));
            return result;

        } else {
            result.put("carrierId", "");
            throw new SystemIllegalArgumentException(
                    Errors.create().key(MessageIdList.CARRIER_CASSETTE_EXISTS).content("晶舟号已存在").build());
        }
    }

    public ActionForward carrierInfoTab(HttpServletRequest request, ActionMapping mapping) {
        request.setAttribute("pcdId", request.getParameter("carrierId"));
        request.setAttribute("transId", "carrier");
        return mapping.findForward("pcdInfoTab");
    }

    public ActionForward getCommentHistory(HttpServletRequest request, ActionMapping mapping) {
        String user = LocalContext.getUserId();
        long facilityRrn = LocalContext.getFacilityRrn();
        return this.getCommentHistory(request, mapping, facilityRrn, user, "carrierPortal", "getCommentHistory");
    }


    public void modify(Map map) {
        String user = LocalContext.getUserId();
        long facilityRrn = LocalContext.getFacilityRrn();
        Map<String, Object> attrMap = getRequestParameterMap(map);
        Assert.isFalse(StringUtils.isBlank(MapUtils.getString(attrMap, CARRIER_ID)),
                       Errors.create().key(MessageIdList.CARRIER_CASSETTE_EMPTY).content("晶舟号不能为空!").build());

        Assert.isFalse(StringUtils.isBlank(MapUtils.getString(attrMap, CARRIER_STATUS)),
                       Errors.create().key(MessageIdList.CARRIER_CASSETTE_STATUS_EMPTY).content("晶舟状态不能为空!").build());

        Assert.isFalse(StringUtils.isBlank(MapUtils.getString(attrMap, SystemConstant.Pcd.CARRIER_TYPE)),
                       Errors.create().key(MessageIdList.CARRIER_CASSETTE_TYPE_EMPTY).content("晶舟类型不能为空!").build());

        Assert.isFalse(StringUtils.isBlank(MapUtils.getString(attrMap, CARRIER_ALLOWABLE_EVENT)),
                       Errors.create().key(MessageIdList.CARRIER_ALLOWABLE_EVENT_EMPTY).content("允许事件集号不能为空!").build());

        Assert.isFalse(StringUtils.isBlank(MapUtils.getString(attrMap, CARRIER_CATEGORY)),
                       Errors.create().key(MessageIdList.CARRIER_CASSETTE_CATEGORY_EMPTY).content("晶舟类别不能为空!").build());

        Assert.isFalse(StringUtils.isBlank(MapUtils.getString(attrMap, CARRIER_CLEAN_CYLE)),
                       Errors.create().key(MessageIdList.CARRIER_CLEAN_CYCLE_EMPTY).content("清洗周期不能为空!").build());


        String carrierCleanCycle = MapUtils.getString(attrMap, "carrierCleanCycle");
        Assert.isFalse(StringUtils.length(carrierCleanCycle) > CLEAN_CYCLE_NUM_SIX,
                       Errors.create().key(MessageIdList.CARRIER_CLEAN_LENGTH_EXCEED_SIX).content("清洗周期不能超过6位数!")
                             .build());

        // 修改操作
        long carrierRrn = baseService.getNamedObjectRrn(MapUtils.getString(attrMap, "carrierId"),
                                                        baseService.getNamedSpace(facilityRrn, ObjectList.ENTITY_KEY),
                                                        ObjectList.ENTITY_KEY, ObjectList.CARRIER_KEY);

        // 不存在,输出提示到界面
        Assert.isTrue(carrierRrn > 0,
                      Errors.create().key(MessageIdList.CARRIER_CASSETTE_MISSING).content("Cassette 不存在").build());
        Carrier carrier = carrierService.getCarrier(carrierRrn);

        Assert.isTrue(StringUtils.isNotBlank(carrier.getCarrierStatus()) &&
                              StringUtils.equalsIgnoreCase(carrier.getCarrierStatus(), PcdStatus.FREE_KEY),
                      Errors.create().key(MessageIdList.CARRIER_FREE_STATUS_CAN_MODIFY).content("只有FREE状态的晶舟才能修改!")
                            .build());

        attrMap.put("carrierRrn", carrierRrn);
        attrMap.put("carrierAvailableSlotCount", carrier.getAvailableSlotCount());
        carrierService.updateCarrierEntity(attrMap, facilityRrn, user);

    }

    public void save(Map map) {
        String user = LocalContext.getUserId();
        long facilityRrn = LocalContext.getFacilityRrn();
        Map<String, Object> attrMap = getRequestParameterMap(map);
        String carrierId;
        Assert.isFalse(StringUtils.isBlank(carrierId = MapUtils.getString(attrMap, CARRIER_ID)),
                       Errors.create().key(MessageIdList.CARRIER_CASSETTE_EMPTY).content("晶舟号不能为空!").build());

        Assert.isFalse((StringUtils.length((MapUtils.getString(attrMap, CARRIER_ID))) > CARRIER_ID_MAXLENGTH),
                       Errors.create().key(MessageIdList.CARRIER_ID_LENGTH_OVERMAX).content("晶舟号长度不能超过64个字节!").build());

        Assert.isFalse((StringUtils.length((MapUtils.getString(attrMap, CARRIERDESC))) > DESCRIPTION_MAXLENGTH),
                      Errors.create().key(MessageIdList.CARRIERDESC_LENGTH_OVERMAX).content("晶舟描述不能超过128个字节!").build());

        Assert.isFalse(StringUtils.isBlank(MapUtils.getString(attrMap, CARRIER_STATUS)),
                       Errors.create().key(MessageIdList.CARRIER_CASSETTE_STATUS_EMPTY).content("晶舟状态不能为空!").build());

        Assert.isFalse(StringUtils.isBlank(MapUtils.getString(attrMap, SystemConstant.Pcd.CARRIER_TYPE)),
                       Errors.create().key(MessageIdList.CARRIER_CASSETTE_TYPE_EMPTY).content("晶舟类型不能为空!").build());

        Assert.isFalse(StringUtils.isBlank(MapUtils.getString(attrMap, CARRIER_ALLOWABLE_EVENT)),
                       Errors.create().key(MessageIdList.CARRIER_ALLOWABLE_EVENT_EMPTY).content("允许事件集号不能为空!").build());

        Assert.isFalse(StringUtils.isBlank(MapUtils.getString(attrMap, CARRIER_CATEGORY)),
                       Errors.create().key(MessageIdList.CARRIER_CASSETTE_CATEGORY_EMPTY).content("晶舟类别不能为空!").build());

        Assert.isFalse(StringUtils.isBlank(MapUtils.getString(attrMap, CARRIER_CLEAN_CYLE)),
                       Errors.create().key(MessageIdList.CARRIER_CLEAN_CYCLE_EMPTY).content("清洗周期不能为空!").build());

        String carrierCleanCycle = MapUtils.getString(attrMap, CARRIER_CLEAN_CYLE);
        Assert.isFalse(StringUtils.length(carrierCleanCycle) > CLEAN_CYCLE_NUM_SIX,
                       Errors.create().key(MessageIdList.CARRIER_CLEAN_LENGTH_EXCEED_SIX).content("清洗周期不能超过6位数!")
                             .build());

        checkNamedObjectIdRule(carrierId, "Cassette");

        long carrierRrn = baseService.getNamedObjectRrn(MapUtils.getString(attrMap, CARRIER_ID),
                                                        baseService.getNamedSpace(facilityRrn, ObjectList.ENTITY_KEY),
                                                        ObjectList.ENTITY_KEY, ObjectList.CARRIER_KEY);

        Assert.isTrue(carrierRrn < 1,
                      Errors.create().key(MessageIdList.CARRIER_CASSETTE_EXISTS).content("晶舟号已存在!").build());

        long namedObjectRrn = baseService.getNamedObjectRrn(MapUtils.getString(attrMap, "carrierId"), baseService
                .getNamedSpace(facilityRrn, ObjectList.ENTITY_KEY), ObjectList.ENTITY_KEY);
        Assert.isTrue(namedObjectRrn < 1,
                      Errors.create().key(MessageIdList.CARRIER_ID_EXISTS).content("系统中已存在此ID!").build());
        //checkCarrierType(MapUtils.getString(attrMap, "carrierType"));
        carrierService.addCarrierEntity(attrMap, facilityRrn, user);
        initStatusByEvent(facilityRrn, user, MapUtils.getString(attrMap, "carrierId"), ObjectList.CARRIER_KEY,
                          EventName.INIT_CST);
    }

    private Map<String, Object> getRequestParameterMap(Map paramMap) {
        Map<String, Object> map = new HashMap<String, Object>(20);
        map.put("carrierId", paramMap.get("winCarrierId"));
        map.put("carrierDesc", paramMap.get("winCarrierDesc"));
        map.put("carrierStatus", paramMap.get("winCarrierStatus"));
        map.put("carrierType", paramMap.get("winCarrierType"));
        map.put("carrierColor", paramMap.get("winCarrierColor"));
        map.put("carrierPosition", paramMap.get("winCarrierLocation"));
        map.put("carrierSlotCount", paramMap.get("winSlotCount"));
        map.put("carrierPollutionLevel", paramMap.get("winCarrierPollutionLevel"));
        map.put("carrierAllowableEvent", paramMap.get("winCarrierAllowableEvent"));
        map.put("carrierEngineerGroupID", paramMap.get("winCarrierEngineerGroupID"));
        map.put("carrierlocation", paramMap.get("carrierlocation"));
        map.put("carrierCategory", paramMap.get("winCarrierCategory"));
        map.put("carrierCleanCycle", paramMap.get("winCarrierCleanCycle"));

        return map;
    }

    class CountDownProp implements Comparable {
        private long countDownKey;

        private CountDownLatch countDownLatch;

        CountDownProp(long countDownKey, CountDownLatch countDownLatch) {
            this.countDownKey = countDownKey;
            this.countDownLatch = countDownLatch;
        }

        public long getCountDownKey() {
            return countDownKey;
        }

        public void setCountDownKey(long countDownKey) {
            this.countDownKey = countDownKey;
        }

        public CountDownLatch getCountDownLatch() {
            return countDownLatch;
        }

        public void setCountDownLatch(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof CountDownProp)) {
                return false;
            }
            CountDownProp t = (CountDownProp) obj;
            return this.countDownKey == t.countDownKey;
        }

        @Override
        public int compareTo(Object obj) {
            CountDownProp team = (CountDownProp) obj;
            int num = (int) (this.countDownKey - team.countDownKey);
            return num;
        }

    }

    public Map<String,Object> generateIdByCSType(Map<String,Object> param){
        String type =MapUtils.getString(param,"type");
        String cstId = generatePCDId(SystemConstant.Pcd.CARRIER, type);
        Map result = new HashMap<String,Object>();
        result.put("cstId",cstId);
        return result;
    }

    // 手动change cassette type
    public void manualExchangePCDType(Map param) {
        String carrierId = MapUtils.getString(param, "carrierId");
        List<Lot> lotList = lotInqService.getLotListByCarrierId(carrierId);
        Carrier carrier = carrierService
                .getCarrier(LocalContext.getFacilityRrn(), MapUtils.getString(param, "carrierId"));
        Assert.state(StringUtils.equalsIgnoreCase(carrier.getCarrierStatus(), PcdStatus.FREE_KEY) ||
                             StringUtils.equalsIgnoreCase(carrier.getCarrierStatus(), PcdStatus.ASSEMBLY_KEY),
                     Errors.create().key(MessageIdList.CARRIER_FREE_STATUS_CAN_MODIFY).content("只有FREE状态的晶舟才能修改!")
                                                                                                   .build());

        String lotIds = lotList.stream().map(Lot::getLotId).collect(Collectors.joining(StringUtils.COMMA_SIGN));
        Assert.state(StringUtils.isEmpty(lotIds),
                     Errors.create().key(MessageIdList.CARRIER_MANUAL_CHANGE_TYPE_LOT_ERROR)
                           .content("Cassette: {} binging lot: {} cannot manual change type ")
                           .args(MapUtils.getString(param, "carrierId"), lotIds).build());
        carrierService.manualExchangePCDType(carrier);
    }


    // 检查cassette type
    private void checkCarrierType(String carrierType) {
        ReferenceFileDetail referenceFileDetail = new ReferenceFileDetail(ReferenceDetailNames.PROCESS_LOCATION_AUTO_CHANGE_CASSETTE_TYPE,
                                                                          getNamedSpace(ObjectList.REFERENCE_FILE_KEY,
                                                                                        LocalContext.getFacilityRrn()),
                                                                          ObjectList.REFERENCE_FILE_KEY);
        List<ReferenceFileDetail> referenceFileDetails = sysService
                .getReferenceFileDetails(referenceFileDetail, LocalContext.getFacilityRrn());
        for (ReferenceFileDetail ref : referenceFileDetails) {
            Matcher mathcher = WipUtils.PCDPATERN.matcher(ref.getData1Value());
            if(mathcher.matches()) {
                Assert.state(!StringUtils.equalsIgnoreCase(StringUtils.split(ref.getData1Value(), "-")[1], carrierType),
                             Errors.create().key(MessageIdList.CARRIER_CREATE_TYPE_ERROR)
                                   .content("Cannot create a cassette with cassette type {}!").args(carrierType).build());
            }

        }
    }

}