package com.quantgroup.asset.distribution.service.funding.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.quantgroup.asset.distribution.enums.RuleOperator;
import com.quantgroup.asset.distribution.enums.UnionType;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.model.entity.fund.ChannelFundConfigNew;
import com.quantgroup.asset.distribution.model.entity.fund.FundConfigCondition;
import com.quantgroup.asset.distribution.model.entity.fund.FundConfigSimulationVO;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigNewService;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.rule.IRuleService;
import com.quantgroup.asset.distribution.service.rule.vo.BaseRuleVO;
import com.quantgroup.asset.distribution.service.rule.vo.IRuleVO;
import com.quantgroup.asset.distribution.service.rule.vo.UnionRuleVO;
import org.apache.commons.collections.Bag;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.bag.HashBag;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Stopwatch;
import com.quantgroup.asset.distribution.config.annotation.HandleException;
import com.quantgroup.asset.distribution.constant.FundModuleConstants;
import com.quantgroup.asset.distribution.enums.funding.AuditStatusEnum;
import com.quantgroup.asset.distribution.enums.response.FundModuleResponse;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions;
import com.quantgroup.asset.distribution.model.entity.fund.FundInfo;
import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import com.quantgroup.asset.distribution.service.approval.IApprovalLogService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleLimitTypeService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleService;
import com.quantgroup.asset.distribution.service.httpclient.IHttpService;
import com.quantgroup.asset.distribution.service.jpa.entity.ApprovalLog;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfig;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleLimitTypeConfig;

import lombok.extern.slf4j.Slf4j;

/**
 * 资方模块Service
 * @author liwenbin
 *
 */
@Service
@Slf4j
public class FundModuleServiceImpl implements IFundModuleService{
	
	@Autowired
	private IHttpService httpService;
	@Autowired
	private IFundModuleLimitTypeService fundModuleLimitTypeService;
	@Autowired
	private IFundModuleChannelFundConfigService fundModuleChannelFundConfigService;
	@Autowired
	private IFundModuleChannelFundConfigNewService fundModuleChannelFundConfigNewService;
	@Autowired
	private IApprovalLogService approvalLogService;
	@Autowired
	private IRuleService ruleService;
	@Value("${clotho.url}")  
	private String clothoURL;
	@Value("${mo-config.url}")
	private String moConfigURL;

