package com.lcrx.selector.service;

import com.alibaba.fastjson.JSON;
import com.lcrx.selector.constant.Constant;
import com.lcrx.selector.constant.RedisKey;
import com.lcrx.selector.entity.DO.VariantTableDO;
import com.lcrx.selector.entity.DTO.InitializationInputDTO.CharacteristicListBean;
import com.lcrx.selector.entity.DTO.PreVerifyInputDTO;
import com.lcrx.selector.entity.DTO.PreVerifyOutputDTO;
import com.lcrx.selector.entity.PO.QuantityMappingPO;
import com.lcrx.selector.entity.PO.TotalQuantityMappingPO;
import com.lcrx.selector.entity.PO.VariantTablePO;
import com.lcrx.selector.entity.DO.InitializeResultDO;
import com.lcrx.selector.entity.POJO.TotalQuantityCalcResultPOJO;
import com.lcrx.selector.enums.CharacteristicType;
import com.lcrx.selector.enums.YesOrNo;
import com.lcrx.selector.utils.CastHelper;
import com.lcrx.selector.utils.RedisHelper;
import com.lcrx.selector.utils.StringHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ###
 */
@Service
public class VariantTableService {
    @Value("${applicationSettings.sessionTimeout}")
    private Long sessionTimeout;
    @Value("${applicationSettings.variantTableEmptyGroupPlaceholderValue}")
    private String variantTableEmptyGroupPlaceholderValue;
    @Value("${applicationSettings.system}")
    private String system;

    private final SelectorCacheService selectorCacheService;
    private final RedisHelper redisHelper;

    public VariantTableService(SelectorCacheService selectorCacheService,
                               RedisHelper redisHelper) {
        this.selectorCacheService = selectorCacheService;
        this.redisHelper = redisHelper;
    }

    public InitializeResultDO initializeMaterialVariantTable(
                                                    Map<String, List<String>> totalCharacteristicList,
                                                    Map<Integer, Map<Integer, Map<String, List<String>>>> variantTableList,
                                                    Map<Integer, List<Integer>> invalidGroupMap) {

        InitializeResultDO initializeResultDO = new InitializeResultDO();

        initializeResultDO.setVariantTableMap(variantTableList);

        Map<String, List<String>> singleVariantTable;

        if (null != variantTableList && variantTableList.size() > 0) {
            int findCnt;

            for (int i = 1; i <= variantTableList.size(); i++) {
                Map<Integer, Map<String, List<String>>> groupVariantTableMap = variantTableList.get(i);
                for (int j = 1; j <= groupVariantTableMap.size(); j++) {
                    //之前已经确认是无效的行了
                    if (invalidGroupMap.containsKey(i) && invalidGroupMap.get(i).contains(j)) {
                        continue;
                    }

                    Map<String, List<String>> variantTableCharacteristicValueMap = groupVariantTableMap.get(j);
                    //去除无效的VT组
                    findCnt = 0;
                    for (Map.Entry<String, List<String>> entry : variantTableCharacteristicValueMap.entrySet()) {
                        List<String> ls = new ArrayList<>();
                        Collections.addAll(ls, new String[entry.getValue().size()]);
                        Collections.copy(ls, entry.getValue());
                        ls.retainAll(totalCharacteristicList.get(entry.getKey()));
                        if (ls.size() > 0) {
                            //此列值有效
                            findCnt++;
                        } else {
                            break;
                        }
                    }

                    if (findCnt < variantTableCharacteristicValueMap.size()) {
                        if (invalidGroupMap.containsKey(i)) {
                            invalidGroupMap.get(i).add(j);
                        } else {
                            List<Integer> invalidGroupList = new ArrayList<>();
                            invalidGroupList.add(j);
                            invalidGroupMap.put(i, invalidGroupList);
                        }
                        continue;
                    }

                    for (Map.Entry<String, List<String>> lineData : variantTableCharacteristicValueMap.entrySet()) {
                        List<String> tmpCharacteristicValueList = new ArrayList<>();
                        Collections.addAll(tmpCharacteristicValueList, new String[lineData.getValue().size()]);
                        Collections.copy(tmpCharacteristicValueList, lineData.getValue());

                        if (!initializeResultDO.getVariantTableGroupMap().containsKey(i)) {
                            singleVariantTable = new HashMap<>();
                            singleVariantTable.put(lineData.getKey(), tmpCharacteristicValueList);

                            initializeResultDO.getVariantTableGroupMap().put(i, singleVariantTable);
                        } else if (!initializeResultDO.getVariantTableGroupMap().get(i).containsKey(lineData.getKey())) {
                            initializeResultDO.getVariantTableGroupMap().get(i).put(lineData.getKey(), tmpCharacteristicValueList);
                        } else {
                            //同一个变式表取并集
                            if (initializeResultDO.getVariantTableGroupMap().get(i).get(lineData.getKey()) != null) {
                                //做交集
                                tmpCharacteristicValueList.addAll(initializeResultDO.getVariantTableGroupMap().get(i).get(lineData.getKey()));
                            }

                            initializeResultDO.getVariantTableGroupMap().get(i).put(lineData.getKey(), tmpCharacteristicValueList);
                        }
                    }
                }
            }
        }

        return initializeResultDO;
    }

