package nc.vo.baseapp.jsontool;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import nc.bs.framework.common.NCLocator;
import nc.bs.uap.tools.formula.ExtFormulaParser;
import nc.itf.uap.IUAPQueryBS;
import nc.pub.sap.constant.SapConstants;
import nc.pub.twxt.sort.TwxtVOSort;
import nc.util.mmf.framework.base.MMStringUtil;
import nc.util.mmf.framework.base.MMValueCheck;
import nc.vo.ep.bx.BXVO;
import nc.vo.erm.costshare.CShareDetailVO;
import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.BusinessException;
import nc.vo.pub.CircularlyAccessibleValueObject;
import nc.vo.pub.VOStatus;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.lang.UFDate;
import nc.vo.pub.lang.UFDateTime;
import nc.vo.pub.lang.UFDouble;
import nc.vo.pubapp.pattern.data.ValueUtils;
import nc.vo.sap.syproconfig.SyProConfigBVO;
import nccloud.commons.lang.ArrayUtils;
import nccloud.commons.lang.StringUtils;


public class JsonTransfVOUtil {
	public static <T extends AggregatedValueObject> T json2AggVO(ParamVO paramVO) throws Exception {
		String billdata = paramVO.getBilldata();
		JSONObject data =  JSONObject.parseObject(billdata);
		if(data == null||MMStringUtil.isEmpty(data.toString())) {
			return null;
		}
		JSONObject headJsonObject =data.getJSONObject("Header");
		//获取sap-nc的sap编码和nc的编码
		HashMap<String,String> htranNCcodeMap=getTranNCcodes(paramVO.gethCfgCode(), SapConstants.DIRECTION_SAP2NC);
		HashMap<String,String> btranNCcodeMap=getTranNCcodes(paramVO.getBfgCode(), SapConstants.DIRECTION_SAP2NC);
		
		Set<String> hsap_code=htranNCcodeMap.keySet();
		Set<String> bsap_code=btranNCcodeMap.keySet();
		
		HashMap<String,String> transfMap=new HashMap<String,String>();
		Class<? extends AggregatedValueObject> aggVOClass = paramVO.getAggVOClass();
		Class<? extends CircularlyAccessibleValueObject> headVOClass = paramVO.getHeadVOClass();
		Class<? extends CircularlyAccessibleValueObject> bodyVOClass = paramVO.getBodyVOClass();
		T aggVO = (T) aggVOClass.newInstance();
		CircularlyAccessibleValueObject headVO = headVOClass.newInstance();
		CircularlyAccessibleValueObject bodyVO = bodyVOClass.newInstance();
		CircularlyAccessibleValueObject[] bodyVOs;
		JSONObject bodyJsonObj;
		
		String hval=null;
		for(String wbcode:hsap_code){
			if(!headJsonObject.containsKey(wbcode.toLowerCase())){
				continue;
			}
			hval=headJsonObject.get(wbcode.toLowerCase())+"";
			transfMap.put(htranNCcodeMap.get(wbcode),hval);
		}
		String json = JSON.toJSONString(transfMap);
		JSONObject headJson = JSONObject.parseObject(json);
		JSONArray bodyitems = (JSONArray) data.get("Items");
		if (headJson == null || bodyitems == null) {
			return null;
		}
		//表头设值
		setValue(headVO,headJson);
		//表体VO
		bodyVOs =(CircularlyAccessibleValueObject[]) Array.newInstance(bodyVOClass,bodyitems.size());
		for (int j = 0; j < bodyitems.size(); j++) {
			transfMap=new HashMap<String,String>();
			bodyJsonObj = (JSONObject) bodyitems.get(j);
			String value=null;
			for(String wbcode:bsap_code){
				if(!bodyJsonObj.containsKey(wbcode.toLowerCase())){
					continue;
				}
				value=bodyJsonObj.get(wbcode.toLowerCase())+"";
				transfMap.put(btranNCcodeMap.get(wbcode),value);
			}

			String jsonbody = JSON.toJSONString(transfMap);
			bodyJsonObj = JSONObject.parseObject(jsonbody);
			
			if (bodyJsonObj == null) {
				continue;
			}
			bodyVO = bodyVOClass.newInstance();
			//表体设值
			setValue(bodyVO, bodyJsonObj);	
			bodyVOs[j] = bodyVO;
		}
		//组装AggVO
		aggVO.setParentVO(headVO);
		aggVO.setChildrenVO(bodyVOs);	

		return aggVO;
	}
	protected static void setValue(CircularlyAccessibleValueObject vo, JSONObject jaonObject) throws Exception{
		Map<String,String> fieldTypeMap = new HashMap<String,String>();
		Method[]  methods=vo.getClass().getMethods();
		List<Field> dataTypes=Arrays.asList(vo.getClass().getFields());
		
		for(Method m:methods){
			fieldTypeMap.put(m.getName().toLowerCase(), m.getReturnType().getSimpleName());
		}
		for(Field dataType:dataTypes){
			fieldTypeMap.put(dataType.getName(), dataType.getType().getSimpleName());
		}
		String attributeName;
		String type;
		Object value;
		Iterator<String> it =null;
		
		Set itSet=jaonObject.keySet();
		it=itSet.iterator();
		
		while (it.hasNext()) {
			attributeName = it.next();
			if (MMStringUtil.isEmpty(attributeName)) {
				continue;
			}
			value = jaonObject.get(attributeName);
			if (value == null || MMStringUtil.isEmpty(value.toString())) {
				continue;
			}
			type = fieldTypeMap.get(attributeName.toLowerCase());
			if(type==null){
				type=fieldTypeMap.get("get"+attributeName.toLowerCase());
			}
			if(type==null){
				vo.setAttributeValue(attributeName, value);
			}else if ("Integer".equals(type)) {
					value=jaonObject.getInteger(attributeName);
				for(int m=0;m<methods.length;m++){
					if(methods[m].getName().toLowerCase().equals("set"+attributeName)){
						vo.getClass().getMethod(methods[m].getName(),methods[m].getParameterTypes()[0]).invoke(vo, new Object[]{Integer.parseInt(value.toString())});
						break;
					}
				}
			} else if ("UFDouble".equals(type)) {
				vo.setAttributeValue(attributeName, new UFDouble(jaonObject.getDouble(attributeName)));
			} else if ("UFBoolean".equals(type)) {
				vo.setAttributeValue(attributeName, new UFBoolean(value.toString()));
			} else if ("UFDate".equals(type)) {
				vo.setAttributeValue(attributeName, new UFDate(value.toString()));
			} else if ("UFDateTime".equals(type)) {
				SimpleDateFormat sdfs = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				String notdate = sdfs.format(ValueUtils.getUFLiteralDate(value).getMillis());
				vo.setAttributeValue(attributeName, new UFDateTime(notdate));
			} else {
				vo.setAttributeValue(attributeName,value);
				if(null==vo.getAttributeValue(attributeName)){
					for(int m=0;m<methods.length;m++){
						if(methods[m].getName().toLowerCase().equals("set"+attributeName)){
							vo.getClass().getMethod(methods[m].getName(),methods[m].getParameterTypes()[0]).invoke(vo, new Object[]{value});
							break;
						}
					}
					
				}
			}
		}
		//VO状态
		vo.setStatus(VOStatus.NEW);
	}
	