	@HandleException
	@Override
	public GlobalResponse getAllFundsInfo() {
		Stopwatch stopwatch = Stopwatch.createStarted();
		String text = httpService.get(clothoURL + "/ex/funding/corp/all.json");
		log.info("拉取xyqb所有资方信息完成, 耗时 : {}, 结果 : {}", stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), text);
		QGPreconditions.checkArgument(StringUtils.isNotEmpty(text), QGExceptionType.GET_ALL_FUNDS_INFO_ERROR, text);
		JSONObject data = JSONObject.parseObject(text);
		QGPreconditions.checkArgument(data != null && "0000".equals(data.getString("code")), QGExceptionType.GET_ALL_FUNDS_INFO_ERROR, text);
		// 将xyqb返回的结果转化成返回结果
		List<FundInfo> fundInfoList = new ArrayList<>();
		JSONArray fundsArray = data.getJSONArray("data");
		for (int i = 0, len = fundsArray.size(); i < len; ++i) {
			FundInfo fundInfo = new FundInfo();
			JSONObject fundInfoJSON = fundsArray.getJSONObject(i);
			fundInfo.setFundId(fundInfoJSON.getLong("id"));
			fundInfo.setFundName(fundInfoJSON.getString("name"));
			fundInfo.setStrategyName(fundInfoJSON.getString("strategyName"));
			fundInfoList.add(fundInfo);
		}
		return GlobalResponse.create(FundModuleResponse.SUCCESS, fundInfoList);
	}

	@HandleException
	@Override
	public GlobalResponse getMiddleOfficeAllFundsInfo() {
		Stopwatch stopwatch = Stopwatch.createStarted();
		String text = httpService.get(moConfigURL + "/finance/fund_product");
		log.info("拉取xyqb所有资方信息完成, 耗时 : {}, 结果 : {}", stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), text);

		QGPreconditions.checkArgument(StringUtils.isNotEmpty(text), QGExceptionType.GET_ALL_FUNDS_INFO_ERROR, text);
		JSONObject data = JSONObject.parseObject(text);
		QGPreconditions.checkArgument(data != null && "0".equals(data.getString("code")), QGExceptionType.GET_ALL_FUNDS_INFO_ERROR, text);

		List<FundInfo> fundInfoList = new ArrayList<>();
		JSONArray fundsArray = data.getJSONArray("data");
		for (int i = 0, len = fundsArray.size(); i < len; ++i) {
			JSONObject fundInfoJSON = fundsArray.getJSONObject(i);
			FundInfo fundInfo = new FundInfo();
			fundInfo.setFundId(fundInfoJSON.getLong("fundCorpId"));
			fundInfo.setFundName(fundInfoJSON.getString("fundCorpName"));
			fundInfo.setStrategyName(fundInfoJSON.getString("fundCorpStrategyName"));

			// 该资方产品id
			List<FundInfo.FundProductInfo> fundProductInfoList = new ArrayList<>();
			JSONArray fundProductArray = fundInfoJSON.getJSONArray("fundProductList");
			if (fundProductArray != null && fundProductArray.size() != 0) {
				for (int j = 0, lenP = fundProductArray.size(); j < lenP; ++j) {
					JSONObject fundProductJSON = fundProductArray.getJSONObject(j);
					FundInfo.FundProductInfo fundProductInfo = new FundInfo.FundProductInfo();
					fundProductInfo.setFundProductId(fundProductJSON.getLong("fundProductId"));
					fundProductInfo.setFundProductRemark(fundProductJSON.getString("fundProductRemark"));
					fundProductInfoList.add(fundProductInfo);
				}
			}
			fundInfo.setFundProductList(fundProductInfoList);
			fundInfoList.add(fundInfo);
		}
		return GlobalResponse.create(FundModuleResponse.SUCCESS, fundInfoList);
	}

	@HandleException
	@Override
	public GlobalResponse getAllLimitType() {
		List<FundModuleLimitTypeConfig> configList = fundModuleLimitTypeService.getAllLimitType();
		return GlobalResponse.create(FundModuleResponse.SUCCESS, configList);
	}

	@HandleException
	@Override
	public GlobalResponse saveChannelFundConfig(Integer type, Long id, String bizChannel, String funds, String remarks, 
			String auditor, String proposer) {
		if (type == FundModuleConstants.CHANNEL_FUNDS_OPERAOTR_TYPE_ADD) {
			return fundModuleChannelFundConfigService.addChannelFundConfig(bizChannel, funds, remarks, proposer, auditor);
		} else if (type == FundModuleConstants.CHANNEL_FUNDS_OPERATOR_TYPE_UPDATE) {
			return fundModuleChannelFundConfigService.updateChannelFundConfig(id, bizChannel, funds, remarks, proposer, auditor);
		}
		return GlobalResponse.create(FundModuleResponse.UNKNOW_TYPE);
	}

	@HandleException
	@Override
	public GlobalResponse saveChannelFundConfigNew(Integer type, Long id, String bizChannel, String funds, String remarks, String auditor, String proposer) {
		if (type == FundModuleConstants.CHANNEL_FUNDS_OPERAOTR_TYPE_ADD) {
			return fundModuleChannelFundConfigNewService.addChannelFundConfig(bizChannel, funds, remarks, proposer, auditor);
		} else if (type == FundModuleConstants.CHANNEL_FUNDS_OPERATOR_TYPE_UPDATE) {
			return fundModuleChannelFundConfigNewService.updateChannelFundConfig(id, bizChannel, funds, remarks, proposer, auditor);
		}
		return GlobalResponse.create(FundModuleResponse.UNKNOW_TYPE);
	}

	@HandleException
	@Override
	public GlobalResponse getChannelFundConfigs(String bizChannel, Long fundId, Integer pageNum, Integer pageSize) {
		Map<String, Object> result = fundModuleChannelFundConfigService.getChannelFundConfigsByChannelOrFundId(bizChannel, fundId, pageNum, pageSize);
		if (result.size() == 0) {
			return GlobalResponse.create(FundModuleResponse.HAS_NO_DATA);
		}
		return GlobalResponse.success(result);
	}

	@HandleException
	@Override
	public GlobalResponse getChannelFundConfigsNew(String bizChannel, Long fundId, Integer pageNum, Integer pageSize,Integer sortMode) {
		Map<String, Object> result;
		if (sortMode != null && sortMode == 1){
			result = fundModuleChannelFundConfigNewService.getChannelFundConfigsByChannelOrFundIdOrdered(bizChannel, fundId, pageNum, pageSize);
		}else{
			result = fundModuleChannelFundConfigNewService.getChannelFundConfigsByChannelOrFundId(bizChannel, fundId, pageNum, pageSize);
		}
		if (result == null || result.size() == 0) {
			return GlobalResponse.create(FundModuleResponse.HAS_NO_DATA);
		}
		return GlobalResponse.success(result);
	}

	@HandleException
	@Override
	public GlobalResponse getAuditInfos(String targetName, Integer auditStatus, Integer auditType, Integer auditTarget,
			String applyStartTime, String applyEndTime, String user, Integer pageNum, Integer pageSize) {
		Map<String, Object> result = approvalLogService.getApprovalLogs(targetName, auditStatus, auditType, auditTarget, applyStartTime, applyEndTime, user, pageNum, pageSize);
		if (result.size() == 0) {
			return GlobalResponse.create(FundModuleResponse.HAS_NO_DATA);
		}
		return GlobalResponse.success(result);
	}
	
	@HandleException
	@Override
	public GlobalResponse findChannelFundConfigById(Long configId) {
		FundModuleChannelFundConfig config = fundModuleChannelFundConfigService.findById(configId);
		if (config == null) {
			return GlobalResponse.create(FundModuleResponse.HAS_NO_DATA);
		}
		return GlobalResponse.success(config);
	}

	@HandleException
	@Override
	public GlobalResponse findChannelFundConfigNewById(Long configId) {
		FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewService.findById(configId);
		if (config == null) {
			return GlobalResponse.create(FundModuleResponse.HAS_NO_DATA);
		}
		return GlobalResponse.success(config);
	}

	@HandleException
	@Override
	public GlobalResponse audit(Long id, Integer auditStatus) {
		// 先获取审批记录
		ApprovalLog approvalLog = approvalLogService.findById(id);
		if (approvalLog == null) {
			return GlobalResponse.create(FundModuleResponse.HAS_NO_DATA);
		}
		
		if (AuditStatusEnum.containsCode(auditStatus)) {
			approvalLogService.audit(approvalLog, auditStatus);
			return GlobalResponse.success();
		} else {
			return GlobalResponse.create(FundModuleResponse.UKNOW_AUDIT_STATUS);
		}
	}

	@HandleException
	@Override
	public GlobalResponse getAllConfigChannel() {
		List<String> channels = fundModuleChannelFundConfigNewService.getAllConfigChanels();
		if (channels == null) {
			channels = Lists.newArrayList();
		}
		return GlobalResponse.success(channels);
	}

	@HandleException
	@Override
	public GlobalResponse getAllConditionsOfFundConfig(Long configId){
		FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewService.findById(configId);
		// 未找到资方渠道配置直接通知
		if (config == null) {
			return GlobalResponse.error("未找到相关配置");
		}
		List<ChannelFundConfigNew> fundConfigList = JSONArray.parseArray(config.getFunds(), ChannelFundConfigNew.class);
		List<FundModuleLimitTypeConfig> typeConfigs = fundModuleLimitTypeService.getAllLimitType();
		Map<String,String> codeToNameMap = new HashMap<>();
		for (FundModuleLimitTypeConfig typeConfig : typeConfigs){
			codeToNameMap.put(typeConfig.getCode(),typeConfig.getName());
		}
		List<BaseRuleVO> baseRuleList = new ArrayList<>();
		for (ChannelFundConfigNew channelFundConfig : fundConfigList) {
			IRuleVO ruleVO = ruleService.getIRuleVo(channelFundConfig.getLimits());
			getAllBaseRule(baseRuleList,ruleVO);
		}
		Map<String,List<String>> keyValueMap = collectValueMap(baseRuleList);
		//去掉相同的值 例如 amount>3000 和amount>=3000在生成案例时 3001都可以满足 此时会有两个3001
		for (Map.Entry<String,List<String>> entry : keyValueMap.entrySet()){
			entry.setValue(new ArrayList<>(new LinkedHashSet<>(entry.getValue())));
		}
		List<FundConfigCondition> configConditions = createCondition(keyValueMap,codeToNameMap);
		FundConfigSimulationVO vo = new FundConfigSimulationVO();
		vo.setConditionsCase(configConditions);
		List<FundConfigCondition.Condition> type = new ArrayList<>();
		for (String key : keyValueMap.keySet()){
			FundConfigCondition.Condition condition = new FundConfigCondition.Condition();
			condition.setConditionCode(key);
			condition.setConditionName(codeToNameMap.get(key));
			type.add(condition);
		}
		vo.setConditionsType(type);
		return GlobalResponse.success(vo);
	}

	@Override
	public GlobalResponse simulationCases(List<FundConfigCondition> configConditions,Long configId) {
		FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewService.findById(configId);
		if (config == null) {
			return GlobalResponse.error("未找到相关配置");
		}
		List<ChannelFundConfigNew> fundConfigList = JSONArray.parseArray(config.getFunds(), ChannelFundConfigNew.class);
		B:for (FundConfigCondition configCondition : configConditions){
			Map<String,Object> data = new HashMap<>();
			for (FundConfigCondition.Condition condition : configCondition.getCondition()){
				String value = condition.getConditionValue();
				Class<?> clazz = getType(value);
				if (clazz.isAssignableFrom(BigDecimal.class)){
					data.put(condition.getConditionCode(),new BigDecimal(value));
				}else{
					data.put(condition.getConditionCode(),value);
				}
			}
			// 资方去重, 可能存在多条件同一个资方
			Set<String> fundSet = new HashSet<>();
			JSONArray fundArray = new JSONArray();
			List<String> fundIds = new ArrayList<>();
			A:for (ChannelFundConfigNew channelFundConfig : fundConfigList) {
				IRuleVO ruleVO = ruleService.getIRuleVo(channelFundConfig.getLimits());
				if (ruleVO == null) { throw new QGException(QGExceptionType.CRATE_RULE_VO_ERROR); }
				Set<String> params = ruleVO.getParamNames();
				for (String key : params) {
					if (!data.containsKey(key)) {
						continue A;
					}
				}
				if (!ruleVO.valid(data)) {
					continue;
				}
				String key = channelFundConfig.getFundId() + "_" + channelFundConfig.getFundProductId() + "_" + channelFundConfig.getPriority();
				if (!fundSet.contains(key)) {
					// 创建并增加资方配置
					JSONObject fundInfoJSON = new JSONObject();
					fundInfoJSON.put("fundId", channelFundConfig.getFundId());
					fundInfoJSON.put("fundProductId", channelFundConfig.getFundProductId());
					fundInfoJSON.put("priority", channelFundConfig.getPriority());
					fundArray.add(fundInfoJSON);
					fundSet.add(key);
				}
				//命中一次增加一条
				fundIds.add(channelFundConfig.getFundId().toString());
			}
			FundConfigCondition.Result result = new FundConfigCondition.Result();
			if (CollectionUtils.isEmpty(fundArray)){
				result.setSuccess(false);
				result.setMessage("不存在输出结果");
				configCondition.setResult(result);
				continue;
			}
			QGPreconditions.checkArgument(fundArray.size() != 0, QGExceptionType.NO_FUND_INFO_BEEN_HIT);
			// 看命中优先级是否符合要求
            if (fundArray.size() > 1){
                Bag priBag = new HashBag(fundIds);
                List<Integer> priList = new ArrayList<>();
                for (int i = 0, len = fundArray.size(); i < len; i++) {
                    Integer pri = fundArray.getJSONObject(i).getIntValue("priority");
                    priList.add(pri);
                    priBag.add(pri);
                }
                for (Integer pri : priList) {
                    if (priBag.getCount(pri) > 1) {
                        result.setSuccess(false);
                        result.setMessage("多个资方配置存在交集");
                        configCondition.setResult(result);
                        continue B;
                    }
                }
            }
			// 查看是否两个资方ID相同且条件存在交集
			Bag bag = new HashBag(fundIds);
			boolean hasSameResultTotal = false;
			for (String id : fundIds){
				if (bag.getCount(id) > 1 ){
					hasSameResultTotal = true;
					break;
				}
			}
			if (hasSameResultTotal){
				result.setSuccess(false);
				result.setMessage("同资方存在配置交集");
				configCondition.setResult(result);
				continue ;
			}
			result.setSuccess(true);
			fundArray = JSONArray.parseArray(JSON.toJSONString(fundArray.stream().sorted(Comparator.comparingInt(o -> ((JSONObject) o).getInteger("priority"))).collect(Collectors.toList())));
			StringBuilder fundInfo = new StringBuilder();
			for (int i=0;i < fundArray.size();i++){
				String fundProductId = fundArray.getJSONObject(i).getString("fundProductId");
				String fundId = fundArray.getJSONObject(i).getString("fundId");
				fundInfo.append(("null".equals(fundProductId) || StringUtils.isEmpty(fundProductId)) ? fundId : fundId + "_" + fundProductId).append(",");
			}
			if (fundInfo.length() > 1){
				fundInfo.deleteCharAt(fundInfo.length() -1);
			}
			result.setFundInfo(fundInfo.toString());
			configCondition.setResult(result);
		}
		FundConfigSimulationVO vo = new FundConfigSimulationVO();
		vo.setConditionsCase(configConditions);
		return GlobalResponse.success(vo);
	}

	private static void getAllBaseRule(List<BaseRuleVO> ruleVOList,IRuleVO ruleVO){
		if (ruleVO.getClass().isAssignableFrom(UnionRuleVO.class)){
			UnionRuleVO uRuleVo = (UnionRuleVO)ruleVO;
			ruleVOList.addAll(uRuleVo.getBaseRules());
			if (CollectionUtils.isNotEmpty(uRuleVo.getUnionRules())){
				for (UnionRuleVO vo : uRuleVo.getUnionRules()){
					getAllBaseRule(ruleVOList,vo);
				}
			}
		}else {
			ruleVOList.add((BaseRuleVO)ruleVO);
		}
	}

	private static List<String> createValue(String operator,String value){
		List<String> list = new ArrayList<>();
		switch (RuleOperator.fromCode(operator)) {
			case Equal:
			case NotEqual:
				list.add(getValue(RuleOperator.Equal.getCode(),value));
				list.add(getValue(RuleOperator.NotEqual.getCode(),value));
				return list;
			case In:
			case NotIn:
				list.add(getValue(RuleOperator.In.getCode(),value));
				list.add(getValue(RuleOperator.NotIn.getCode(),value));
				return list;
			case LessThan:
			case GreaterThanOrEqual:
				list.add(getValue(RuleOperator.LessThan.getCode(),value));
				list.add(getValue(RuleOperator.GreaterThanOrEqual.getCode(),value));
				return list;
			case GreaterThan:
			case LessThanOrEqual:
				list.add(getValue(RuleOperator.GreaterThan.getCode(),value));
				list.add(getValue(RuleOperator.LessThanOrEqual.getCode(),value));
				return list;
			default:
				throw new QGException(QGExceptionType.RULE_OPERATOR_NOT_EXIST);
		}
	}

	/**
	 * 根据操作符和值生成新值  exp. >  3000   生成 3001   not in {9,10} 生成 8
	 * @param operator  操作符 参照 {@link RuleOperator}
	 * @param value 参与对比的值    若返回结果为x    则 x满足 x operator value
	 * @return 参照上述x
	 * @auth jian.zheng
	 * @update 2020-4-10 11:35:38
	 * @updatedBy jian.zheng
	 */
	private static String getValue(String operator,String value){
		Class<?> clazz = getType(value);
		switch (RuleOperator.fromCode(operator)) {
			case Equal:
			case LessThanOrEqual:
			case GreaterThanOrEqual:
				return value;
			case NotEqual:
				if (clazz.isAssignableFrom(BigDecimal.class)) {
					return new BigDecimal(value).add(new BigDecimal(1)).toString();
				}else if (clazz.isAssignableFrom(Boolean.class)){
					return Boolean.toString(!Boolean.parseBoolean(value));
				}else {
					if (RandomUtils.nextInt(0,10) <5){
						if ("a".equals(value) || "A".equals(value)){
							return getValue(">",value);
						}else {
							return getValue("<",value);
						}
					}else {
						if ("z".equals(value) || "Z".equals(value)){
							return getValue("<",value);
						}else {
							return getValue(">",value);
						}
					}
				}
			case In:
				if (value.contains(",")){
					List<String> list = Arrays.asList(value.split(","));
					return list.get(RandomUtils.nextInt(0,list.size()-1));
				}else {
					return value;
				}
			case NotIn:
				if (value.contains(",")){
					List<String> list = Arrays.asList(value.split(","));
					String start = getValue(operator,list.get(0));
					while (list.contains(start)){
						start = getValue("!=",start);
					}
					return start;
				}else {
					return getValue("!=",value);
				}
			case LessThan:
				if (BigDecimal.class.isAssignableFrom(clazz)){
					if (new BigDecimal(value).doubleValue() < 1 && new BigDecimal(value).doubleValue() > 0){
						return new BigDecimal(value).divide(new BigDecimal(10),value.split(".")[1].length(), RoundingMode.HALF_UP).toString();
					}else {
						return new BigDecimal(value).subtract(new BigDecimal(1)).toString();
					}
				}else if (String.class.isAssignableFrom(clazz)){
					if (value.length() == 1){
						if ("a".equals(value) || "A".equals(value)){
							return value + "-1";
						}else {
							return String.valueOf((char) (value.charAt(0) - 1));
						}
					}else {
						String front = value.substring(0,value.length() - 1);
						String last = String.valueOf(value.charAt(value.length() -1));
						String newLast = getValue("<",last);
						return front + newLast;
					}
				}
			case GreaterThan:
				if (BigDecimal.class.isAssignableFrom(clazz)){
					return new BigDecimal(value).add(new BigDecimal(1)).toString();
				}else if (String.class.isAssignableFrom(clazz)){
					if (value.length() == 1){
						if ("z".equals(value) || "Z".equals(value)){
							return value + "+1";
						}else {
							return String.valueOf((char) (value.charAt(0) + 1));
						}
					}else {
						String front = value.substring(0,value.length() - 1);
						String last = String.valueOf(value.charAt(value.length() + 1));
						String newLast = getValue(">",last);
						return front + newLast;
					}
				}
			default:
				throw new QGException(QGExceptionType.RULE_OPERATOR_NOT_EXIST);
		}
	}

	public static void main(String[] args) {
		System.out.println(getValue(">=","3000"));
		System.out.println(getValue("<=","3000"));
	}

	private static Class<?> getType(String value){
		if (StringUtils.isNumeric(value)){
			return BigDecimal.class;
		}
		if ("true".equals(value) || "false".equals(value)){
			return Boolean.class;
		}
		return String.class;
	}

	private static Map<String,List<String>> collectValueMap(List<BaseRuleVO> vos){
		Map<String,List<String>> keyValueMap = new HashMap<>();
		for (BaseRuleVO vo : vos){
			if (keyValueMap.containsKey(vo.getKey())){
				keyValueMap.get(vo.getKey()).addAll(createValue(vo.getOperator(),vo.getValue()));
			}else {
				keyValueMap.put(vo.getKey(),new ArrayList<>(createValue(vo.getOperator(),vo.getValue())));
			}
		}
		return keyValueMap;
	}

	/**
	 * 对map中的每个key的list做笛卡儿积
	 * @param map
	 * @return
	 */
	private static List<FundConfigCondition> createCondition(Map<String,List<String>> map,Map<String,String> codeToNameMap){
		List<FundConfigCondition> configConditions = new ArrayList<>();
		List<String> keyList = new ArrayList<>(map.keySet());
		List<List<String>> dimensionValue = new ArrayList<>();
		for (String key:keyList){
			dimensionValue.add(map.get(key));
		}
		List<List<String>> results = new ArrayList<>();
		descartes(dimensionValue,results,0,new ArrayList<>());
		for (int i = 0;i<results.size();i++){
			FundConfigCondition configCondition = new FundConfigCondition();
			List<FundConfigCondition.Condition> conditions = new ArrayList<>();
			for (int j = 0;j<results.get(i).size();j++){
				FundConfigCondition.Condition condition = new FundConfigCondition.Condition();
				condition.setConditionCode(keyList.get(j));
				condition.setConditionValue(results.get(i).get(j));
				condition.setConditionName(codeToNameMap.get(keyList.get(j)));
				conditions.add(condition);
			}
			configCondition.setConditionTempId(String.valueOf(i));
			configCondition.setCondition(conditions);
			configConditions.add(configCondition);
		}
		return configConditions;
	}

	/**
	 * 笛卡尔积演算
	 * @param dimensionValue
	 * @param result
	 * @param layer
	 * @param currentList
	 * @param <T>
	 */
	private static <T> void descartes(List<List<T>> dimensionValue, List<List<T>> result, int layer, List<T> currentList) {
		if (layer < dimensionValue.size() - 1) {
			if (dimensionValue.get(layer).size() == 0) {
				descartes(dimensionValue, result, layer + 1, currentList);
			} else {
				for (int i = 0; i < dimensionValue.get(layer).size(); i++) {
					List<T> list = new ArrayList<>(currentList);
					list.add(dimensionValue.get(layer).get(i));
					descartes(dimensionValue, result, layer + 1, list);
				}
			}
		} else if (layer == dimensionValue.size() - 1) {
			if (dimensionValue.get(layer).size() == 0) {
				result.add(currentList);
			} else {
				for (int i = 0; i < dimensionValue.get(layer).size(); i++) {
					List<T> list = new ArrayList<>(currentList);
					list.add(dimensionValue.get(layer).get(i));
					result.add(list);
				}
			}
		}
	}

}