    /**
     * 前置验证
     *
     * @param totalCharacteristicList       全部的配置信息
     * @param selectedCharacteristicValueMap  已选的配置信息
     * @param preVerifyInputDTO    入参
     * @return PreValidationOutputV2DTO
     */
    public PreVerifyOutputDTO preVerify(List<CharacteristicListBean> totalCharacteristicList,
                                        HashMap<String, String> selectedCharacteristicValueMap,
                                         PreVerifyInputDTO preVerifyInputDTO) {
        PreVerifyOutputDTO preVerifyOutputDTO = new PreVerifyOutputDTO();

        boolean clearSelected = false;

        //请选择 讲对应的数量c的值删除
        if (Constant.CHARACTERISTIC_UNSELECTED_VALUE.equals(preVerifyInputDTO.getCharacteristicValueName())) {
            clearSelected = true;
        }

        Map<String, String> quantityCharacteristicMap = new HashMap<>();
        List<String> quantityCharacteristicList = new ArrayList<>();
        List<QuantityMappingPO> quantityMappingPOList = selectorCacheService.getQuantityMapping(system);
        List<TotalQuantityMappingPO> totalQuantityMappingPOList = selectorCacheService.getTotalQuantityMapping(system);

        for(QuantityMappingPO quantityMappingPO : quantityMappingPOList)
        {
            quantityCharacteristicMap.put(quantityMappingPO.getPrimaryCharacteristicName(), quantityMappingPO.getAssociatedCharacteristicName());
            quantityCharacteristicList.add(quantityMappingPO.getAssociatedCharacteristicName());
        }

        Map<String, List<String>> totalCharacteristicAndValues = totalCharacteristicList.stream().collect(HashMap::new,
                (map, characteristicListBean) -> {
                    map.put(characteristicListBean.getName(),
                            characteristicListBean.getValues().stream().map(CharacteristicListBean.ValuesBean::getName).collect(Collectors.toList()));
                }, HashMap::putAll);

        //隐藏的特征
        List<String> hiddenCharacteristicList = totalCharacteristicList.stream().filter(characteristicListBean ->
                        characteristicListBean.getIsDerive() == YesOrNo.Yes.getYesOrNo()
                                || characteristicListBean.getInvisibleForSales() == YesOrNo.Yes.getYesOrNo())
                .collect(Collectors.toList()).stream().map(CharacteristicListBean::getName).collect(Collectors.toList());

        List<String> techHiddenCharacteristicList = totalCharacteristicList.stream().filter(characteristicListBean ->
                characteristicListBean.getIsDerive() == YesOrNo.Yes.getYesOrNo())
                .collect(Collectors.toList()).stream().map(CharacteristicListBean::getName).collect(Collectors.toList());

        List<String> numberCharacteristicList = new ArrayList<>();
        Map<String, String> numberCharacteristicValueList = new HashMap<>();
        List<String> pureTotalCharacteristicList = new ArrayList<>();

        for(CharacteristicListBean characteristicListBean: totalCharacteristicList)
        {
            if(characteristicListBean.getType() == CharacteristicType.Num.getCharacteristicType())
            {
                numberCharacteristicList.add(characteristicListBean.getName());

                for(CharacteristicListBean.ValuesBean valuesBean: characteristicListBean.getValues())
                {
                    numberCharacteristicValueList.put(characteristicListBean.getName().concat("_").concat(valuesBean.getName()), valuesBean.getName());
                }
            }

            pureTotalCharacteristicList.add(characteristicListBean.getName());
        }

        List<String> numberHiddenCharacteristicList = totalCharacteristicList.stream().filter(characteristicListBean ->
                        characteristicListBean.getType() == CharacteristicType.Num.getCharacteristicType()
                    && characteristicListBean.getIsDerive() == YesOrNo.Yes.getYesOrNo()
                )
                .collect(Collectors.toList()).stream().map(CharacteristicListBean::getName).collect(Collectors.toList());

        //通过遍历特征list判断
        boolean hasNumberCharacteristic = numberCharacteristicList.size() > 0;

        if(hasNumberCharacteristic)
        {
            List<String> hiddenCharacteristicTempList = getHiddenNumberCharacteristic(totalQuantityMappingPOList, quantityMappingPOList);
            hiddenCharacteristicList.removeAll(hiddenCharacteristicTempList);
            hiddenCharacteristicList.addAll(hiddenCharacteristicTempList);
        }

        Map<Integer, VariantTableDO> variantTableDOMap = getVariantTable(system, preVerifyInputDTO.getProductGroupCode(), preVerifyInputDTO.getMaterialCode());

        //Cache需要考虑只参与一个variantTable的从属C集合表
        List<String> followCharacteristicList = getFollowCharacteristicList(variantTableDOMap,
                numberCharacteristicList, totalQuantityMappingPOList, numberHiddenCharacteristicList);

        followCharacteristicList.retainAll(hiddenCharacteristicList);

        Map<String, List<String>> totalCharacteristicAndValueMap = new HashMap<>(totalCharacteristicAndValues);

        Map<String, List<String>> relationship;

        if (!StringHelper.isNullOrEmpty(preVerifyInputDTO.getCharacteristicName())) {
            if (!StringHelper.isNullOrWhiteSpace(preVerifyInputDTO.getCharacteristicValueName())) {
                selectedCharacteristicValueMap.put(preVerifyInputDTO.getCharacteristicName(), preVerifyInputDTO.getCharacteristicValueName());
            } else {
                selectedCharacteristicValueMap.remove(preVerifyInputDTO.getCharacteristicName());
            }
        }

        //需要check的VT，如果不包含List里的特征则忽略。默认check所有变化的特征，选中也是一种变化。
        List<String> needCheckCharacteristicList = new ArrayList<>();

        for (Map.Entry<String, String> kvp : selectedCharacteristicValueMap.entrySet()) {
            needCheckCharacteristicList.add(kvp.getKey());
        }

        TotalQuantityCalcResultPOJO totalQuantityCalcResultPOJO = new TotalQuantityCalcResultPOJO();
        totalQuantityCalcResultPOJO.setResult(true);
        totalQuantityCalcResultPOJO.setCharacteristicValueList(new ArrayList<>());

        //验证total数量,先Check是否需要数量验证
        if (!StringHelper.isNullOrEmpty(preVerifyInputDTO.getCharacteristicName())
                && numberCharacteristicList.size() > 0) {
            totalQuantityCalcResultPOJO = calcTotalQuantityProcedure(preVerifyInputDTO.getCharacteristicValueName(),
                    numberCharacteristicValueList, selectedCharacteristicValueMap, totalQuantityMappingPOList);
            if (totalQuantityCalcResultPOJO.isResult() && totalQuantityCalcResultPOJO.getCharacteristicValueList().size() > 0) {
                for (String forceCharacteristicValue : totalQuantityCalcResultPOJO.getForceCharacteristicValueList()
                ) {
                    String forceCharacteristicName = forceCharacteristicValue.split(":")[0];
                    String forceCharacteristicValueName = forceCharacteristicValue.split(":")[1].split("_")[1];

                    selectedCharacteristicValueMap.put(forceCharacteristicName, forceCharacteristicValueName);
                    if (!needCheckCharacteristicList.contains(forceCharacteristicName)) {
                        needCheckCharacteristicList.add(forceCharacteristicName);
                    }
                }
            }
            //已经选择了部分用于累加的数量型C
            else if (totalQuantityCalcResultPOJO.isPartialQuantitySelection()) {
                for (Map.Entry<String, Integer> entry : totalQuantityCalcResultPOJO.getTotalCharacteristicValueList().entrySet()) {
                    String totalCharacteristicName = entry.getKey();
                    needCheckCharacteristicList.add(totalCharacteristicName);

                    //清洗比临时计算出的total c小的值
                    List<String> invalidCharacteristicValues = totalCharacteristicAndValues.get(totalCharacteristicName).stream().filter(characteristicValue ->
                            Integer.parseInt(characteristicValue) < entry.getValue()).collect(Collectors.toList());
                    totalCharacteristicAndValues.get(totalCharacteristicName).removeAll(invalidCharacteristicValues);
                }
            }
        }

        ///第一次调用的返回结果
        relationship = new HashMap<>();
        //计数器
        int cnt = 1;
        //todo 配置最大挖掘深度
        int maxDig = 10;
        //结果
        String resultStatus;
        // 当前调用的返回结果集合
        Map<String, List<String>> relationshipTemp;

        //todo 数量型特征Special先不处理
        Map<String, List<String>> hiddenSpecialCharacteristicMap = new HashMap<>();

        String conflictGroup = "";

        Map<Integer, Map<Integer, Map<String, List<String>>>> totalVariantTableMap = new HashMap<>(variantTableDOMap.size());

        buildVariantTableStructure(variantTableDOMap, totalVariantTableMap);

        //#region   //2.对当前选中 进行第一轮筛选。
        //判断可见特征部分是否全部选择
        List<String> variantTableCharacteristicList = getAllCharacteristic(variantTableDOMap);
        boolean allSelected = checkAllSelected(selectedCharacteristicValueMap, variantTableCharacteristicList, hiddenCharacteristicList);
        //只选取本BOM参与公式的
        List<String> formulaCharacteristicList = getFormulaCharacteristic(totalQuantityMappingPOList, quantityMappingPOList);
        formulaCharacteristicList.retainAll(variantTableCharacteristicList);

        needCheckCharacteristicList = new ArrayList<>(variantTableCharacteristicList);

        List<String> totalQuantitiesCharacteristicList = totalQuantityMappingPOList.stream().map(TotalQuantityMappingPO::getTotalCharacteristicName).collect(Collectors.toList());
        Map<String, Boolean> totalSelectionResultMap = getTotalCharacteristicSelectionStatus(totalQuantityMappingPOList,
                selectedCharacteristicValueMap, pureTotalCharacteristicList);

        //既有显示数字型C，又有隐藏非数字型C的VT,此部分需要使隐藏C升级参与到VT判断中来
        Map<Integer, Map<String, List<String>>> upgradedNonNumCharacteristicMap = getUpgradeNonNumericCharacteristic(totalVariantTableMap,
                hiddenCharacteristicList, quantityCharacteristicList);

        //标明失效的行
        Map<Integer, List<Integer>> invalidGroupMap;
        Map<Integer, Map<Integer, Map<String, List<String>>>> tempVariantTableMap = new HashMap<>(totalVariantTableMap);
        Map<Integer, Map<String, List<String>>> tempVariantTableGroupMap;

        //3.对当前选中 进行第二轮筛选。
        resultStatus = "false";

        String procResult = "{\"type\":\"check-pr\"}";
        List<String> emptyCharacteristics = new ArrayList<>();

        int isSuccess;
        //为了不让VT的0值的default rule被忽略，所以cvs全集要加入0
        totalCharacteristicAndValueMap.forEach((k, v)->{
            v.add(variantTableEmptyGroupPlaceholderValue);
        });

        do {
            //初始化 为 0
            isSuccess = 0;
            invalidGroupMap = new HashMap<>();

            InitializeResultDO initializeResultDO = selectorFilter(
                    selectedCharacteristicValueMap,
                    totalCharacteristicAndValueMap,
                    totalVariantTableMap,
                    invalidGroupMap,
                    hasNumberCharacteristic,
                    formulaCharacteristicList,
                    totalQuantitiesCharacteristicList,
                    quantityCharacteristicMap,
                    hiddenCharacteristicList,
                    allSelected,
                    false,
                    needCheckCharacteristicList,
                    totalSelectionResultMap,
                    followCharacteristicList,
                    hiddenSpecialCharacteristicMap,
                    upgradedNonNumCharacteristicMap);

            tempVariantTableGroupMap = initializeResultDO.getVariantTableGroupMap();

            //变式表之间取交集
            for (Map.Entry<Integer, Map<String, List<String>>> entry : tempVariantTableGroupMap.entrySet()) {
                for (Map.Entry<String, List<String>> entryCharacteristicValue : entry.getValue().entrySet()) {
                    if (!relationship.containsKey(entryCharacteristicValue.getKey())) {
                        relationship.put(entryCharacteristicValue.getKey(), entryCharacteristicValue.getValue());
                    } else {
                        relationship.get(entryCharacteristicValue.getKey()).retainAll(entryCharacteristicValue.getValue());
                    }
                }
            }

            boolean hasEmptyChar = false;
            //出现unselect
            for (Map.Entry<String, List<String>> kvp : relationship.entrySet()) {
                if (kvp.getValue().size() == 0) {
                    hasEmptyChar = true;
                    emptyCharacteristics.add(kvp.getKey());
                    break;
                }
            }

            if (hasEmptyChar || !StringHelper.isNullOrEmpty(conflictGroup)) {
                resultStatus = "unselect";
                break;
            }
            if (checkConflict(relationship, selectedCharacteristicValueMap, hiddenCharacteristicList)) {
                resultStatus = "unselect";
                break;
            }

            //重新初始化需要check的特征list
            //判断relationship 结果集是否 与 BOMInitialize(bomCode, aryCVSClone, division);结果集一致，如不一直则继续循环处理aryCVSClone结果集
            for (Map.Entry<String, List<String>> relationshipItem : relationship.entrySet()) {
                List<String> tempCharacteristicValueList = totalCharacteristicAndValueMap.get(relationshipItem.getKey());
                List<String> relationshipItemValue = relationship.get(relationshipItem.getKey());
                //如过数量为0 ，则直接跳出循环
                if (tempCharacteristicValueList.size() == 0 || relationshipItemValue.size() == 0) {
                    isSuccess = 0;
                    break;
                }

                List<String> resultList = new ArrayList<>(tempCharacteristicValueList);
                //两个结果集取交集，
                resultList.retainAll(relationshipItemValue);
                //如过交集后个数，与原数据 个数不一致，则将交集结果 赋值 aryCVSClone
                if (resultList.size() != tempCharacteristicValueList.size() || resultList.size() != relationshipItemValue.size()) {
                    List<String> aryCVSResult = new ArrayList<>(resultList);

                    totalCharacteristicAndValueMap.put(relationshipItem.getKey(), aryCVSResult);
                    isSuccess++; //证明特征值不一样
                }
            }

            ///出现true。和variant无关
            if (relationship.size() == 0) {
                resultStatus = "true";
                break;
            }

            if (totalCharacteristicAndValueMap.size() == 0) {
                isSuccess = 0;
            }

            if (cnt > maxDig) {
                resultStatus = "overflow";
                break;
            }

            //数量特征的后置计算
            //有新值选中，需要模拟判断是否全部选择完毕
            allSelected = checkAllSelected(selectedCharacteristicValueMap,
                    variantTableCharacteristicList,
                    hiddenCharacteristicList);

            if (hasNumberCharacteristic) {
                //数量特征
                totalSelectionResultMap = getTotalCharacteristicSelectionStatus(totalQuantityMappingPOList,
                        selectedCharacteristicValueMap, pureTotalCharacteristicList);

                for (String quantityCharacteristic : quantityCharacteristicList) {
                    if (totalSelectionResultMap.containsKey(quantityCharacteristic) && totalSelectionResultMap.get(quantityCharacteristic)) {
                        needCheckCharacteristicList.add(quantityCharacteristic);
                    }
                }

                //todo 解决3.5寸盘数量限制问题
                Map<String, List<String>> dicUnProc = procCalcUnSelect(selectedCharacteristicValueMap,
                        relationship,  totalQuantityMappingPOList, quantityMappingPOList, totalCharacteristicList);

                if (relationship.size() > 0) {
                    //移除不可用的v
                    for (String key : relationship.keySet()) {
                        if (dicUnProc.containsKey(key)) {
                            List<String> characteristicValueList = dicUnProc.get(key);
                            List<String> tempCharacteristicValueList = new ArrayList<>(characteristicValueList);

                            totalCharacteristicAndValueMap.get(key).removeAll(tempCharacteristicValueList);
                        }
                    }
                }
            }

            cnt++;

        } while (isSuccess != 0);

        relationshipTemp = new HashMap<>(relationship);

        //获取proc计算出来不可选的v
        Map<String, List<String>> dicUnProc = procCalcUnSelect(selectedCharacteristicValueMap,
                relationshipTemp, totalQuantityMappingPOList, quantityMappingPOList, totalCharacteristicList);

        if (relationship.size() > 0) {
            //移除不可用的v
            for (String key : relationshipTemp.keySet()) {
                if (dicUnProc.containsKey(key)) {
                    List<String> characteristicValueList = dicUnProc.get(key);

                    List<String> tempCharacteristicValueList = new ArrayList<>(characteristicValueList);

                    relationshipTemp.get(key).removeAll(tempCharacteristicValueList);
                }
            }

            for (String key : dicUnProc.keySet()) {
                if (!relationshipTemp.containsKey(key)) {
                    List<String> characteristicValueList = new ArrayList<>(totalCharacteristicAndValueMap.get(key));
                    characteristicValueList.removeAll(dicUnProc.get(key));
                    relationshipTemp.put(key, characteristicValueList);
                }
            }
        }

        if (relationshipTemp.size() > 0 && !"unselect".equals(resultStatus)) {

            List<PreVerifyOutputDTO.ActiveValuesBean> activeValuesBeanList = new ArrayList<>();

            for (Map.Entry<String, List<String>> item : relationshipTemp.entrySet()) {
                /*
                 * TODO 缓存待定
                 */
                PreVerifyOutputDTO.ActiveValuesBean activeValuesBean = new PreVerifyOutputDTO.ActiveValuesBean();

                activeValuesBean.setCharacteristicName(item.getKey());
                activeValuesBean.setValues(item.getValue());
                activeValuesBeanList.add(activeValuesBean);
            }

            preVerifyOutputDTO.setMessage("");
            preVerifyOutputDTO.setResult(true);
            preVerifyOutputDTO.setActiveValues(activeValuesBeanList);

            redisHelper.set(RedisKey.getSelectedCharacteristicKey(preVerifyInputDTO.getSessionId()),
                    JSON.toJSONString(selectedCharacteristicValueMap), sessionTimeout);
        } else {
            preVerifyOutputDTO.setResult(false);
            preVerifyOutputDTO.setMessage(resultStatus);
            preVerifyOutputDTO.setActiveValues(new ArrayList<>());
        }

        if ("unselect".equals(resultStatus)) {
            preVerifyOutputDTO.setMessage(StringHelper.trimTrailingCharacter("因为限配关系，选择该值后会导致下列特征无可选项:".concat(
                    String.join(",", emptyCharacteristics)).concat(",选择将重置请重新选择!"), ','));

            preVerifyOutputDTO.setConflictingCharacteristicList(emptyCharacteristics);
            preVerifyOutputDTO.setResult(false);
        }

        return preVerifyOutputDTO;
    }