	/**
	 * 非空校验+执行公式
	 * @param hConfigCode
	 * 				表头公式配置编码
	 * @param bConfigCode
	 * 				表体公式配置编码
	 * @param headVO
	 * 				表头VO
	 * @param bodyVOs
	 * 				表体VO
	 * @throws BusinessException
	 */
	public static void notNullCheckAndExFormula(String hConfigCode,String bConfigCode,AggregatedValueObject aggVO) throws Exception {
		HashMap<String,ArrayList<String>> hFormulaone = getFormulas(hConfigCode,SapConstants.DIRECTION_SAP2NC);
		HashMap<String,ArrayList<String>> bFormulaone = getFormulas(bConfigCode,SapConstants.DIRECTION_SAP2NC);
		List<String> headKeys = hFormulaone.get(SapConstants.NOTNULL_FIELD_KEY);
		List<String> headKeYsName = hFormulaone.get(SapConstants.NC_FIELD_NAME);
		List<String> bodyKeys = new ArrayList<String>();
		List<String> bodyKeysName = new ArrayList<String>();
		if(bFormulaone!=null){
			bodyKeys=bFormulaone.get(SapConstants.NOTNULL_FIELD_KEY);	
			 bodyKeysName=bFormulaone.get(SapConstants.NC_FIELD_NAME);
		}
		
		
		ArrayList<String> hFormula = hFormulaone.get(SapConstants.FORMULA_KEY);
		ArrayList<String> bFormula = new ArrayList<String>(); 
		if(bFormulaone!=null){
			bFormula =bFormulaone.get(SapConstants.FORMULA_KEY);
		}
		ExtFormulaParser extFormulaParser = new ExtFormulaParser();
		if(aggVO instanceof BXVO){//报销单
			
			BXVO bxvo=(BXVO)aggVO;
			CShareDetailVO[] shareVO=bxvo.getcShareDetailVo();
			if(shareVO!=null&&shareVO.length>0){
				notNullCheck(headKeys,headKeYsName,bodyKeysName,bodyKeys, aggVO.getParentVO(), bxvo.getcShareDetailVo(),1);	
				extFormulaParser.execFormulas(hFormula.toArray(new String[0]), bFormula.toArray(new String[0]), bxvo, null);
				notNullCheck(headKeys,headKeYsName,bodyKeysName,bodyKeys, aggVO.getParentVO(),bxvo.getcShareDetailVo(),2);
			}else {
				notNullCheck(headKeys,headKeYsName,bodyKeysName,bodyKeys, aggVO.getParentVO(), aggVO.getChildrenVO(),1);	
				extFormulaParser.execFormulas(hFormula.toArray(new String[0]), bFormula.toArray(new String[0]), bxvo, null);
				notNullCheck(headKeys,headKeYsName,bodyKeysName,bodyKeys, aggVO.getParentVO(),aggVO.getChildrenVO(),2);
			}
		}else{
			notNullCheck(headKeys,headKeYsName,bodyKeysName,bodyKeys, aggVO.getParentVO(), aggVO.getChildrenVO(),1);
			extFormulaParser.execFormulas(hFormula.toArray(new String[0]), bFormula.toArray(new String[0]),aggVO);
			notNullCheck(headKeys,headKeYsName,bodyKeysName,bodyKeys, aggVO.getParentVO(),aggVO.getChildrenVO(),2);
		}
	}
	