    /**
     * 数量型C做减法
     *
     * @param selectedCharacteristicValueMap      已选的cvlist
     * @param processedVariantTable    vt 验证过的
     * @param totalQuantityMappingPOList 所有allowedTotal 映射关系
     * @param quantityMappingPOList CapacityC&QuantityC的对应关系
     * @param totalCharacteristicList 特征值集合
     * @return 略
     */
    private Map<String, List<String>> procCalcUnSelect(Map<String, String> selectedCharacteristicValueMap,
                                                       Map<String, List<String>> processedVariantTable,
                                                       List<TotalQuantityMappingPO> totalQuantityMappingPOList,
                                                       List<QuantityMappingPO> quantityMappingPOList,
                                                       List<CharacteristicListBean> totalCharacteristicList) {

        //不可选： 特征编号：list<特征值编号>
        Map<String, List<String>> notAvailableCharacteristicValueList = new HashMap<>(16);

        //初始产品下所有数字型特征:特征值编号,特征值数量
        Map<String, Map<String, Integer>> internalTotalCharacteristicList = new HashMap<>(totalCharacteristicList.size());
        for (CharacteristicListBean characteristicListBean : totalCharacteristicList) {
            if (characteristicListBean.getType() == CharacteristicType.Num.getCharacteristicType())
            {
                for(CharacteristicListBean.ValuesBean valuesBean : characteristicListBean.getValues()) {
                    int result = Integer.parseInt(valuesBean.getName());

                    Map<String, Integer> nameValueMap;
                    if (!internalTotalCharacteristicList.containsKey(characteristicListBean.getName())) {
                        nameValueMap = new HashMap<>(16);
                        internalTotalCharacteristicList.put(characteristicListBean.getName(), nameValueMap);
                    } else {
                        nameValueMap = internalTotalCharacteristicList.get(characteristicListBean.getName());
                    }

                    nameValueMap.put(valuesBean.getName(), result);
                }
            }
        }

        List<TotalQuantityMappingPO> selfTotalQuantityMappingList = new ArrayList<>();

        ///取到bomCode所有用到的totalMapping特征值
        for (TotalQuantityMappingPO tempTotalQuantityMapping : totalQuantityMappingPOList) {
            if (processedVariantTable.containsKey(tempTotalQuantityMapping.getQuantityCharacteristicName())) {
                selfTotalQuantityMappingList.add(tempTotalQuantityMapping);
            } else {
                for (QuantityMappingPO quantityMappingPO : quantityMappingPOList) {
                    if (processedVariantTable.containsKey(quantityMappingPO.getPrimaryCharacteristicName())
                            && !selfTotalQuantityMappingList.contains(tempTotalQuantityMapping)
                            && tempTotalQuantityMapping.getQuantityCharacteristicName().equals(quantityMappingPO.getAssociatedCharacteristicName())) {
                        selfTotalQuantityMappingList.add(tempTotalQuantityMapping);
                    }
                }
            }
        }

        ///取到所有allow特征
        List<String> allowDistinctCharacteristicList = selfTotalQuantityMappingList.stream().map(TotalQuantityMappingPO::getAllowedCharacteristicName).distinct().collect(Collectors.toList());

        for (String allowCharacteristic : allowDistinctCharacteristicList) {
            List<TotalQuantityMappingPO> tempSelfTotalQuantityMappingList = selfTotalQuantityMappingList.stream().filter(a ->
                    a.getAllowedCharacteristicName().equals(allowCharacteristic)).collect(Collectors.toList());

            String totalCharacteristicName = tempSelfTotalQuantityMappingList.get(0).getTotalCharacteristicName();

            //不包含TotalC
            if (!internalTotalCharacteristicList.containsKey(totalCharacteristicName)) {
                continue;
            }

            //最大的total值
            int totalValue = Collections.max(internalTotalCharacteristicList.get(totalCharacteristicName).values());

            //vt算出的allowedValue的值
            int allowedValue = totalValue;

            //如果vt没有算出allowed值，则就是用total值
            if (processedVariantTable.containsKey(tempSelfTotalQuantityMappingList.get(0).getAllowedCharacteristicName())
                    && processedVariantTable.get(tempSelfTotalQuantityMappingList.get(0).getAllowedCharacteristicName()).size() > 0) {

                List<CharacteristicListBean> characteristicListBeans = totalCharacteristicList.stream().filter(characteristicListBean ->
                        characteristicListBean.getName().equals(tempSelfTotalQuantityMappingList.get(0).getAllowedCharacteristicName()))
                        .collect(Collectors.toList());

                List<Integer> allowedValueList = new ArrayList<>();
                for(CharacteristicListBean characteristicListBean : characteristicListBeans)
                {
                        allowedValueList = characteristicListBean.getValues().stream().filter(characteristicValue ->
                                processedVariantTable.get(tempSelfTotalQuantityMappingList.get(0).getAllowedCharacteristicName()).contains(
                                        characteristicValue.getName())).collect(Collectors.toList()).stream().map(
                                CharacteristicListBean.ValuesBean::getName).map(Integer::parseInt).collect(Collectors.toList());
                }

                allowedValue = (allowedValueList.size() > 0) ? Collections.max(allowedValueList) : allowedValue;
            }

            //total本身被限制住了，就要去total的和allowTotal的最小值
            if (processedVariantTable.containsKey(tempSelfTotalQuantityMappingList.get(0).getTotalCharacteristicName())
                    && processedVariantTable.get(tempSelfTotalQuantityMappingList.get(0).getTotalCharacteristicName()).size() > 0) {

                List<CharacteristicListBean> characteristicListBeans = totalCharacteristicList.stream().filter(characteristicListBean ->
                        characteristicListBean.getName().equals(tempSelfTotalQuantityMappingList.get(0).getTotalCharacteristicName()))
                        .collect(Collectors.toList());

                List<Integer> totalValues = new ArrayList<>();
                for(CharacteristicListBean characteristicListBean : characteristicListBeans)
                {
                    totalValues.addAll(characteristicListBean.getValues().stream().filter(valuesBean->
                            processedVariantTable.get(tempSelfTotalQuantityMappingList.get(0).getTotalCharacteristicName()).contains(valuesBean.getName())).map(
                                b -> Integer.parseInt(b.getName())
                    ).collect(Collectors.toList()));
                }

                if (totalValues.size() > 0) {
                    totalValues.sort(Collections.reverseOrder());
                    allowedValue = Math.min(totalValues.get(0), allowedValue);
                }
            }

            ///计算出的数量c 加和 的最大的值
            int totalCalc = Math.min(totalValue, allowedValue);

            //计算已经选中的v 的和
            int totalSelect = 0;
            Map<String, Integer> aryVirtualSel = new HashMap<>(tempSelfTotalQuantityMappingList.size());
            for (TotalQuantityMappingPO tempTotalQtyMapp : tempSelfTotalQuantityMappingList) {
                String strQtyChar = tempTotalQtyMapp.getQuantityCharacteristicName();

                //如果已经选中了数量
                if (selectedCharacteristicValueMap.containsKey(tempTotalQtyMapp.getQuantityCharacteristicName())
                        && internalTotalCharacteristicList.containsKey(tempTotalQtyMapp.getQuantityCharacteristicName())
                        && internalTotalCharacteristicList.get(tempTotalQtyMapp.getQuantityCharacteristicName()).containsKey(selectedCharacteristicValueMap.get(tempTotalQtyMapp.getQuantityCharacteristicName()))
                ) {
                    int select = internalTotalCharacteristicList.get(tempTotalQtyMapp.getQuantityCharacteristicName()).get(selectedCharacteristicValueMap.get(tempTotalQtyMapp.getQuantityCharacteristicName()));
                    totalSelect += select;
                }
                //否则取数量可选项的最小值
                else if (processedVariantTable.containsKey(strQtyChar)) {
                    int select = getMinUsableValue(internalTotalCharacteristicList.get(tempTotalQtyMapp.getQuantityCharacteristicName()),
                            processedVariantTable.get(strQtyChar));

                    totalSelect += select;
                    aryVirtualSel.put(tempTotalQtyMapp.getQuantityCharacteristicName(), select);
                }
            }

            for (TotalQuantityMappingPO tempTotalQtyMap : tempSelfTotalQuantityMappingList) {
                Map<String, Integer> internalQuantityCharacteristicValueMap = internalTotalCharacteristicList.get(tempTotalQtyMap.getQuantityCharacteristicName());

                List<String> unusedCharacteristicValueList = new ArrayList<>();

                int currentCValue = 0;

                if (selectedCharacteristicValueMap.containsKey(tempTotalQtyMap.getQuantityCharacteristicName())
                        && internalQuantityCharacteristicValueMap.containsKey(selectedCharacteristicValueMap.get(tempTotalQtyMap.getQuantityCharacteristicName()))
                ) {
                    //如果当前C被选中，记录选中的c的v值 否则是0
                    currentCValue = internalQuantityCharacteristicValueMap.get(selectedCharacteristicValueMap.get(tempTotalQtyMap.getQuantityCharacteristicName()));
                }

                int currentValueMax = totalCalc + currentCValue - totalSelect + aryVirtualSel.getOrDefault(tempTotalQtyMap.getQuantityCharacteristicName(), 0);

                for (String key : internalQuantityCharacteristicValueMap.keySet()) {
                    //如果v的数量大于 剩余v最大数量，且大于currentCValue，则加到结果集里。
                    if (internalQuantityCharacteristicValueMap.get(key) > currentValueMax) {
                        unusedCharacteristicValueList.add(key);
                    }
                }

                if (!notAvailableCharacteristicValueList.containsKey(tempTotalQtyMap.getQuantityCharacteristicName())) {
                    notAvailableCharacteristicValueList.put(tempTotalQtyMap.getQuantityCharacteristicName(), unusedCharacteristicValueList);
                }
            }
        }

        return notAvailableCharacteristicValueList;
    }

    /**
     * @param aryValues  所有值Name的集合
     * @param aryUsableValues 可用值的集合
     * @return 取得数量C中最小的可用值
     */
    private int getMinUsableValue(Map<String, Integer> aryValues, List<String> aryUsableValues) {
        int result = -999999;

        for (Map.Entry<String, Integer> kvp : aryValues.entrySet()) {
            if (aryUsableValues.contains(kvp.getKey())) {
                if (result == -999999 || result > kvp.getValue()) {
                    result = kvp.getValue();
                }
            }
        }

        return result;
    }

    /**
     * find out 既有显示数字型特征，又有隐藏非数字型特征的VT,此部分需要使隐藏特征升级参与到VT判断中来
     *
     * @param variantTableMap      variant table信息集合
     * @param hiddenCharacteristicList 隐藏特征集合
     * @param quantityCharacteristicList 数量特征集合
     * @return 略
     */
    private Map<Integer, Map<String, List<String>>> getUpgradeNonNumericCharacteristic(Map<Integer, Map<Integer, Map<String, List<String>>>> variantTableMap,
                                                                                       List<String> hiddenCharacteristicList,
                                                                                       List<String> quantityCharacteristicList) {
        Map<Integer, Map<String, List<String>>> nonNumericCharacteristicList = new HashMap<>(variantTableMap.size());

        for (Map.Entry<Integer, Map<Integer, Map<String, List<String>>>> entry : variantTableMap.entrySet()) {
            if (entry.getValue().size() > 0) {
                List<String> aryHiddenNonNum = new ArrayList<>();
                List<String> aryNumNonHidden = new ArrayList<>();

                for (String str : entry.getValue().get(1).keySet()) {
                    //隐藏的非数字C
                    if (hiddenCharacteristicList.contains(str) && !quantityCharacteristicList.contains(str)) {
                        aryHiddenNonNum.add(str);
                    } else if (!hiddenCharacteristicList.contains(str) && quantityCharacteristicList.contains(str)) {
                        aryNumNonHidden.add(str);
                    }
                }

                if (aryHiddenNonNum.size() > 0 && aryNumNonHidden.size() > 0) {
                    Map<String, List<String>> aryTmp = new HashMap<>(aryNumNonHidden.size());
                    for (String c : aryNumNonHidden) {
                        aryTmp.put(c, aryHiddenNonNum);
                    }
                    nonNumericCharacteristicList.put(entry.getKey(), aryTmp);
                }
            }
        }

        return nonNumericCharacteristicList;
    }

    /**
     * @param selectedCharacteristicValueMap 选择的CV
     * @param totalCharacteristicList        全部total相关的特征
     * @return 确认是否参与total计算的都选择完了
     */
    private Map<String, Boolean> getTotalCharacteristicSelectionStatus(List<TotalQuantityMappingPO> totalQuantityMappingPOList,
                                                      Map<String, String> selectedCharacteristicValueMap,
                                                      List<String> totalCharacteristicList) {

        Map<String, Boolean> returnTotalQuantityMappingPO = new HashMap<>(totalQuantityMappingPOList.size());

        for (String totalCharacteristicName : totalCharacteristicList) {
            List<TotalQuantityMappingPO> tempTotalQuantityMappingPOList = totalQuantityMappingPOList.stream().filter(totalQuantityMappingPO ->
                    totalQuantityMappingPO.getTotalCharacteristicName().equals(totalCharacteristicName)).collect(Collectors.toList());

            boolean totalSelect = totalQuantityMappingPOList.stream().anyMatch(totalQuantityMappingPO ->
                    totalQuantityMappingPO.getTotalCharacteristicName().equals(totalCharacteristicName) && selectedCharacteristicValueMap.containsKey(totalCharacteristicName));

            for (TotalQuantityMappingPO totalQuantityMappingPO : tempTotalQuantityMappingPOList) {
                String formulaCharacteristic = totalQuantityMappingPO.getQuantityCharacteristicName();

                if (!returnTotalQuantityMappingPO.containsKey(formulaCharacteristic)) {
                    returnTotalQuantityMappingPO.put(formulaCharacteristic, totalSelect);
                }
            }
        }

        return returnTotalQuantityMappingPO;
    }

    /**
     * @return 获取公式计算用到的C值
     */
    private List<String> getFormulaCharacteristic(List<TotalQuantityMappingPO> totalQuantityMappingPOList,
                                                  List<QuantityMappingPO> quantityMappingPOList) {

        List<String> allowCharacteristicList = new ArrayList<>();
        List<String> totalCharacteristicList = new ArrayList<>();
        List<String> allowQuantityCharacteristicList = new ArrayList<>();

        for(TotalQuantityMappingPO totalQuantityMappingPO : totalQuantityMappingPOList)
        {
            allowCharacteristicList.add(totalQuantityMappingPO.getAllowedCharacteristicName());
            totalCharacteristicList.add(totalQuantityMappingPO.getTotalCharacteristicName());
            allowQuantityCharacteristicList.add(totalQuantityMappingPO.getQuantityCharacteristicName());
        }

        List<String> quantityCharacteristicList = quantityMappingPOList.stream().map(QuantityMappingPO::getAssociatedCharacteristicName).collect(Collectors.toList());

        totalCharacteristicList.addAll(allowCharacteristicList);
        totalCharacteristicList.addAll(allowQuantityCharacteristicList);
        totalCharacteristicList.addAll(quantityCharacteristicList);

        return totalCharacteristicList.stream().distinct().collect(Collectors.toList());
    }