	/**
	 * 查询公式
	 * @param code			表头编码
	 * @param direction		方向【SAP->NC ? NC->SAP】
	 * @return
	 * @throws BusinessException
	 */
	public static HashMap<String,ArrayList<String>> getFormulas(String code,int direction) throws BusinessException{
		String enableCon="isenable_sn";
		if(SapConstants.DIRECTION_NC2SAP==direction) {
			enableCon="isenable_ns";
		}
		StringBuffer sqlstr = new StringBuffer("");
		sqlstr.append("item = (select pk_head").append("\r\n");
		sqlstr.append("  from sap_syproconfig").append("\r\n");
		sqlstr.append(" where billno = '");
		sqlstr.append(code);
		sqlstr.append("'").append("\r\n");
		sqlstr.append("   and nvl(dr, 0) = 0) and nvl(dr, 0) = 0  and "+enableCon+"='Y' ");
		List<SyProConfigBVO> syProConfigBVOs = (List<SyProConfigBVO>)getQueryBS().retrieveByClause(SyProConfigBVO.class, sqlstr.toString());
		if(syProConfigBVOs!=null && syProConfigBVOs.size()>0){
			HashMap<String,ArrayList<String>> formulasMap = new HashMap<String,ArrayList<String>>();
			//非空字段
			ArrayList<String> notNullField = new ArrayList<String>();
			//SAP->NC ？ NC->SAP 公式
			ArrayList<String> formula = new ArrayList<String>();
			//NC字段编码
			ArrayList<String> nc_field_code = new ArrayList<String>();
			//NC字段名称
			ArrayList<String> nc_field_name = new ArrayList<String>();
			//SAP字段编码
			ArrayList<String> sap_field_code = new ArrayList<String>();
			Collections.sort(syProConfigBVOs, new TwxtVOSort(direction));
			for(SyProConfigBVO syProConfigBVO:syProConfigBVOs){
				if(SapConstants.DIRECTION_SAP2NC==direction){
					//SAP->NC
					if(syProConfigBVO.getIsenable_sn().booleanValue()){
						if(!syProConfigBVO.getNullflag().booleanValue()){
							notNullField.add(syProConfigBVO.getField_code());
							nc_field_name.add(syProConfigBVO.getField_name());
						}
						formula.add(syProConfigBVO.getFormula_sn());
					}
					//把NC编码也放进去 begin
					nc_field_code.add(syProConfigBVO.getField_code());
					//把NC编码也放进去 end
				}else if(SapConstants.DIRECTION_NC2SAP==direction){
					//NC->SAP
					if(syProConfigBVO.getIsenable_ns().booleanValue()){
						formula.add(syProConfigBVO.getFormula_ns());
						nc_field_code.add(syProConfigBVO.getField_code());
						sap_field_code.add(syProConfigBVO.getField_code_sap());
					}
				}
			}
			formulasMap.put(SapConstants.NOTNULL_FIELD_KEY, notNullField);
			formulasMap.put(SapConstants.FORMULA_KEY, formula);
			formulasMap.put(SapConstants.NC_FIELD_CODE, nc_field_code);
			formulasMap.put(SapConstants.SAP_FIELD_CODE, sap_field_code);
			formulasMap.put(SapConstants.NC_FIELD_NAME, nc_field_name);
			return formulasMap;
		}
		return null;
	}
	