    /**
     * Procedure计算total
     * @param characteristicValueName 特征值编码=>特征值名称
     * @param selectedCharacteristicValueMap 已经选中的cv
     * @param numberCharacteristicValueMap 所有的数字型的特征值编号:特征值英文名称
     * @param totalQuantityMappingPOList   totalQuantityMapping集合
     * @return 略
     */
    private TotalQuantityCalcResultPOJO calcTotalQuantityProcedure(String characteristicValueName,
                                                      Map<String, String> numberCharacteristicValueMap,
                                                      Map<String, String> selectedCharacteristicValueMap,
                                                      List<TotalQuantityMappingPO> totalQuantityMappingPOList) {
        String currentCharacteristicName = null;
        String currentTotalCharacteristicName;
        int total = 0;

        // internalNumberCharacteristicValueMap=>key=特征名称，value=特征值名称，即是数量
        Map<String, Integer> internalNumberCharacteristicValueMap = new HashMap<>(numberCharacteristicValueMap.size());
        for (Map.Entry<String, String> entry : numberCharacteristicValueMap.entrySet()) {
            if (!internalNumberCharacteristicValueMap.containsKey(entry.getKey())) {
                internalNumberCharacteristicValueMap.put(entry.getKey(), Integer.parseInt(entry.getValue()));
            }
        }

        if (!selectedCharacteristicValueMap.containsValue(characteristicValueName)) {

            TotalQuantityCalcResultPOJO totalQuantityCalcResultPOJO = new TotalQuantityCalcResultPOJO();
            totalQuantityCalcResultPOJO.setResult(true);
            totalQuantityCalcResultPOJO.setCharacteristicValueList(new ArrayList<>());

            return totalQuantityCalcResultPOJO;
        }

        Optional<Map.Entry<String, String>> entryOptional = selectedCharacteristicValueMap.entrySet().stream()
                .filter(selectedCharacteristicValue -> selectedCharacteristicValue.getValue().equals(characteristicValueName)).findFirst();

        currentCharacteristicName = entryOptional.isPresent() ? entryOptional.get().getKey() : currentCharacteristicName;

        String finalCurrentCharacteristicName = currentCharacteristicName;
        if (totalQuantityMappingPOList.stream().anyMatch(totalQuantityMappingPO ->
                totalQuantityMappingPO.getQuantityCharacteristicName().equals(finalCurrentCharacteristicName))) {

            Optional<TotalQuantityMappingPO> ctoTotalQTYMappingOptional = totalQuantityMappingPOList.stream().filter(totalQuantityMappingPO ->
                    totalQuantityMappingPO.getQuantityCharacteristicName().equals(finalCurrentCharacteristicName)).findFirst();
            TotalQuantityMappingPO totalQuantityMappingPO = ctoTotalQTYMappingOptional.orElse(null);

            if (Objects.isNull(totalQuantityMappingPO)) {
                TotalQuantityCalcResultPOJO totalQuantityCalcResultPOJO = new TotalQuantityCalcResultPOJO();
                totalQuantityCalcResultPOJO.setResult(true);
                totalQuantityCalcResultPOJO.setCharacteristicValueList(new ArrayList<>());

                return totalQuantityCalcResultPOJO;
            }

            currentTotalCharacteristicName = totalQuantityMappingPO.getTotalCharacteristicName();

            List<TotalQuantityMappingPO> suitableTotalQuantityMappings = totalQuantityMappingPOList.stream().filter(tempTotalQuantityMappingPO ->
                    tempTotalQuantityMappingPO.getTotalCharacteristicName().equals(currentTotalCharacteristicName)).collect(Collectors.toList());

            //计算已选数量C的临时total值
            Map<String, Integer> totalCharacteristicValueList = new HashMap<>();
            for (TotalQuantityMappingPO tempTotalQuantityMappingPO : suitableTotalQuantityMappings) {
                if (selectedCharacteristicValueMap.containsKey(tempTotalQuantityMappingPO.getQuantityCharacteristicName())) {
                    if (totalCharacteristicValueList.containsKey(tempTotalQuantityMappingPO.getTotalCharacteristicName())) {
                        totalCharacteristicValueList.put(tempTotalQuantityMappingPO.getTotalCharacteristicName(),
                                Integer.sum(totalCharacteristicValueList.get(tempTotalQuantityMappingPO.getTotalCharacteristicName()),
                                        internalNumberCharacteristicValueMap.get(
                                                tempTotalQuantityMappingPO.getQuantityCharacteristicName().concat("_")
                                                        .concat(selectedCharacteristicValueMap.get(tempTotalQuantityMappingPO.getQuantityCharacteristicName()
                                                                )
                                                        )
                                        )
                                )
                        );
                    } else {
                        totalCharacteristicValueList.put(tempTotalQuantityMappingPO.getTotalCharacteristicName(),
                                internalNumberCharacteristicValueMap.get(tempTotalQuantityMappingPO.getQuantityCharacteristicName().concat("_")
                                        .concat(selectedCharacteristicValueMap.get(tempTotalQuantityMappingPO.getQuantityCharacteristicName()))));
                    }
                }
            }

            //判断是否整套的数量特征都选过了。
            for (TotalQuantityMappingPO tempTotalQuantityMappingPO : suitableTotalQuantityMappings) {
                if (!selectedCharacteristicValueMap.containsKey(tempTotalQuantityMappingPO.getQuantityCharacteristicName())) {

                    TotalQuantityCalcResultPOJO totalQuantityCalcResultPOJO = new TotalQuantityCalcResultPOJO();
                    totalQuantityCalcResultPOJO.setResult(true);
                    totalQuantityCalcResultPOJO.setCharacteristicValueList(new ArrayList<>());
                    totalQuantityCalcResultPOJO.setTotalCharacteristicValueList(totalCharacteristicValueList);
                    totalQuantityCalcResultPOJO.setPartialQuantitySelection(totalCharacteristicValueList.size() > 0);

                    return totalQuantityCalcResultPOJO;
                }
            }

            for (TotalQuantityMappingPO tempTotalQuantityMappingPO : suitableTotalQuantityMappings) {
                if (selectedCharacteristicValueMap.containsKey(tempTotalQuantityMappingPO.getQuantityCharacteristicName())) {
                    total += internalNumberCharacteristicValueMap.get(tempTotalQuantityMappingPO.getQuantityCharacteristicName().concat("_")
                            .concat(selectedCharacteristicValueMap.get(tempTotalQuantityMappingPO.getQuantityCharacteristicName())));
                }
            }

            Integer totalCount = total;

            if (internalNumberCharacteristicValueMap.entrySet().stream().noneMatch(internalNumberCharacteristicValue ->
                    internalNumberCharacteristicValue.getValue().equals(totalCount)
                            && internalNumberCharacteristicValue.getKey().contains(currentTotalCharacteristicName))) {
                //特征值数量超出total 最大值
                TotalQuantityCalcResultPOJO totalQuantityCalcResultPOJO = new TotalQuantityCalcResultPOJO();
                totalQuantityCalcResultPOJO.setResult(true);
                totalQuantityCalcResultPOJO.setCharacteristicValueList(new ArrayList<>());

                return totalQuantityCalcResultPOJO;

            } else {
                Optional<Map.Entry<String, Integer>> optionalEntry = internalNumberCharacteristicValueMap.entrySet().stream().filter(internalNumberCharacteristicValue ->
                        internalNumberCharacteristicValue.getValue().equals(totalCount)
                                && internalNumberCharacteristicValue.getKey().contains(currentTotalCharacteristicName)).findFirst();

                if (!optionalEntry.isPresent()) {
                    TotalQuantityCalcResultPOJO totalQuantityCalcResultPOJO = new TotalQuantityCalcResultPOJO();
                    totalQuantityCalcResultPOJO.setResult(true);
                    totalQuantityCalcResultPOJO.setCharacteristicValueList(new ArrayList<>());

                    return totalQuantityCalcResultPOJO;
                }

                List<String> forceCharacteristicValueList = new ArrayList<>();
                forceCharacteristicValueList.add(currentTotalCharacteristicName + ":" + optionalEntry.get().getKey());

                TotalQuantityCalcResultPOJO totalQuantityCalcResultPOJO = new TotalQuantityCalcResultPOJO();
                totalQuantityCalcResultPOJO.setResult(true);
                totalQuantityCalcResultPOJO.setCharacteristicValueList(new ArrayList<>());
                totalQuantityCalcResultPOJO.setForceCharacteristicValueList(forceCharacteristicValueList);

                return totalQuantityCalcResultPOJO;
            }
        }

        TotalQuantityCalcResultPOJO totalQuantityCalcResultPOJO = new TotalQuantityCalcResultPOJO();
        totalQuantityCalcResultPOJO.setResult(true);
        totalQuantityCalcResultPOJO.setCharacteristicValueList(new ArrayList<>());

        return totalQuantityCalcResultPOJO;
    }


    /**
     * 获取从属的特征，从属的特征在OD检验中会特别处理
     * @param variantTableDOMap OD集合
     * @param numberCharacteristicList  数量型特征的集合
     * @param totalQuantityMappingPOList    total数量型mapping集合
     * @param numberHiddenCharacteristicList    隐藏的数量型特征集合
     * @return 从属的特征集合
     */
    List<String> getFollowCharacteristicList(Map<Integer, VariantTableDO> variantTableDOMap,
                                             List<String> numberCharacteristicList,
                                             List<TotalQuantityMappingPO> totalQuantityMappingPOList,
                                             List<String> numberHiddenCharacteristicList) {
        List<String> followCharacteristicList = new ArrayList<>(0);
        List<String> totalQuantityCharacteristicList = totalQuantityMappingPOList.stream()
                .map(TotalQuantityMappingPO::getTotalCharacteristicName).collect(Collectors.toList());

        numberCharacteristicList.removeAll(totalQuantityCharacteristicList);
        numberHiddenCharacteristicList.removeAll(totalQuantityCharacteristicList);

        if (null != variantTableDOMap && variantTableDOMap.size() > 0) {
            for(Map.Entry<Integer, VariantTableDO> variantTableDOEntry : variantTableDOMap.entrySet())
            {
                List<String> constraintCharacteristicNameList = variantTableDOEntry.getValue().getConstraintCharacteristicName()
                        .stream().filter(constraintCharacteristic ->
                                numberCharacteristicList.contains(constraintCharacteristic)).collect(Collectors.toList());

                followCharacteristicList.removeAll(constraintCharacteristicNameList);
                followCharacteristicList.addAll(constraintCharacteristicNameList);
            }

            followCharacteristicList.removeAll(numberHiddenCharacteristicList);
            followCharacteristicList.addAll(numberHiddenCharacteristicList);
        }

        return followCharacteristicList;
    }

    /**
     * @param ctoTotalQTYMappings 汇总数量特征Mapping
     * @param ctoQtyCharMappings  数量特征Mapping
     * @return 非现实数量特征
     */
    private static List<String> getHiddenNumberCharacteristic(List<TotalQuantityMappingPO> ctoTotalQTYMappings, List<QuantityMappingPO> ctoQtyCharMappings) {

        List<String> allowCharacteristicList = ctoTotalQTYMappings.stream().map(TotalQuantityMappingPO::getAllowedCharacteristicName).collect(Collectors.toList());
        List<String> totalCharacteristicList = ctoTotalQTYMappings.stream().map(TotalQuantityMappingPO::getTotalCharacteristicName).collect(Collectors.toList());
        List<String> allowCharacteristicNumberList = ctoTotalQTYMappings.stream().map(TotalQuantityMappingPO::getQuantityCharacteristicName).collect(Collectors.toList());
        List<String> numberCharacteristicList = ctoQtyCharMappings.stream().map(QuantityMappingPO::getAssociatedCharacteristicName).collect(Collectors.toList());

        totalCharacteristicList.addAll(allowCharacteristicList);
        totalCharacteristicList.addAll(allowCharacteristicNumberList);
        totalCharacteristicList.removeAll(numberCharacteristicList);

        return totalCharacteristicList.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 获取Variant table 约束信息
     * @param system 系统
     * @param productGroupCode 产品组
     * @param materialCode 物料编号
     * @return Variant Table信息
     */
    public Map<Integer, VariantTableDO> getVariantTable(String system,
                                                        String productGroupCode,
                                                        String materialCode) {

        Map<Integer, VariantTableDO> variantTableDOMap = new HashMap<>();

        List<VariantTablePO> variantTablePOList = selectorCacheService.getVariantTable(system,
                productGroupCode, materialCode);

        if (Objects.isNull(variantTablePOList))
        {
            return null;
        }

        for(VariantTablePO variantTablePO : variantTablePOList) {
            VariantTableDO variantTableDO = new VariantTableDO();

            variantTableDO.setVariantTableId(variantTablePO.getTableId());
            variantTableDO.setConstraintCharacteristicName(variantTablePO.getData().getConstraintCharacteristicName());

            Map<Integer, Map<String, List<String>>> constraintCharacteristicValuesMap = new HashMap<>();

            for(VariantTablePO.DataBean.ConstraintCharacteristicValuesBean constraintCharacteristicValuesBean
                    : variantTablePO.getData().getConstraintCharacteristicValues())
            {
                Map<String, List<String>> characteristicValuesMap = new HashMap<>();

                for(VariantTablePO.DataBean.ConstraintCharacteristicValuesBean.CharacteristicValuesBean characteristicValuesBean
                        : constraintCharacteristicValuesBean.getCharacteristicValues())
                {
                    characteristicValuesMap.put(characteristicValuesBean.getCharacteristicName(), characteristicValuesBean.getValues());
                }

                constraintCharacteristicValuesMap.put(Integer.parseInt(constraintCharacteristicValuesBean.getGroupNumber()),
                        characteristicValuesMap);
            }


            variantTableDO.setConstraintCharacteristicValues(constraintCharacteristicValuesMap);

            variantTableDOMap.put(variantTablePO.getTableId(), variantTableDO);
        }

        return variantTableDOMap;
    }

    private InitializeResultDO selectorFilter(Map<String, String> selectedCharacteristicValues,
                                              Map<String, List<String>> totalCharacteristicList,
                                              Map<Integer, Map<Integer, Map<String, List<String>>>> variantTableMap,
                                              Map<Integer, List<Integer>> invalidGroupMap,
                                              boolean complexMaterial,
                                              List<String> formulaCharacteristicList,
                                              List<String> sumOfQuantitiesCharacteristicList,
                                              Map<String, String> quantityCharacteristicMap,
                                              List<String> hiddenCharacteristicList,
                                              boolean allSelected,
                                              boolean withDerive,
                                              List<String> needCheckCharacteristicList,
                                              Map<String, Boolean> totalCharacteristicSelectionResultMap,
                                              List<String> followHiddenCharacteristicList,
                                              Map<String, List<String>> hiddenSpecialMap,
                                              Map<Integer, Map<String, List<String>>> upgradedNonNumberVariantTableMap) {
        Map<String, List<String>> relationship;

        InitializeResultDO initializeResultDO = new InitializeResultDO();

        //主键是变式表名
        initializeResultDO.setVariantTableGroupMap(new HashMap<>());
        initializeResultDO.setInvalidGroupMap(new HashMap<>(invalidGroupMap));

        if (null != variantTableMap && variantTableMap.size() > 0) {
            boolean isValid;

            for (int i = 1; i <= variantTableMap.size(); i++) {
                Map<Integer, Map<String, List<String>>> variantTableGroup = variantTableMap.get(i);

                Map<String, Boolean> conditionMap = new HashMap<>();

                if (variantTableGroup.size() > 0) {
                    for (String key : variantTableGroup.get(1).keySet()) {
                        if (!initializeResultDO.getVariantTableGroupMap().containsKey(i)) {
                            relationship = new HashMap<>();
                            relationship.put(key, new ArrayList<>());

                            initializeResultDO.getVariantTableGroupMap().put(i, relationship);
                        } else if (!initializeResultDO.getVariantTableGroupMap().get(i).containsKey(key)) {
                            initializeResultDO.getVariantTableGroupMap().get(i).put(key, new ArrayList<>());
                        }
                    }

                    for (Map.Entry<String, List<String>> kvp1 : variantTableGroup.get(1).entrySet()) {
                        conditionMap.put(kvp1.getKey(),
                                (complexMaterial && hiddenCharacteristicList.contains(kvp1.getKey())
                                        && formulaCharacteristicList.contains(kvp1.getKey())
                                        && !sumOfQuantitiesCharacteristicList.contains(kvp1.getKey())
                                        && totalCharacteristicSelectionResultMap.containsKey(kvp1.getKey())
                                        && !totalCharacteristicSelectionResultMap.get(kvp1.getKey())));
                    }
                }

                for (int j = 1; j <= variantTableGroup.size(); j++) {
                    Map<String, List<String>> singleVariantTableMap = variantTableGroup.get(j);

                    //假如这个variantTable都不需要检查就直接跳出循环
                    if (StringHelper.intersect(singleVariantTableMap.keySet(), needCheckCharacteristicList).size() <= 0) {
                        break;
                    }

                    //去除无效的variantTable组
                    for (Map.Entry<String, List<String>> entry : singleVariantTableMap.entrySet()) {
                        //
                        isValid = true;

                        for (Map.Entry<String, List<String>> kvp1 : singleVariantTableMap.entrySet()) {
                            boolean condition1 = kvp1.getKey().equals(entry.getKey());
                            boolean condition2 = !withDerive
                                    && !allSelected && hiddenCharacteristicList.contains(kvp1.getKey())
                                    && isHiddenCharacteristicUpgrade(
                                        hiddenSpecialMap,
                                        selectedCharacteristicValues,
                                        kvp1.getKey(),
                                        entry.getKey(),
                                        upgradedNonNumberVariantTableMap,
                                        i,
                                        hiddenCharacteristicList,
                                        quantityCharacteristicMap)
                                    && (!complexMaterial || !formulaCharacteristicList.contains(kvp1.getKey()));
                            boolean condition3 = conditionMap.get(kvp1.getKey());
                            boolean condition4 = selectedCharacteristicValues.containsKey(kvp1.getKey()) && !followHiddenCharacteristicList.contains(kvp1.getKey());
                            boolean condition5 = !selectedCharacteristicValues.containsKey(entry.getKey())
                                    && (kvp1.getValue().size() > 0 && !kvp1.getValue().get(0).equals(variantTableEmptyGroupPlaceholderValue))
                                    && !checkExistOrNot(kvp1.getValue(), totalCharacteristicList.get(kvp1.getKey()));

                            if(!condition1 && !condition2 && !condition3)
                            {
                                if(condition4)
                                {
                                    if (!kvp1.getValue().contains(selectedCharacteristicValues.get(kvp1.getKey()))
                                            && (kvp1.getValue().size() == 0 || !kvp1.getValue().get(0).equals(variantTableEmptyGroupPlaceholderValue))
                                    ) {
                                        isValid = false;
                                        break;
                                    }
                                }
                                else if(condition5)
                                {
                                    isValid = false;
                                    break;
                                }
                            }
                        }

                        //无效组继续
                        if (!isValid) {
                            if (initializeResultDO.getInvalidGroupMap().containsKey(i)) {
                                initializeResultDO.getInvalidGroupMap().get(i).add(j);
                            } else {
                                List<Integer> invalidList = new ArrayList<>();
                                invalidList.add(j);
                                initializeResultDO.getInvalidGroupMap().put(i, invalidList);
                            }

                            break;
                        }

                        List<String> tempCharacteristicValues;
                        tempCharacteristicValues = new ArrayList<>(entry.getValue());
                        {
                            //同一个变式表取并集
                            initializeResultDO.getVariantTableGroupMap().get(i).put(entry.getKey(),
                                    CastHelper.cast(StringHelper.union(initializeResultDO.getVariantTableGroupMap().get(i).get(entry.getKey()), tempCharacteristicValues)));
                        }
                    }
                }

                Map<String, List<String>> singleVariantTableMap = new HashMap<>();

                //处理无效variantTable
                if (initializeResultDO.getVariantTableGroupMap() != null && initializeResultDO.getVariantTableGroupMap().containsKey(i))
                {
                    for (Map.Entry<String, List<String>> entry : initializeResultDO.getVariantTableGroupMap().get(i).entrySet()) {
                        if (entry.getValue().size() > 0) {
                            singleVariantTableMap.put(entry.getKey(), new ArrayList<>(entry.getValue()));
                        }
                    }

                    initializeResultDO.getVariantTableGroupMap().remove(i);
                    initializeResultDO.getVariantTableGroupMap().put(i, singleVariantTableMap);
                }
            }
        }

        return initializeResultDO;
    }

    /**
     * 检查是否有交集
     * @param searchList 要查询的list
     * @param totalList 全部的值list
     * @return 结果
     */
    private static boolean checkExistOrNot(List<String> searchList, List<String> totalList) {
        boolean ret = true;

        for (String v : searchList) {
            if (totalList.contains(v)) {
                ret = false;
                break;
            }
        }

        return !ret;
    }

    /**
     * 既有显示数字型特征，又有隐藏非数字型特征的variantTable,此部分需要使隐藏特征升级参与到variantTable判断
     * @param hiddenSpecialMap 隐藏的特殊的数字型特征集合
     * @param selectedCharacteristicValues  选中的特征值
     * @param characteristicName    特征名称
     * @param currentCharacteristicName 当前的特征名称
     * @param upgradedNonNumberVariantTableMap  非数量型C的variant table集合
     * @param i 索引
     * @param hiddenCharacteristicList 隐藏的特征集合
     * @param quantityCharacteristicMap 数量特征集合
     * @return true or false
     */
    private static boolean isHiddenCharacteristicUpgrade(
                                           Map<String, List<String>> hiddenSpecialMap,
                                           Map<String, String> selectedCharacteristicValues,
                                           String characteristicName,
                                           String currentCharacteristicName,
                                           Map<Integer, Map<String, List<String>>> upgradedNonNumberVariantTableMap,
                                           int i,
                                           List<String> hiddenCharacteristicList,
                                           Map<String, String> quantityCharacteristicMap) {
        boolean ret = false;

        if (hiddenSpecialMap.containsKey(characteristicName)) {
            for (String str : hiddenSpecialMap.get(characteristicName)) {
                if (str.equals(currentCharacteristicName) || selectedCharacteristicValues.containsKey(str)) {
                    ret = true;
                    break;
                }
            }
        }

        if (!hiddenCharacteristicList.contains(currentCharacteristicName) && selectedCharacteristicValues.containsKey(currentCharacteristicName)) {
            ret = true;
        }
        //既有显示数字型特征，又有隐藏非数字型特征的variantTable,此部分需要使隐藏特征升级参与到variantTable判断
        else if (quantityCharacteristicMap.containsKey(currentCharacteristicName)
                && selectedCharacteristicValues.containsKey(quantityCharacteristicMap.get(currentCharacteristicName))
                && upgradedNonNumberVariantTableMap.containsKey(i)
                && upgradedNonNumberVariantTableMap.get(i).containsKey(currentCharacteristicName)
                && upgradedNonNumberVariantTableMap.get(i).get(currentCharacteristicName).contains(currentCharacteristicName)) {
            ret = true;
        }

        return !ret;
    }

    /**
     * 构造variant table 简化结构
     * @param variantTableDOMap variant table 缓存中的结构
     * @param totalVariantTableMap variant table 简化结构
     */
    public void buildVariantTableStructure(Map<Integer, VariantTableDO> variantTableDOMap,
                                            Map<Integer, Map<Integer, Map<String, List<String>>>> totalVariantTableMap)
    {
        if (null != variantTableDOMap && variantTableDOMap.size() > 0) {
            int variantTableId = 1;
            int groupNumber;

            //variantTable表遍历
            for (Map.Entry<Integer, VariantTableDO> variantTableDOEntry : variantTableDOMap.entrySet()) {
                groupNumber = 1;
                Map<Integer, Map<String, List<String>>> variantTableGroupMap = new HashMap<>(variantTableDOEntry.getValue().getConstraintCharacteristicValues().size());

                //某一VT行遍历
                for (Map.Entry<Integer, Map<String, List<String>>> constraintCharacteristicValues : variantTableDOEntry.getValue().getConstraintCharacteristicValues().entrySet()) {

                    Map<String, List<String>> singleVariantTableMap = new HashMap<>(variantTableDOEntry.getValue().getConstraintCharacteristicName().size());

                    //某一VT列遍历
                    for (String characteristicName : variantTableDOEntry.getValue().getConstraintCharacteristicName()) {
                        List<String> characteristicValues = new ArrayList<>();
                        for (String characteristicValueName : constraintCharacteristicValues.getValue().get(characteristicName)) {
                            characteristicValues.add(characteristicValueName);
                        }
                        singleVariantTableMap.put(characteristicName, characteristicValues);
                    }

                    variantTableGroupMap.put(groupNumber, singleVariantTableMap);
                    groupNumber++;
                }

                totalVariantTableMap.put(variantTableId, variantTableGroupMap);
                variantTableId++;
            }
        }
    }

    /**
     * 返回某BOM对应的所有variant table中包含的特征
     * @param variantTableDOMap 所有的variant table
     * @return 所有variant table中包含的特征
     */
    static List<String> getAllCharacteristic(Map<Integer, VariantTableDO> variantTableDOMap) {
        List<String> characteristicNames = new ArrayList<>();

        if (variantTableDOMap != null) {
            for (Map.Entry<Integer, VariantTableDO> kvp : variantTableDOMap.entrySet()) {
                for (String characteristicName : kvp.getValue().getConstraintCharacteristicName()) {
                    if (!characteristicNames.contains(characteristicName)) {
                        characteristicNames.add(characteristicName);
                    }
                }
            }
        }

        return characteristicNames;
    }

    /**
     * 检查是否CTO的可见部分都已经选择
     * @param selectedCharacteristicValueMap 所有当前选中的
     * @param variantTableCharacteristicList 物料所有参与VT的特征
     * @param hiddenCharacteristicList 隐藏的特征集合
     * @return true or false
     */
    static Boolean checkAllSelected(Map<String, String> selectedCharacteristicValueMap,
                                    List<String> variantTableCharacteristicList,
                                    List<String> hiddenCharacteristicList) {
        boolean ret = true;

        for (String characteristicName : variantTableCharacteristicList) {
            //隐藏的C不算
            if (hiddenCharacteristicList.contains(characteristicName)) {
                continue;
            }

            //有一个没有选中就立刻返回
            if (!selectedCharacteristicValueMap.containsKey(characteristicName)) {
                ret = false;
                break;
            }
        }

        return ret;
    }

    /**
     * 检查返回的结果集是否包含页面已选中的特征值
     * @param characteristicValuesMap 特征值和特征对应的map
     * @param selectedCharacteristicValuesMap 选中的特征值
     * @param hiddenCharacteristicList 隐藏的特征
     * @return true or false
     */
    static boolean checkConflict(Map<String, List<String>> characteristicValuesMap,
                                 Map<String, String> selectedCharacteristicValuesMap,
                                 List<String> hiddenCharacteristicList) {
        boolean ret = true;

        for (Map.Entry<String, List<String>> entry : characteristicValuesMap.entrySet()) {
            if (selectedCharacteristicValuesMap.containsKey(entry.getKey())) {
                if (hiddenCharacteristicList.contains(entry.getKey())) {
                    continue;
                }
                if (!entry.getValue().contains(selectedCharacteristicValuesMap.get(entry.getKey()))) {
                    ret = false;
                    break;
                }
            }
        }

        return !ret;
    }

    /**
     * 后置验证variant table
     *
     * @param materialCode  物料编号
     * @param productGroupCode 产品组
     * @param selectedCharacteristicValueMap    特征值对集合
     * @return 有问题的特征集合
     */
    public List<String> verifyVariantTable(String materialCode,
                                            String productGroupCode,
                                            HashMap<String, String> selectedCharacteristicValueMap
    ){
        List<String> characteristicList = new ArrayList<>();

        List<VariantTablePO> variantTablePOList = selectorCacheService.getVariantTable(system,
                productGroupCode, materialCode);

        if (Objects.isNull(variantTablePOList))
        {
            return null;
        }

        String characteristicValueName;

        for(VariantTablePO variantTablePO : variantTablePOList)
        {
            boolean find = true;

            for (VariantTablePO.DataBean.ConstraintCharacteristicValuesBean constraintCharacteristicValuesBean
                 : variantTablePO.getData().getConstraintCharacteristicValues()
            ) {
                find = true;

                for (VariantTablePO.DataBean.ConstraintCharacteristicValuesBean.CharacteristicValuesBean characteristicValuesBean
                        : constraintCharacteristicValuesBean.getCharacteristicValues()
                ) {
                    characteristicValueName = selectedCharacteristicValueMap.get(characteristicValuesBean.getCharacteristicName());

                    if (StringUtils.isNotBlank(characteristicValueName) && !characteristicValuesBean.getValues().contains(characteristicValueName)) {
                        find = false;
                    }
                }

                if (find) {
                    break;
                }
            }

            if (!find) {
                for (String characteristicName : variantTablePO.getData().getConstraintCharacteristicName()) {
                    if (!characteristicList.contains(characteristicName)) {
                        characteristicList.add(characteristicName);
                    }
                }
            }
        }

        //todo 数量型C的验证，各子项的和要保证和total的数相等

        return characteristicList;
    }

    /**
     * 初始冲突分析
     * @param characteristicName 特征名称
     * @param selectedCharacteristicMap 已选特征值
     * @param variantTableDOMap variant table
     * @return 有问题的variant table
     */
    public Map<Integer, Map<String, List<String>>> initialConflictAnalysis(
            String characteristicName,
            Map<String, String> selectedCharacteristicMap,
            Map<Integer, VariantTableDO> variantTableDOMap) {

        Map<Integer, Map<String, List<String>>> resultMap = new HashMap<>(variantTableDOMap.size());

        if (variantTableDOMap.size() > 0) {
            {
                int index = 0;

                for (Map.Entry<Integer, VariantTableDO> variantTableDOEntry : variantTableDOMap.entrySet()
                ) {
                    if (variantTableDOEntry.getValue().getConstraintCharacteristicName().contains(characteristicName)) {
                        List<String> characteristicNameList = CastHelper.cast(StringHelper.intersect(selectedCharacteristicMap.keySet(),
                                CastHelper.cast(variantTableDOEntry.getValue().getConstraintCharacteristicName())));

                        boolean validVariantTable = false;

                        //variantTable表需要验证
                        if (characteristicNameList.size() > 0) {
                            for (Map.Entry<Integer, Map<String, List<String>>> entry : variantTableDOEntry.getValue().getConstraintCharacteristicValues().entrySet()
                            ) {
                                boolean invalidGroup = false;
                                for (String loopCharacteristicName : characteristicNameList
                                ) {
                                    //假如不匹配已选中的特征值，直接下一行
                                    if (!entry.getValue().get(loopCharacteristicName).contains(selectedCharacteristicMap.get(loopCharacteristicName))) {
                                        invalidGroup = true;
                                        break;
                                    }
                                }

                                //找到一行就不用再继续找了
                                if (!invalidGroup) {
                                    validVariantTable = true;
                                    break;
                                }
                            }
                        }

                        if (!validVariantTable) {
                            index += 1;

                            Map<String, List<String>> aryItem = new HashMap<>(variantTableDOEntry.getValue().getConstraintCharacteristicName().size());

                            for (String loopCharacteristicName : variantTableDOEntry.getValue().getConstraintCharacteristicName()) {
                                if (!loopCharacteristicName.equals(characteristicName)) {
                                    //当前与选中项冲突
                                    if (selectedCharacteristicMap.containsKey(loopCharacteristicName)) {
                                        aryItem.put(loopCharacteristicName, new ArrayList<String>() {{
                                            add(selectedCharacteristicMap.get(loopCharacteristicName));
                                        }});
                                    } else {
                                        //不存在选中项集合
                                        aryItem.put(loopCharacteristicName, new ArrayList<String>() {{
                                            add("");
                                        }});
                                    }
                                }
                            }

                            resultMap.put(index, aryItem);
                        }
                    }
                }

            }
        }

        return resultMap;
    }

    /**
     * 深度分析variant table冲突
     * @param variantTableDOMap variant table
     * @param resultMap 有问题的variant table
     * @param characteristicName 特征名称
     * @param characteristicValueName 特征值名称
     * @param selectedCharacteristicMap 已选特征值
     * @param conflictCharacteristicList 有问题的特征集合
     * @return 有问题的特征
     */
    public List<String> deepConflictAnalysis(Map<Integer, VariantTableDO> variantTableDOMap,
                                          Map<Integer, Map<String, List<String>>> resultMap,
                                          String characteristicName,
                                          String characteristicValueName,
                                          Map<String, String> selectedCharacteristicMap,
                                          List<String> conflictCharacteristicList
    ) {

        List<String> deepConflictCharacteristic = new ArrayList<>();
        Map<String, List<String>> conflictCharacteristicValues = new HashMap<>();

        if (variantTableDOMap.size() > 0) {
            for (Map.Entry<Integer, VariantTableDO> variantTableDOEntry : variantTableDOMap.entrySet()) {
                //variant table包含排除的特征
                List<String> localConflictCharacteristicList = CastHelper.cast(StringHelper.intersect(conflictCharacteristicList,
                        CastHelper.cast(variantTableDOEntry.getValue().getConstraintCharacteristicName())));

                if (variantTableDOEntry.getValue().getConstraintCharacteristicName().contains(characteristicName)
                        && localConflictCharacteristicList.size() > 0) {
                    for (Map.Entry<Integer, Map<String, List<String>>> constraintCharacteristicValuesEntry : variantTableDOEntry.getValue().getConstraintCharacteristicValues().entrySet()) {
                        if (constraintCharacteristicValuesEntry.getValue().get(characteristicName).contains(characteristicValueName)) {
                            for (String conflictCharacteristicName : localConflictCharacteristicList) {
                                if (conflictCharacteristicValues.containsKey(conflictCharacteristicName)) {
                                    conflictCharacteristicValues.get(conflictCharacteristicName).removeAll(constraintCharacteristicValuesEntry.getValue().get(conflictCharacteristicName));
                                    conflictCharacteristicValues.get(conflictCharacteristicName).addAll(constraintCharacteristicValuesEntry.getValue().get(conflictCharacteristicName));
                                } else {
                                    conflictCharacteristicValues.put(conflictCharacteristicName, constraintCharacteristicValuesEntry.getValue().get(conflictCharacteristicName));
                                }
                            }
                        }
                    }
                }
            }

            //遍历深度排除
            for (Map.Entry<Integer, VariantTableDO> variantTableDOEntry : variantTableDOMap.entrySet()) {
                //根据已选特征取出所有有效的VT表
                List<String> localCharacteristicList = CastHelper.cast(StringHelper.intersect(selectedCharacteristicMap.keySet(),
                        CastHelper.cast(variantTableDOEntry.getValue().getConstraintCharacteristicName())));
                //排除的特征所在的VT表
                List<String> localConflictCharacteristicList = CastHelper.cast(StringHelper.intersect(conflictCharacteristicList,
                        CastHelper.cast(variantTableDOEntry.getValue().getConstraintCharacteristicName())));
                localCharacteristicList.removeAll(localConflictCharacteristicList);

                //要排除当前强选的特征,并且包含排除的特征所在的VT表
                if (!localCharacteristicList.contains(characteristicName) && localConflictCharacteristicList.size() > 0) {
                    boolean invalidGroup = false;
                    boolean isValidVariantTable = false;

                    for (Map.Entry<Integer, Map<String, List<String>>> constraintCharacteristicValuesEntry : variantTableDOEntry.getValue().getConstraintCharacteristicValues().entrySet()) {
                        for (Map.Entry<String, List<String>> conflictCharacteristicValuesEntry : conflictCharacteristicValues.entrySet()) {
                            if (localConflictCharacteristicList.contains(conflictCharacteristicValuesEntry.getKey())) {
                                if (StringHelper.intersect(constraintCharacteristicValuesEntry.getValue().get(
                                        conflictCharacteristicValuesEntry.getKey()), conflictCharacteristicValuesEntry.getValue()).size() == 0) {
                                    invalidGroup = true;
                                    break;
                                }
                            }
                        }

                        //所有的排除行都满足了
                        if (!invalidGroup) {
                            for (String loopCharacteristicName : localCharacteristicList
                            ) {
                                //假如不匹配已选中的特征值，直接下一行
                                if (!constraintCharacteristicValuesEntry.getValue().get(loopCharacteristicName).contains(selectedCharacteristicMap.get(loopCharacteristicName))) {
                                    invalidGroup = true;
                                    break;
                                }
                            }

                            //和其他已选特征都吻合，就不用遍历了
                            if (!invalidGroup) {
                                isValidVariantTable = true;
                                break;
                            }
                        }

                        invalidGroup = false;
                    }

                    if (!isValidVariantTable) {
                        deepConflictCharacteristic.removeAll(localCharacteristicList);
                        deepConflictCharacteristic.addAll(localCharacteristicList);
                    }
                }
            }
        }

        return deepConflictCharacteristic;
    }

    /**
     * 深度的间接variant table的验证
     * @param variantTableDOMap variant table 集合
     * @param conflictingCharacteristicList 冲突的特征集合
     * @param depth 深度层级
     * @return 新的冲突特征集合
     */
    public List<String> deepIndirectConflictAnalysis(Map<Integer, VariantTableDO> variantTableDOMap,
                                                   List<String> conflictingCharacteristicList,
                                                   int depth
    ) {

        List<String> deepConflictCharacteristics = new ArrayList<>();

        if (variantTableDOMap.size() > 0 && null!=conflictingCharacteristicList) {
            for (Map.Entry<Integer, VariantTableDO> variantTableDOEntry : variantTableDOMap.entrySet()) {
                for(String conflictingCharacteristic : conflictingCharacteristicList)
                {
                    if(variantTableDOEntry.getValue().getConstraintCharacteristicName().contains(conflictingCharacteristic))
                    {
                        deepConflictCharacteristics.addAll(variantTableDOEntry.getValue().getConstraintCharacteristicName());
                        if(depth>0) {
                            List<String> tempDeepConflictCharacteristics = deepIndirectConflictAnalysis(variantTableDOMap, variantTableDOEntry.getValue().getConstraintCharacteristicName(), depth - 1);
                            deepConflictCharacteristics.removeAll(tempDeepConflictCharacteristics);
                            deepConflictCharacteristics.addAll(tempDeepConflictCharacteristics);
                        }
                    }
                }
            }
        }

        return deepConflictCharacteristics;
    }

    /**
     * 假如强选中前置验证返回了空的特征集合，则要移除相关的variant table中的关联特征，以及pair数字特征的全部特征，此功能待加强。
     * 2020-08-16 临时方案
     * @param selectedCharacteristicList 已选特征
     * @param activeValues 可用特征值集合
     * @param dataSourceFlag 数据源
     */
    /*private void removeRelationCharacteristicByEmptyActiveCharacteristic(
            String token, String bomCode, String division,
            List<PreValidationInputV2DTO.SelectedCharacteristicBean> selectedCharacteristicList,
            List<BomInitializeOutputV2DTO.CharacteristicValuesBean> activeValues,
            String dataSourceFlag
    )
    {
        //获取VT全集
        Map<Integer, ODData> aryData = odService.getVariantTable(token, bomCode, division, 1, null, dataSourceFlag);
        //获取数字Pair全集
        List<CTOQTYCMapping> ctoQtyCharacteristicMappingList = configuratorCacheService.getCTOQTYCMapping(dataSourceFlag);

        for(BomInitializeOutputV2DTO.CharacteristicValuesBean characteristicValuesBean: activeValues)
        {
            //特征下没有可用特征值
            if(characteristicValuesBean.getValues().size() == 0)
            {
                for(Map.Entry<Integer, ODData> kvp : aryData.entrySet())
                {
                    if(kvp.getValue().getAryChar().contains(characteristicValuesBean.getCharacteristicCode()))
                    {
                        selectedCharacteristicList.removeIf(i->kvp.getValue().getAryChar().contains(i.getCharacteristicCode()));

                        //清除数量Pair关系特征
                        for(CTOQTYCMapping ctoqtycMapping : ctoQtyCharacteristicMappingList)
                        {
                            if(kvp.getValue().getAryChar().contains(ctoqtycMapping.getR3Code()))
                            {
                                selectedCharacteristicList.removeIf(i->i.getCharacteristicCode().equals(ctoqtycMapping.getQtyR3Code()));
                            }
                            if(kvp.getValue().getAryChar().contains(ctoqtycMapping.getQtyR3Code()))
                            {
                                selectedCharacteristicList.removeIf(i->i.getCharacteristicCode().equals(ctoqtycMapping.getR3Code()));
                            }
                        }
                    }
                }
            }
        }
    }*/
}