	/**
	 * 非空字段校验
	 * @param headKeys
	 * 			表头字段
	 * @param bodyKeys
	 * 			表体字段
	 * @param bodyKeys2 
	 * @param bodyKeysName 
	 * @param headVO
	 * 			表头VO
	 * @param bodyVOs
	 * 			表体VO
	 * @param type
	 * 			1：第一次非空校验，2：转换后非空校验
	 * @throws Exception
	 */
	public static void notNullCheck(List<String> headKeys,List<String> headKeYsName,List<String> bodyKeysName, List<String> bodyKeys, CircularlyAccessibleValueObject headVO,CircularlyAccessibleValueObject[] bodyVOs,int type) throws Exception{
		Set<String> keySetName = new HashSet<String>();
		Object value;
		if(MMValueCheck.isNotEmpty(headKeys) && headVO!=null){
			for (int i = 0; i < headKeys.size(); i++) {
				String key=headKeys.get(i);
				value = headVO.getAttributeValue(key);
				if(value==null || MMStringUtil.isEmpty(value.toString())){
					keySetName.add(headKeYsName.get(i));
				}
			}
		}
		if(MMValueCheck.isNotEmpty(bodyKeys) && ArrayUtils.isNotEmpty(bodyVOs)){
		     for (int i = 0; i < bodyKeys.size(); i++) {
				for(CircularlyAccessibleValueObject bodyVO:bodyVOs){
					String key=bodyKeys.get(i);
					value = bodyVO.getAttributeValue(key);
					if(value==null || MMStringUtil.isEmpty(value.toString())){
						keySetName.add(bodyKeysName.get(i));
					}
				}
			}
		}
		if(keySetName.size()>0){
			String keyName = StringUtils.join(keySetName.toArray(), "、");
			if(type==1){
				throw new BusinessException( "以下字段不能为空："+keyName);	
			}else{
				throw new BusinessException( "以下字段转换失败："+keyName);	
			}
		}
	}
	
	/**
	 * 查询NC字段编码和SAP编码对照
	 * @param code			表头编码
	 * @param direction		方向【SAP->NC ? NC->SAP】
	 * @return SAP->NC
	 * @throws BusinessException
	 */
	public static HashMap<String,String> getTranNCcodes(String code,int direction) throws BusinessException{
		StringBuffer sqlstr = new StringBuffer("");
		sqlstr.append("item = (select pk_head").append("\r\n");
		sqlstr.append("  from sap_syproconfig").append("\r\n");
		sqlstr.append(" where billno = '");
		sqlstr.append(code);
		sqlstr.append("'").append("\r\n");
		sqlstr.append("   and nvl(dr, 0) = 0) and nvl(dr, 0) = 0 "); 
		List<SyProConfigBVO> syProConfigBVOs = (List<SyProConfigBVO>)getQueryBS().retrieveByClause(SyProConfigBVO.class, sqlstr.toString());
		if(syProConfigBVOs!=null && syProConfigBVOs.size()>0){
			HashMap<String,String> tranNCcodeMap = new HashMap<String,String>();
			for(SyProConfigBVO syProConfigBVO:syProConfigBVOs){
				if(SapConstants.DIRECTION_SAP2NC==direction){
					//SAP->NC					
					if(syProConfigBVO.getIsenable_sn().booleanValue()){//是否启用sap-nc
						String code_sap=syProConfigBVO.getField_code_sap();
						if(code_sap!=null&&!"".equals(code_sap.trim())&&!"1".equals(code_sap.trim())){
							tranNCcodeMap.put(code_sap,syProConfigBVO.getField_code());
						}
					}					
				}
			}
			return tranNCcodeMap;
		}
		return null;
	}
	
	/**
	 * 只保留2000长度字符串
	 * @param str
	 * @return
	 */
	public static String getNewStr(String str) {
		if(str==null || "".equals(str)){
			return str;
		}
        int length = 0;
        int j = 0;
        for(int i = 0; i < str.length(); i++){
            int ascii = Character.codePointAt(str, i);  
            if(ascii >= 0 && ascii <=255){
            	length++;
            }else{
            	length += 2;
            }
            if(length>2000){
            	break;
            }
            j = i;
        }
       return str.substring(0,j+1);
    }
	
	public static IUAPQueryBS getQueryBS() {
		return NCLocator.getInstance().lookup(IUAPQueryBS.class);
	}
}
