package com.eactive.eai.rms.ext.mmi;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.eactive.eai.rms.common.util.CamelCaseUtil;
import com.eactive.eai.rms.common.util.StringUtils;
import com.eactive.eai.rms.onl.common.util.DateUtil;
import com.eactive.eai.transformer.layout.Item;
import com.eactive.eai.transformer.layout.Types;
import com.eactive.eai.transformer.util.ConstantUtil;

public class MMIParser implements MMIParserKey {
	public static void validation(String srcSysType,String tgtSysType,String interfaceType, Map<String, Map<String, String>> adapters
			, List<HashMap<String,Object>> transforms, List<HashMap<String,Object>> layouts , String eaiSevrDstcd) throws Exception{
//		1.어댑터 서버구분코드가 다를경우
		Map<String, String> src = adapters.get(SRC);
		Map<String, String> tgt = adapters.get(TGT);
		Map<String, String> resSrc = adapters.get(RES_SRC);
		
		
		String srcEaiSevrDstcd = "";//소스 어댑터 EAI서버구분코드
		String tgtEaiSevrDstcd = "";//타겟 어댑터 EAI서버구분코드
		String resSrcEaiSevrDstcd = "";//소스응답 어댑터 EAI서버구분코드
		if (src != null){
			if(adapters.get(SRC) != null){ //취약점소스 수정 2020.08.27
				srcEaiSevrDstcd = adapters.get(SRC).get("EAISEVRDSTCD");
			}
			
		}
		if (tgt != null){
			if(adapters.get(TGT) != null){ //취약점소스 수정 2020.08.27
				tgtEaiSevrDstcd = adapters.get(TGT).get("EAISEVRDSTCD");
			}
			
		}
		if (resSrc != null){
			if(adapters.get(RES_SRC) != null){ //취약점소스 수정 2020.08.27
				resSrcEaiSevrDstcd = adapters.get(RES_SRC).get("EAISEVRDSTCD");
			}
		}
		
		if ("A".equals(srcSysType) && "S".equals(tgtSysType) && "R".equals(interfaceType)){ // Async-Sync 응답으로 되어 있지만 실제는  Sync-Async 응답 임
			//어댑터가 1개여서 구분할수 없음
			if (StringUtils.isBlank(srcEaiSevrDstcd)){
				throw new Exception("소스 어댑터에 EAI서버구분코드가 없음. (" +srcEaiSevrDstcd+")" );
			}
		}else{
			
			if (StringUtils.isBlank(srcEaiSevrDstcd)){
				throw new Exception("소스 어댑터에 EAI서버구분코드가 없음. (" +srcEaiSevrDstcd+")" );
			}
			if (StringUtils.isBlank(tgtEaiSevrDstcd)){
				throw new Exception("타겟 어댑터에 EAI서버구분코드가 없음. (" +tgtEaiSevrDstcd+")" );
			}
			if ("A".equals(srcSysType) && "S".equals(tgtSysType)){ //Async-Sync인경우 어댑터 3개 비교
				if (StringUtils.isBlank(resSrcEaiSevrDstcd)){
					throw new Exception("소스응답 어댑터에 EAI서버구분코드가 없음. (" +resSrcEaiSevrDstcd+")" );
				}
				if (!srcEaiSevrDstcd.equals(resSrcEaiSevrDstcd)){
					throw new Exception("소스 어댑터의 EAI서버구분코드("+srcEaiSevrDstcd+") 와 소스 응답 어댑터에 EAI서버구분코드("+resSrcEaiSevrDstcd+") 가 불일치." );
				}
			}
			if (!srcEaiSevrDstcd.equals(tgtEaiSevrDstcd)){
				throw new Exception("소스 어댑터의 EAI서버구분코드("+srcEaiSevrDstcd+") 와 응답 어댑터에 EAI서버구분코드("+tgtEaiSevrDstcd+") 가 불일치." );
			}
			
		}
		
		if (!eaiSevrDstcd.equals(srcEaiSevrDstcd)){
			throw new Exception("인터페이스의 서버구분코드 ("+eaiSevrDstcd +") 와  소스 어댑터의 EAI서버구분코드("+srcEaiSevrDstcd+") 가 불일치." );
		}
		
//		2. 변환 갯수 valication
//		 > A-A 요청 REQ/RES 허용
//		 > A-A 응답 (REQ/RES)/ERR 허용
//		 > S-A 응답 허용안함   -- MMI 에서 넘어올때는 A-S 응답으로 넘어옴
//		 > A-S 요청 REQ/RES/ERR 허용
//		 > S-S 요청 REQ/RES/ERR 허용
//		 > S-A 요청 REQ/RES/ERR 허용
//
//		3. 레이아웃과 어댑터 type validation
//		 > A-A 요청 일때 REQ의 소스는 요청어댑터 타겟은 응답어댑터
//		 > A-A 응답 일때 RES의 소스는 요청어댑터 타겟은 응답어댑터
//		 > S-A 응답 일때 valication 안함
//		 > 나머지 
//		  >>REQ의 소스는 요청어댑터 타겟은 응답어댑터
//		  >>RES의 소스는 응답어댑터 타겟은 요청어댑터
//		  >>ERR의 소스는 응답어댑터 타겟은 요청어댑터
		
		if (transforms == null ||  transforms.size() == 0){
			return ;
		}

		//2. 변환 갯수 valication
		if ("A".equals(srcSysType) && "A".equals(tgtSysType) && "S".equals(interfaceType)){ // Async-Async 요청
			//인터페이스가 1개여야됨 
			//REQ 혹은 RES
			if( transforms.size() >1){
				String name = "";
				for(HashMap<String,Object> map : transforms){
					String temp = (String)map.get("cnvsnName");
					name += temp +",";
				}
				throw new Exception("변환룰이 설정해야 하는 것보다 많습니다.1개만 필요. 변환목록("+ name+")");
			}
		}else if ("A".equals(srcSysType) && "A".equals(tgtSysType) && "R".equals(interfaceType)){ // Async-Async 응답
			//인터페이스가 2개여야됨
			//(REQ or RES) and ERR
			String name = "";
			int count =0;
			for(HashMap<String,Object> map : transforms){
				String temp = (String)map.get("cnvsnName");
				if (temp.endsWith("_REQ") ||  temp.endsWith("_RES")){
					name += temp +",";
					count++;
				}
			}
			if (count==2){
				throw new Exception("변환룰이 설정해야 하는 것보다 많습니다.요청이나 응답은 1개만 필요. 변환목록("+ name+")");
			}
		}else if ("A".equals(srcSysType) && "S".equals(tgtSysType) && "R".equals(interfaceType)){ // Async-Sync 응답으로 되어 있지만 실제는  Sync-Async 응답 임
			//변환 설정이 없어야됨
			if (transforms.size()>0){
				String name = "";
				for(HashMap<String,Object> map : transforms){
					String temp = (String)map.get("cnvsnName");
					name += temp +",";
				}
				throw new Exception("변환룰이 설정해야 하는 것보다 많습니다.변환필요없음."+ name);
			}
		}

		if (layouts == null || layouts.size()==0){
			return ;
		}
		
//		Map<String, String> src = adapters.get(SRC);
//		Map<String, String> tgt = adapters.get(TGT);
		String srcAdptrMsgDstcd = "";//소스 어댑터 타입
		String tgtAdptrMsgDstcd = "";//타겟 어댑터 타입
		if (src != null){
			if(adapters.get(SRC) != null){//취약점소스 수정 2020.08.27
				srcAdptrMsgDstcd = adapters.get(SRC).get("ADPTRMSGDSTCD");
			}
		}
		if (tgt != null){
			if(adapters.get(TGT) != null){//취약점소스 수정 2020.08.27
				tgtAdptrMsgDstcd = adapters.get(TGT).get("ADPTRMSGDSTCD");
			}
		}
		//layout별 layout타입
		HashMap<String,String> layoutTypes = new HashMap<String,String>();
		for(HashMap m : layouts){
			layoutTypes.put((String)m.get("loutName"), (String)m.get("loutPtrnName"));
		}		
		
		//3. 레이아웃과 어댑터 type validation
		if ("A".equals(srcSysType) && "A".equals(tgtSysType)){ // Async-Async 요청/응답
			for(HashMap<String,Object> transform : transforms){
				List<HashMap<String,Object>> lists = (List)transform.get("layouts");
				String layout ="";
				for(HashMap m : lists){
					layout = (String)m.get("loutName");
					if (layout != null && layout.startsWith("EAI_") && layout.endsWith("_ERR") ){
						continue;
					}
					if ("SRC_LAYOUT".equals(m.get("sourcRsultDstcd"))){
						layout = (String)m.get("loutName");
						String layoutType = layoutTypes.get(layout);
						if (layoutType == null ){
							throw new Exception("MMI 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
						}
						if (!validationTypeMapping(srcAdptrMsgDstcd,layoutType)){
							throw new Exception("레이아웃 ("+layout+") 타입 오류 입니다. 어댑터 타입("+srcAdptrMsgDstcd+") 과 레이아웃 타입이 ("+layoutType+") 이 다릅니다. 어댑터를 잘못선택하거나 레이아웃 타입이 잘못됐습니다.");
						}
					}
					if ("TGT_LAYOUT".equals(m.get("sourcRsultDstcd"))){
						layout = (String)m.get("loutName");
						String layoutType = layoutTypes.get(layout);
						if (layoutType == null){
							throw new Exception("MMI 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
						}						
						if (!validationTypeMapping(tgtAdptrMsgDstcd,layoutType)){
							throw new Exception("레이아웃 ("+layout+") 타입 오류 입니다. 어댑터 타입("+tgtAdptrMsgDstcd+") 과 레이아웃 타입이 ("+layoutType+") 이 다릅니다. 어댑터를 잘못선택하거나 레이아웃 타입이 잘못됐습니다.");
						}
					}
				}
			}
		}else if ("A".equals(srcSysType) && "S".equals(tgtSysType) && "R".equals(interfaceType)){ // Async-Sync 응답으로 되어 있지만 실제는  Sync-Async 응답 임
			//없어야됨
		}else{
			for(HashMap<String,Object> transform : transforms){
				String cnvsnName = (String)transform.get("cnvsnName");
				if (cnvsnName.endsWith("_REQ")){
					List<HashMap<String,Object>> lists = (List)transform.get("layouts");
					String layout ="";
					for(HashMap m : lists){
						layout = (String)m.get("loutName");
						if (layout != null && layout.startsWith("EAI_") && layout.endsWith("_ERR") ){
							continue;
						}
						if ("SRC_LAYOUT".equals(m.get("sourcRsultDstcd"))){
							layout = (String)m.get("loutName");
							String layoutType = layoutTypes.get(layout);
							if (layoutType == null){
								throw new Exception("MMI 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
							}						
							if (!validationTypeMapping(srcAdptrMsgDstcd,layoutType)){
								throw new Exception("레이아웃 ("+layout+") 타입 오류 입니다. 어댑터 타입("+srcAdptrMsgDstcd+") 과 레이아웃 타입이 ("+layoutType+") 이 다릅니다. 어댑터를 잘못선택하거나 레이아웃 타입이 잘못됐습니다.");
							}
						}
						if ("TGT_LAYOUT".equals(m.get("sourcRsultDstcd"))){
							layout = (String)m.get("loutName");
							String layoutType = layoutTypes.get(layout);
							if (layoutType == null){
								throw new Exception("MMI 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
							}						
							if (!validationTypeMapping(tgtAdptrMsgDstcd,layoutType)){
								throw new Exception("레이아웃 ("+layout+") 타입 오류 입니다. 어댑터 타입("+tgtAdptrMsgDstcd+") 과 레이아웃 타입이 ("+layoutType+") 이 다릅니다. 어댑터를 잘못선택하거나 레이아웃 타입이 잘못됐습니다.");
							}
						}
					}
				}else if (cnvsnName.endsWith("_RES") || cnvsnName.endsWith("_ERR") ){
					List<HashMap<String,Object>> lists = (List)transform.get("layouts");
					String layout ="";
					for(HashMap m : lists){
						layout = (String)m.get("loutName");
						if (layout != null && layout.startsWith("EAI_") && layout.endsWith("_ERR") ){
							continue;
						}
						if ("SRC_LAYOUT".equals(m.get("sourcRsultDstcd"))){
							layout = (String)m.get("loutName");
							String layoutType = layoutTypes.get(layout);
							if (layoutType == null){
								throw new Exception("MMI 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
							}						
							if (!validationTypeMapping(tgtAdptrMsgDstcd,layoutType)){
								throw new Exception("레이아웃 ("+layout+") 타입 오류 입니다. 어댑터 타입("+tgtAdptrMsgDstcd+") 과 레이아웃 타입이 ("+layoutType+") 이 다릅니다. 어댑터를 잘못선택하거나 레이아웃 타입이 잘못됐습니다.");
							}
						}
						if ("TGT_LAYOUT".equals(m.get("sourcRsultDstcd"))){
							layout = (String)m.get("loutName");
							String layoutType = layoutTypes.get(layout);
							if (layoutType == null){
								throw new Exception("MMI 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
							}						
							if (!validationTypeMapping(srcAdptrMsgDstcd,layoutType)){
								throw new Exception("레이아웃 ("+layout+") 타입 오류 입니다. 어댑터 타입("+srcAdptrMsgDstcd+") 과 레이아웃 타입이 ("+layoutType+") 이 다릅니다. 어댑터를 잘못선택하거나 레이아웃 타입이 잘못됐습니다.");
							}
						}
					}
				}
			}
		}
		
	}
	private static boolean validationTypeMapping(String adapterType, String layoutType){
		if ("ASC".equals(adapterType)){
			if ("BYTES".equals(layoutType) || "COMBYTES".equals(layoutType) || "VBYTES".equals(layoutType) || "VFIELD".equals(layoutType) || "ODDBYTES".equals(layoutType) ){
				return true;
			}else{
				return false;
			}
		}else if ("EBC".equals(adapterType)){
			if ("EBCDIC".equals(layoutType) || "COMEBCDIC".equals(layoutType) || "VEBCDIC".equals(layoutType)){
				return true;
			}else{
				return false;
			}		
		}else if ("XML".equals(adapterType)){
			if ("XML".equals(layoutType) ){
				return true;
			}else{
				return false;
			}
		}else if ("JSN".equals(adapterType)){
			if ("JSON".equals(layoutType) ){
				return true;
			}else{
				return false;
			}
		}else if ("UJN".equals(adapterType)){
			if ("UJSON".equals(layoutType) ){
				return true;
			}else{
				return false;
			}			
		}else {
			return false;
		}
	}
    public static HashMap<String,Object> parseInfo(String data) throws Exception {
    	HashMap<String,Object> result = new HashMap<String,Object>();
    	InputStream is = null;
    	try { 
    		is = StringToStream(data);
    		SAXBuilder builder = new SAXBuilder();
    		Document doc = builder.build(is);
    		
    		Element inter = doc.getRootElement();
            Element attrinfo = inter.getChild(ATTRINFO);
            Element exthe01info = inter.getChild(EXTHE01INFO);
            
            result.putAll(getAttr(inter));
            result.putAll(getAttr(attrinfo));
            result.putAll(getAttr(exthe01info));
    		
    	}catch(Exception e){
    		throw new Exception("info parsing error "+e.getMessage(),e);
    	}finally{
    		if (is != null){try{is.close();}catch(Exception e ){}}
    	}
    	return result;
    	
    }
    public static HashMap<String,Object> parseInterface(String data, Map<String,Map<String,String>> adapters) throws Exception {
    	HashMap<String,Object> result = new HashMap<String,Object>();
    	InputStream is = null;
    	try { 
    		is = StringToStream(data);
	    	SAXBuilder builder = new SAXBuilder();
	        Document doc = builder.build(is);

	        Element inter = doc.getRootElement();
	        
	        validationInterface(inter);  
	        
	        result.put("he01", makeHe01(inter,adapters.get(SRC)));
	        result.put("he02", makeHe02(inter,adapters.get(TGT),adapters.get(RES_SRC)));
	        //요청 어댑터가 표준이 나닐경우 실행해야됨
	        if(KBSTANDARD.equals(adapters.get(SRC).get("ADPTRMSGPTRNCD"))){
	        	result.put("hs04", new ArrayList<HashMap<String,Object>>());
	        }else{
	        	result.put("hs04", makeHs04(inter));
	        }
	        result.put("fr04", makeFr04(inter,adapters.get(SRC)) );
	    	

    	}catch(Exception e){
    		throw new Exception("interface parsing error "+e.getMessage(),e);
    	}finally{
    		if (is != null){try{is.close();}catch(Exception e ){}}
    	}
    	
    	return result;

    }
    public static boolean validationInterface(Element inter)throws Exception{
    	HashMap<String,String> result = null;
        //interface 관련 validation
    	result = getAttr(inter);
    	String stdErrMpng = "";
        if (result != null && result.size() > 0){
        	stdErrMpng = result.get(STD_ERR_MPNG);
        }
    	//attrinfo 관련 validation
        result = getAttr(inter.getChild(ATTRINFO));
        if (result != null && result.size() > 0){
	        makeValidation(INTERFACE_TYPE,result.get(INTERFACE_TYPE),new String[]{"S","R"});
	        makeValidation(EAI_SYS_DSTCD,result.get(EAI_SYS_DSTCD),new String[]{"1","2","3","4","5"});
	        makeValidation(INF_TYPE,result.get(INF_TYPE),new String[]{"1","2"});
        }
        //he01 관련
        result = getAttr(inter.getChild(EXTHE01INFO));
        if(result != null && result.size() > 0){
        	String flowCtrlRoutName = result.get(FLOW_CTRL_ROUT_NAME);
        	if (StringUtils.isEmpty(flowCtrlRoutName)){
        		throw new Exception("FlowControl 라우팅명이 없습니다.");
        	}
        	if ("Y".equals(stdErrMpng) && flowCtrlRoutName.startsWith("B2BFC")){
        		throw new Exception("B2B FlowControl 에서는 표준에러 매핑을 사용할수 없습니다.");
        	}
        	
        }

        //hs01 관련
        result = getAttr(inter.getChild(EXTHS01INFO));
        if(result != null && result.size() > 0){
        	if (!StringUtils.isEmpty(result.get(BZWK_SVC_KEY_NAME))){
        		makeValidation(COMMON_OGTRAN_RSTR_YN,result.get(COMMON_OGTRAN_RSTR_YN),new String[]{"O","X"});
        	}
        }
        return true;
    }
    public static boolean makeValidation(String name, String value , String[] validValues) throws Exception{
    	boolean result = false;
    	String str = "";
    	for(String validValue : validValues){
    		str +=  ("".equals(str)? "":",") + validValue;
    		if (validValue.equals(value)){
    			result = true;
    		}
    	}
    	if (!result){
    		throw new Exception(name +"의 값이 유효하지 않습니다.( "+value +" ) . 유효한 값 목록은 ( "+str+" ) 입니다.");
    	}
    	
    	return true;
    }

	public static HashMap<String,Object> parseKey2( String eaiSvcName, String keyType, String value, String msgDstcd,String fullPath, String eaiSevrDstcd  )throws Exception{
		
		return makeRowFr03(eaiSvcName,keyType, Integer.parseInt(value), msgDstcd, fullPath.substring(2), eaiSevrDstcd );
	}
	/**
	 * 	
	 * 
	 *  sample
     *  findPath="/*[@id='FDEAI_TST0200100_REQ1']/*[@id='grid1']/*[@id='data1']";
	 * 
	 * @param data
	 * @param layoutFullPath
	 * @return
	 * @throws Exception
	 */
	public static boolean parseKeyValidation(String data, String layoutFullPath )throws Exception{
    	InputStream is = null;
    	try { 
    		String[] paths = layoutFullPath.split("\\.");
    		String findPath = "";
    		for(String path : paths){
    			findPath = findPath + "/*[@id='"+path+"']";
    		}
    		is = StringToStream(data);
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
			org.w3c.dom.Document document = documentBuilder.parse(is);
	
			XPath xpath = XPathFactory.newInstance().newXPath();
			NodeList nodelist = null;
			nodelist = (NodeList) xpath.evaluate(findPath, document, XPathConstants.NODESET);
			
			if (nodelist.getLength() == 1){
				return true;
			}
			return false;
		}catch(Exception e){
			throw new Exception("key parsing error "+e.getMessage(),e);
    	}finally{
    		if (is != null){try{is.close();}catch(Exception e ){}}
    	}
		
	}
	public static List<String> parseKey(String data )throws Exception{
		List<String> result = new ArrayList<String>();
    	InputStream is = null;
    	try { 
    		is = StringToStream(data);

    		SAXBuilder builder = new SAXBuilder();
	        Document doc = builder.build(is);

	        Element inter = doc.getRootElement();
	        Element attrinfo = inter.getChild(ATTRINFO);
	        String tranKey = attrinfo.getAttributeValue(TRAN_KEY);
	        if (!StringUtils.isEmpty(  tranKey )){
	        	String [] keys = tranKey.split(",");
	        	for(int i=0;i<keys.length;i++){
	        		if (!StringUtils.isEmpty(keys[i])){
	        			result.add("TR"+","+(i+1)+","+keys[i]);
	        		}
	        	}
	        }
	        String logKey = attrinfo.getAttributeValue(LOG_KEY);
	        if (!StringUtils.isEmpty(  logKey )){
	        	String [] keys = logKey.split(",");
	        	for(int i=0;i<keys.length;i++){
	        		if (!StringUtils.isEmpty(keys[i])){
	        			result.add("AK"+","+(i+1)+","+keys[i]);
	        		}
	        	}
	        }

		}catch(Exception e){
			throw new Exception("key parsing error "+e.getMessage(),e);
    	}finally{
    		if (is != null){try{is.close();}catch(Exception e ){}}
    	}
		
		return result;	
	}
	

	public static HashMap<String,Object> parseTransform(String data, String eaiBzwkDstcd, String eaiSevrDstcd)throws Exception{
		HashMap<String,Object> result = new HashMap<String,Object>();
    	InputStream is = null;
    	try { 
    		is = StringToStream(data);
			SAXBuilder builder = new SAXBuilder();
	        Document doc = builder.build(is);
	
	        Element format = doc.getRootElement();
	        
	        //data sample 변경
	        //FMEAI_FMTST0200100EAI_REQ
	        String cnvsnName = "TRANSFORM_"+format.getAttributeValue(ID).substring(2);
	        String desc = format.getAttributeValue(DESC);
	        
	        //서버구분코드가 FM에 있을경우에 FM을 따름 
	        String fmEaiSevrDstcd = format.getAttributeValue(MMIParserKey.EAI_SYS_DSTCD);
	        if (StringUtils.isEmpty(fmEaiSevrDstcd) ){
	        	fmEaiSevrDstcd = new String(eaiSevrDstcd);
	        }
	        
	        Element inputMap = format.getChild(INPUTMAP);
	        String srcLayoutName = inputMap.getAttributeValue(FROM).substring(2);
	        String tgtLayoutName = inputMap.getAttributeValue(TO).substring(2);
	        List<Element> flds = inputMap.getChildren();
	        List<HashMap<String,String>> mappings = new ArrayList<HashMap<String,String>>();
	        List<HashMap<String,String>> layouts = new ArrayList<HashMap<String,String>>();
	        for(Element fld : flds){
	        	String link = fld.getAttributeValue(LINK);
	        	String def = fld.getAttributeValue(DEFAULT);
	        	String mpngSeq = fld.getAttributeValue(MPNG_SEQ);
	        	String func   = fld.getAttributeValue(FUNC);
	        	String [] splits = link.replaceAll("::", ".").split("\\|");
	        	HashMap<String,String> mapping = new HashMap<String,String>();
	        	mapping.put("cnvsnName", cnvsnName);
	        	mapping.put("cnvsnRsultItemPathName", splits[0].replaceAll("FD"+tgtLayoutName, tgtLayoutName));
	        	//function이 있을경우는 function에 있는값으로 저장
	        	if (StringUtils.isEmpty(func)){
	        		mapping.put("cnvsnCmdName", splits[1].replaceAll("FD"+srcLayoutName, srcLayoutName));
	        	}else{
	        		func = func.replaceAll("::", ".");
	        		mapping.put("cnvsnCmdName", func.replaceAll("FD"+srcLayoutName, srcLayoutName));
	        	}
	        	mapping.put("cnvsnItemBascVal", def);
	        	
	        	if (StringUtils.isEmpty(mpngSeq)){
	        		mapping.put("cnvsnItemSerno", "9999");
	        	}else{
	        		mapping.put("cnvsnItemSerno", mpngSeq);
	        	}
	        	mappings.add(mapping);
	        	
	        }
	        result.put("cnvsnName", cnvsnName);
	        result.put("cnvsnDesc", desc);
	        result.put("lastAmndHms", DateUtil.getDateTimeMilliSecound());
	        result.put("eaiSevrDstcd", fmEaiSevrDstcd);
	        result.put("modfiMgtStusDstcd", " ");
	        result.put("useYn", "1");
	        result.put("verInfo",parseVerInfo(format.getAttributeValue(VER)));
	        
	        layouts.add(new HashMap<String,String>(){{put("cnvsnName",cnvsnName);put("loutName",srcLayoutName);put("sourcRsultDstcd","SRC_LAYOUT");}});
	        layouts.add(new HashMap<String,String>(){{put("cnvsnName",cnvsnName);put("loutName",tgtLayoutName);put("sourcRsultDstcd","TGT_LAYOUT");}});
	        
	        result.put("layouts", layouts);
	        result.put("mappings", mappings);
		}catch(Exception e){
			throw new Exception("transform parsing error "+e.getMessage(),e);
    	}finally{
    		if (is != null){try{is.close();}catch(Exception e ){}}
    	}
        
		return result;
		
	}
	public static void layoutDupValidation(String data)throws Exception{
    	InputStream is = null;
    	HashMap<String,String> map = new HashMap<String,String>();
    	try { 
    		is = StringToStream(data);
    		DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    		DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    		org.w3c.dom.Document document = documentBuilder.parse(is);
    		XPath xpath = XPathFactory.newInstance().newXPath();
    		NodeList nodelist = null;
    		nodelist = (NodeList) xpath.evaluate("/Format//*[@id]", document, XPathConstants.NODESET);
    		
    		for(int i=0;i<nodelist.getLength();i++){
    			Node node = nodelist.item(i);
    			Node parent = node.getParentNode();
    			String path ="";
    			while(parent != null){
    				NamedNodeMap nodeMap = parent.getAttributes();
    				if (nodeMap != null){
    					path = nodeMap.getNamedItem("id").getTextContent() + "." + path;
    				}
    				parent = parent.getParentNode();
    			}
    			path = path + node.getAttributes().getNamedItem("id").getTextContent();
    			if (map.containsKey(path)){
    				throw new Exception("레이아웃 항목이 중복이 발생하였습니다." + path);
    			}else{
    				map.put(path, path);
    			}
    		}    		
		}finally{
			if (is != null){try{is.close();}catch(Exception e ){}}
		}
    
	}	
	public static HashMap<String,Object> parseLayout(String data, String eaiSevrDstcd )throws Exception{
		HashMap<String,Object> vo = new HashMap<String,Object>();
		
    	InputStream is = null;
    	try { 
    		is = StringToStream(data);
			SAXBuilder builder = new SAXBuilder();
	        Document doc = builder.build(is);
	
	        Element format = doc.getRootElement();
	        validationLayout(format);
	        
	        String msgType = format.getAttributeValue(EAI_LAYOUT_CODE);
	        if( "ASCII".equals(msgType) ) {
	        	msgType = "BYTES";
	        } else if( "VASCII".equals(msgType) ) {
	        	msgType = "VBYTES";
	        }
	        String layoutName = format.getAttributeValue(ID).substring(2);
	
	        //서버구분코드가 FD에 있을경우에 FD를 따름 
	        String fdEaiSevrDstcd = format.getAttributeValue(MMIParserKey.EAI_SYS_DSTCD);
	        if (StringUtils.isEmpty(fdEaiSevrDstcd)){
	        	fdEaiSevrDstcd = new String(eaiSevrDstcd);
	        }
	        
			// Layout Format (TR07)
	        vo.put("loutName",layoutName);
	        vo.put("loutPtrnName",msgType); //  ASCII, EBCDIC, XML
	        vo.put("loutDesc",format.getAttributeValue(DESC));  
	
	        vo.put("lastAmndHMS",DateUtil.getDateTimeMilliSecound());
	        //vo.put("eaiBzwkDstcd", format.getAttributeValue(EAI_APP_CODE));
	        vo.put("eaiBzwkDstcd", layoutName.substring(0,3));
	        vo.put("uapplName", " ");
	        vo.put("sysIntfacName", " ");
	        vo.put("eaiSevrDstcd", fdEaiSevrDstcd);
	        vo.put("modfiMgtStusDstcd"," ");
	        vo.put("useYn","1"); //사용여부
	        vo.put("verInfo", parseVerInfo(format.getAttributeValue(VER)));
	        
			// Layout Item Format (TR08)
	        List<HashMap<String,Object>> list = new ArrayList<HashMap<String,Object>>();
	        HashMap<String,Object> tr08 = new HashMap<String,Object>();
	        tr08.put("loutName",layoutName);
	        tr08.put("loutItemName",layoutName);
	        tr08.put("loutItemSerno",0);
	        tr08.put("loutItemIDName",1000);
	        tr08.put("parntLoutItemIDName",0);
	        tr08.put("loutItemDesc",format.getAttributeValue(DESC));
	        tr08.put("loutItemNodePtrnIDName",Item.NODE_MESSAGE);
	        tr08.put("loutItemPtrnIDName",Types.TYPE_UNKNOWN);
	        tr08.put("loutItemPathName",""); // 
	        tr08.put("loutItemLenCnt",0);
	        tr08.put("loutItemRefInfo",""); // GROUP NAME
	        tr08.put("loutItemRefInfo2",""); // 
	        tr08.put("loutItemOccurPtrnDstcd",""); // 레이아웃항목발생유형구분코드
	        tr08.put("loutItemMaxOccurNoitm",0); // 레이아웃항목최대발생건수
	        tr08.put("loutItemMinOccurNoitm",0); // 레이아웃항목최소발생건수
	        tr08.put("loutItemBascVal","");  // 레이아웃항목기본값
	        tr08.put("loutItemMskYn"," "); // 
	        tr08.put("loutDptCnt",1);
	        tr08.put("decptLenCnt",0); // 소수점길이
	        tr08.put("loutItemRefPtrnIDName",""); // 데이터타입
	        tr08.put("loutItemMaskLength",0); //
	        tr08.put("multiLang", "");//multi language 관련
	        
	        list.add(tr08);
//	        HashMap<String, GroupVo> groupMap = new HashMap<String, GroupVo>();
//	        list.addAll(setLayoutItems(format, msgType, layoutName,groupMap));
	        list.addAll(setLayoutItems(format, msgType, layoutName));
	        
	        vo.put("list", list);
		}catch(Exception e){
			throw new Exception("layout parsing error "+e.getMessage(),e);
    	}finally{
    		if (is != null){try{is.close();}catch(Exception e ){}}
    	}
		return vo;
		
	}

	public static List<HashMap<String,Object>> setLayoutItems(Element e, String msgType, String loutName ) throws Exception {
		List<HashMap<String,Object>> list = new ArrayList<HashMap<String,Object>>();

        List<Element> items = e.getChildren();
        for(Element el : items) {
    		// Layout Item Format (TR08)
            HashMap<String,Object> item = new HashMap<String,Object>();

            item.put("loutName",loutName);
            item.put("loutItemName",el.getAttributeValue(ID));
            item.put("loutItemSerno", Integer.parseInt(el.getAttributeValue(NO)) );
            item.put("loutItemIDName",Integer.parseInt(el.getAttributeValue(NO)) + 1000);
            String no = el.getParentElement().getAttributeValue(NO);
            item.put("parntLoutItemIDName",Integer.parseInt( no == null ? "0":no ) + 1000 );
            item.put("loutItemDesc",el.getAttributeValue(DESC));
            
            int node = 0;
            if( GROUP.equals(el.getName().toUpperCase()) ) {
            	node = Item.NODE_GROUP;
            } else if(GRID.equals(el.getName().toUpperCase())) {
            	node = Item.NODE_GROUP;
            } else if(FLD.equals(el.getName().toUpperCase())) {
            	node = Item.NODE_FIELD;
            } else if(COLUMN.equals(el.getName().toUpperCase())) {
            	node = Item.NODE_FIELD;
            } else if(ATTR.equals(el.getName().toUpperCase())) {
            	node = Item.NODE_ATTR;
            	if ("JSON".equals(msgType) || "UJSON".equals(msgType)){
            		throw new Exception(el.getName()+"는 "+msgType+"에서 지원하지 않는 레이아웃 NODE 타입 입니다."+el.getAttributeValue(ID));
            	}
            } else {
            	throw new Exception("지원하지 않는 레이아웃 NODE 타입("+el.getName()+") 입니다."+ el.getAttributeValue(ID));
            }
            
            item.put("loutItemNodePtrnIDName",node);
            
            int loutType = Types.TYPE_UNKNOWN;

            if( GRID.equals(el.getName().toUpperCase()) || GROUP.equals(el.getName().toUpperCase()) ) {
            	;
            }else{
            	loutType = ConstantUtil.getDataTypeId(el.getAttributeValue(TYPE), msgType);
            }
            
            item.put("loutItemPtrnIDName",loutType);
            item.put("loutItemPathName"  ,"");
            item.put("loutItemLenCnt"    ,"".equals(el.getAttributeValue(LEN)) ? 0 : Integer.parseInt(el.getAttributeValue(LEN)));
            item.put("loutItemRefInfo"   ,""); //
            
            String rowcount = el.getAttributeValue(ROWCOUNT);//한글명일경우
            if (!StringUtils.isEmpty(rowcount)){
            	String findId = "";
            	for(Element findName : items){
            		String desc = findName.getAttributeValue(DESC);
            		if (desc.equals(rowcount)){
            			findId = findName.getAttributeValue(ID);
            		}
            	}            	
//            	Element path = e;
//            	do {
//            		List<Element> loopItems = path.getChildren();
//	            	for(Element findName : loopItems){
//	            		String desc = findName.getAttributeValue(DESC);
//	            		if (desc.equals(rowcount)){
//	            			findId = findName.getAttributeValue(ID);
//	            		}
//	            	}
//            		if ("FORMAT".equals(path.getName().toUpperCase())){
//            			break;
//            		}
//            		path = path.getParentElement();
//	            	
//            	}while(StringUtils.isEmpty(findId) );
            	if (StringUtils.isEmpty(findId)){
            		throw new Exception("레이아웃(" + loutName + ")에서 " + rowcount+" 가 참조하는 id가 존재 하지 않습니다.(참조ID가 GROUP의 depth와 같은 위치에 존재해야됩니다.)");
            	}
            	item.put("loutItemRefInfo2",findId); // 
            }else{
            	item.put("loutItemRefInfo2",""); // 
            }
            
            
            // MIN, MAX 설정
            // 통합인터페이스는 * , 숫자만 보냄 ( 가변은 * 고정은 숫자 ) 
            String occurNoitm = el.getAttributeValue(MAX_CNT);
            int max = 0;
            int min = 0;
            if( String.valueOf(Item.OCC_MULTI_OR_NONE).equals(occurNoitm) ) {  // *
            	max = -1;
            } else if ( String.valueOf(Item.OCC_ONCE_OR_NONE).equals(occurNoitm) ) {  // ?
            	max = 1;
            } else if ( String.valueOf(Item.OCC_MULTI_OR_ONCE).equals(occurNoitm) ) {  // +
            	min = 1;
            	max = -1;
            } else if ( "".equals(occurNoitm) ) {  // ""
            	min = 1;
            	max = 1;
            } else if ( occurNoitm.matches("[0-9]+") ) {  // ""
            	min = StringUtils.isNotEmpty(el.getAttributeValue(ROWCOUNT)) ? 0 : Integer.parseInt(occurNoitm);
            	max =  Integer.parseInt(occurNoitm);
            }
            
            // 반복횟수 참조정보가 없는데 MIN, MAX 값이 설정되지 않은 경우 오류
            if( max == 0 && min == 0 ) {
            	if(GRID.equals(el.getName().toUpperCase()) ) {
            		if ( !StringUtils.isEmpty(el.getAttributeValue(ROWCOUNT)) ) {            		
                	} else {
                		throw new Exception("반복횟수 참조정보 오류." + el.getAttributeValue(ID));
                	}
//            	} else {
//            		min = 1;
//        		    max = 1;
            	}            	
            }
            
//            if( "0".equals(occurNoitm) ) {
//            	occurNoitm = "";         		
//        	}
            //그리드항목중에  배열최대갯수가 ("*") 인데 반복횟수참조정보가 없는경우 
            if( !("XML".equals(msgType) || "UJSON".equals(msgType) || "JSON".equals(msgType))
            	&&	GRID.equals(el.getName().toUpperCase()) && String.valueOf(Item.OCC_MULTI_OR_NONE).equals(occurNoitm) && StringUtils.isEmpty(rowcount) ) {
            	throw new Exception ("가변 그리드에 반복횟수참조정보가 설정이 안되어 있습니다."+ el.getAttributeValue(ID)) ;
            }
            
            item.put("loutItemOccurPtrnDstcd",occurNoitm); // 레이아웃항목발생유형구분코드
            item.put("loutItemMaxOccurNoitm",max); // 레이아웃항목최대발생건수
            item.put("loutItemMinOccurNoitm",min); // 레이아웃항목최소발생건수
            
            //default값 추가에 의한 로직 추가 20200527 jun's
            //1.display O 일 경우 default값은 등록하지 않는다. mask항목 으로 loutItemMskYn 을 셋팅한다.
            //2.display M 일 경우 default값은 등록하지 않는다. mask항목 상관없이 loutItemMskYn 은 Y 로 셋팅
            //3.display D 일 경우 default값은 등록한다.      mask항목 으로 loutItemMskYn 을 셋팅한다.
            String display    = el.getAttributeValue(DISPLAY);;
            String defaultVal = null;
            String mask       = null;
            if ( display == null || "".equals(display) || "O".equals(display) ){
                defaultVal = "";
                mask       = el.getAttributeValue(MASK);  
            }else if ("M".equals(display)){
                defaultVal = "";
                mask       = "Y";  
            }else if ("D".equals(display)){
                defaultVal = el.getAttributeValue(DEFAULT);
                mask       = el.getAttributeValue(MASK);  
            }else {
            	throw new Exception("지원하지 않는 display type("+display+") 입니다."+ el.getAttributeValue(ID));
            }
            if (StringUtils.isBlank(defaultVal)){
            	item.put("loutItemBascVal", "" );  // 레이아웃항목기본값
            }else{
            	item.put("loutItemBascVal", defaultVal );  // 레이아웃항목기본값
            }
            if (StringUtils.isBlank(mask) ){
            	item.put("loutItemMskYn"," "); // [Y/N/ ]
            }else{
            	item.put("loutItemMskYn",mask); // [Y/N/ ]
            }
            
//            item.put("loutItemBascVal", el.getAttributeValue(DEFAULT) );  // 레이아웃항목기본값
//            if (el.getAttributeValue(MASK)==null || el.getAttributeValue(MASK).trim().length()==0 ){
//            	item.put("loutItemMskYn"," "); // [Y/N/ ]
//            }else{
//            	item.put("loutItemMskYn",el.getAttributeValue(MASK)); // [Y/N/ ]
//            }
            String itemDesc = el.getAttributeValue(DESC);
            if (itemDesc != null && itemDesc.indexOf("비밀") !=-1){
            	item.put("loutItemMskYn","Y"); // [Y/N/ ]
            }
            //if( "Y".equals(item.get("loutItemMskYn")) ) item.put("loutItemMaskLength",Integer.parseInt(el.getAttributeValue("len")));
            item.put("loutDptCnt",Integer.parseInt(el.getAttributeValue(DEPTH)) + 1 );  // 통합인터페이스 전달되는 Depth + 1을 해야 함
            item.put("decptLenCnt","".equals(el.getAttributeValue(SCALE)) ? 0 : Integer.parseInt(el.getAttributeValue(SCALE))); // 소수점길이 META에서 "" 이면 "" 으로 표현함
            item.put("loutItemMaskLength",0); // 
            
            String dataType = "";
            if( el.getAttributeValue(TYPE) == null ||  "".equals(el.getAttributeValue(TYPE))) {            	
            } else {
            	dataType = el.getAttributeValue(TYPE);
            }            
            item.put("loutItemRefPtrnIDName",dataType); // 데이터타입
            item.put("multiLang",el.getAttributeValue(CONVERT)); // 데이터타입

            list.add(item);
            if( el.getChildren() != null && el.getChildren().size() > 0 ) {
            	list.addAll(setLayoutItems(el, msgType, loutName));
            }
        }  // end FOR
		
		return list;
	}

    public static boolean validationLayout(Element inter)throws Exception{
    	HashMap<String,String> result = null;
        //layout format 관련 validation
    	result = getAttr(inter);
    	if (result != null && result.size() > 0){
	    	//makeValidation("eai_tran_type",result.get("eai_tran_type"),new String[]{"REQ1","REQ2","RES1","RES2","ERR1","ERR2"});
	    	makeValidation(EAI_LAYOUT_CODE,result.get(EAI_LAYOUT_CODE),
	    			new String[]{ "ASCII", "COMBYTES", "VBYTES"
	    					    , "EBCDIC", "COMEBCDIC","VEBCDIC"
	    					    , "VFIELD" , "ODDBYTES"
	    					    //, "VXML"  as-is vfield 의 상대 tobe에서는 Vfield 가  정상적으로 동작
	    					    , "JSON","UJSON"
	    					    ,"XML"
	    					    });
	    	//makeValidation("id",result.get("id").split("_")[2],new String[]{"REQ1","REQ2","RES1","RES2","ERR1","ERR2"});
    	}

        return true;
    }


	
	public static HashMap<String,Object> makeHe01(Element inter,Map<String,String> src) throws Exception{
		HashMap<String,Object> he01 = new HashMap<String,Object>();
        Element attrinfo = inter.getChild(ATTRINFO);
        Element exthe01info = inter.getChild(EXTHE01INFO);

        //excel 샘플상으로 Async-Sync 응답은 존재 하지 않기 때문에 Sync-Async의 응답 대용으로 한다.
        if ("A".equals(attrinfo.getAttributeValue(SRC_SYS_TYPE))
        		&& "S".equals(attrinfo.getAttributeValue(TRG_SYS_TYPE))
        		&& "R".equals(attrinfo.getAttributeValue(INTERFACE_TYPE))
        		){
            he01.put("svcMotivUseDstcd"           , "SYNC" ); // 서비스동기사용구분코드                      
        }else{
            //he01.put("svcMotivUseDstcd"           , "A".equals(src.get("ADPTRNICKNAME").substring(4,5))?"ASYN":"SYNC" ); // 서비스동기사용구분코드                      
            he01.put("svcMotivUseDstcd"           , "A".equals(attrinfo.getAttributeValue(SRC_SYS_TYPE))?"ASYN":"SYNC" ); // 서비스동기사용구분코드                      
        }
        
        he01.put("eaiSvcName"                 , exthe01info.getAttributeValue(EAI_SVC_NAME)         );// EAI서비스명
        he01.put("eaiBzwkDstcd"               , attrinfo.getAttributeValue(APP_CD)                  ); // EAI업무구분코드        
        he01.put("svcHMSEonot"                , "0"                                                 ); // 서비스시각유무   
        he01.put("svcPrcesDsticName"          , "SINGLE"                                            ); // 서비스프로세스구분명
        
        he01.put("flowCtrlRoutName"           , exthe01info.getAttributeValue(FLOW_CTRL_ROUT_NAME)  ); // 흐름통제라우팅명
        he01.put("intgraDsticName"            , "ONLINE"                                            ); // 통합구분명                                 
        he01.put("svcBfClmnLogYn"             , "1"                                                 ); // 서비스전컬럼로그여부
        if(src != null) {  //취약점소스 수정 2020.08.26
        	he01.put("gstatSysAdptrBzwkGroupName" , src.get("ADPTRBZWKGROUPNAME")                       ); // 기동시스템어댑터업무그룹명
        }
        he01.put("sevrLogLvelNo"              , "2"                                                 ); // 서버로그레벨번호  
        
        he01.put("svcLogLvelNo"               , "3"                                                 ); // 서비스로그레벨번호
        //he01.put("errEaiSvcName"              , " ");//오류EAI서비스면
        //he01.put("dmndErrChngIdName"          , " ");//요청오류변환ID명
        //he01.put("dmndErrFldName"             , " ");//요청에러필드명
        //he01.put("rspnsErrChngIdName"         , " ");//응답오류변환ID명
        //he01.put("rspnsErrFldName"            , " ");//응답에러필드명
        he01.put("eaiSvcDesc"                 , attrinfo.getAttributeValue(SYS_INF_NM)              ); // EAI서비스명
        he01.put("eaiSevrDstcd"               , attrinfo.getAttributeValue(EAI_SYS_DSTCD)           );//EAI서버 구분코드내용
        he01.put("modfiMgtStusDstcd"          , " ");//변경괄리상태구분코드내용
        he01.put("eaiLastAmndYMS"             , DateUtil.getDateTimeMilliSecound());//EAI최종수정일시
        he01.put("eaiGroupCoCd"               , "KB0"                                               );//EAI그룹회사코드내용
        he01.put("tranType"                   , "R"                                                 );//거래처리구분코드내용
        he01.put("useYn"                      , "1"                                                 );//사용여부
        he01.put("verInfo"					  , parseVerInfo(inter.getAttributeValue(VER))			);//서비스코드 버전정보	
        
		return he01;
		
	}
	public static List<HashMap<String,Object>> makeHe02(Element inter,Map<String,String> trg, Map<String,String> resSrc) throws Exception{
		HashMap<String,Object> he02 = new HashMap<String,Object>();
		List<HashMap<String,Object>> he02s = new ArrayList<HashMap<String,Object>>();
        Element attrinfo = inter.getChild(ATTRINFO);
        Element exthe01info = inter.getChild(EXTHE01INFO);
        
        Element restOption        = inter.getChild(RESTOPTION);
        String restOptionData = " ";
        if (restOption != null){
        	restOptionData = restOption.getTextTrim();
        }
        
        //excel 샘플상으로 Async-Sync 응답은 존재 하지 않기 때문에 Sync-Async의 응답 대용으로 한다.
        //Async- Sync 의 응답 은 타겟 어댑터가 없을수 있다.
        if ("A".equals(attrinfo.getAttributeValue(SRC_SYS_TYPE))
        		&& "S".equals(attrinfo.getAttributeValue(TRG_SYS_TYPE))
        		&& "R".equals(attrinfo.getAttributeValue(INTERFACE_TYPE))
        		){
            he02.put("psvIntfacDsticName"       , "ASYN"); // 수동인터페이스구분명        
            if (trg == null || trg.size()==0){
            	he02.put("psvSysAdptrBzwkGroupName" , " "  ); // 수동시스템어댑터업무그룹명
            	he02.put("outbndRoutName"           , "SOCKETOUT"  ); // 아웃바운드라우팅명        
            }else{
            	he02.put("psvSysAdptrBzwkGroupName" , trg.get("ADPTRBZWKGROUPNAME" )); // 수동시스템어댑터업무그룹명
            	he02.put("outbndRoutName"           , trg.get("ROUTNAME")  ); // 아웃바운드라우팅명        
            }
        }else{
            //he02.put("psvIntfacDsticName"       , "A".equals(tgt.get("ADPTRNICKNAME").substring(4,5))?"ASYN":"SYNC"  ); // 수동인터페이스구분명        
            he02.put("psvIntfacDsticName"       , "A".equals(attrinfo.getAttributeValue(TRG_SYS_TYPE))?"ASYN":"SYNC"  ); // 수동인터페이스구분명        
            if (trg != null){//취약점소스 수정 2020.08.27
            	he02.put("psvSysAdptrBzwkGroupName" , trg.get("ADPTRBZWKGROUPNAME" )); // 수동시스템어댑터업무그룹명
            	he02.put("outbndRoutName"           , trg.get("ROUTNAME")  ); // 아웃바운드라우팅명        
            }
        }
        
        he02.put("eaiSvcName"               , exthe01info.getAttributeValue(EAI_SVC_NAME) );// EAI서비스명
        he02.put("svcPrcssNo"               , 1                            ); // 서비스처리번호
        he02.put("psvSysBzwkDstcd"          , exthe01info.getAttributeValue(EAI_SVC_NAME).substring(0,3)       ); // 수동시스템업무구분코드          
    	he02.put("psvSysIDName"             , "EAIDOM"                     ); // 수동시스템ID명         
    	
    	he02.put("psvSysSvcDsticName"       , " "                          ); // 수동시스템서비스구분명      
    	//결정필요                                                             
    	he02.put("flovrYn"                  , "0"                          ); // 장애극복여부            
    	he02.put("chngEonot"                , "0"                          ); // 변환유무             
    	he02.put("chngMsgIDName"            , " "                          ); // 변환메시지ID명         
    	
    	he02.put("bascRspnsMsgCmprCtnt"     , " "                          ); // 기본응답메시지비교내용      
    	he02.put("bascRspnsChngEonot"       , "0"                          ); // 기본응답변환유무             
    	he02.put("bascRspnsChngMsgIDName"   , " "                          ); // 기본응답변환메시지ID명     
    	he02.put("errRspnsMsgCmprCtnt"      , " "                          ); // 오류응답메시지비교내용      
    	he02.put("errRspnsChngEonot"        , "0"                          ); // 오류응답변환유무         
    	
    	he02.put("errRspnsChngMsgIDName"    , " "                          ); // 오류응답변환메시지ID명     
    	he02.put("nextSvcPrcssNo"           , 1                            ); // 다음서비스처리번호      
    	he02.put("toutVal"                  , 60                           ); // 타임아웃값          
    	he02.put("cmpenSvcPrcssDsticName"   , " "                          ); // 보상서비스처리구분명                 
    	
    	he02.put("supplDelYn"               , "0"                          ); // 추가삭제여부         
    	he02.put("hdrCtrlDstcd"             , "01"                         ); // 헤더제어구분코드  
    	he02.put("hdrRefClsName"            , " "                          ); // 헤더참조클래스명  
    	he02.put("restOption"               , restOptionData               ); // rest추가 정보
    	
    	he02s.add(he02);
    	
    	if (resSrc != null){//ASYNC SYNC일경우
    		he02 = new HashMap<String,Object>();
	    	he02.put("eaiSvcName"               , exthe01info.getAttributeValue(EAI_SVC_NAME) );// EAI서비스명
	    	he02.put("svcPrcssNo"               , 2                          ); // 서비스처리번호
	    	he02.put("psvIntfacDsticName"       , "ASYN"                     ); // 수동인터페이스구분명        
	    	he02.put("psvSysBzwkDstcd"          , exthe01info.getAttributeValue(EAI_SVC_NAME).substring(0,3)       ); // 수동시스템업무구분코드          
	    	he02.put("psvSysIDName"             , "EAIDOM"                   ); // 수동시스템ID명         
	    	he02.put("psvSysSvcDsticName"       , " "                        ); // 수동시스템서비스구분명      
	    	he02.put("psvSysAdptrBzwkGroupName" , resSrc.get("ADPTRBZWKGROUPNAME")); // 수동시스템어댑터업무그룹명
	    	//식별필요
	    	he02.put("flovrYn"                  , "0"                        ); // 장애극복여부            
	    	he02.put("chngEonot"                , "0"                        ); // 변환유무             
	    	he02.put("chngMsgIDName"            , " "                        ); // 변환메시지ID명         
	    	he02.put("bascRspnsMsgCmprCtnt"     , " "                        ); // 기본응답메시지비교내용      
	    	he02.put("bascRspnsChngEonot"       , "0"                        ); // 기본응답변환유무             
	    	he02.put("bascRspnsChngMsgIDName"   , " "                        ); // 기본응답변환메시지ID명     
	    	he02.put("errRspnsMsgCmprCtnt"      , " "                        ); // 오류응답메시지비교내용      
	    	he02.put("errRspnsChngEonot"        , "0"                        ); // 오류응답변환유무         
	    	he02.put("errRspnsChngMsgIDName"    , " "                        ); // 오류응답변환메시지ID명     
	    	he02.put("nextSvcPrcssNo"           , 1                          ); // 다음서비스처리번호      
	    	he02.put("outbndRoutName"           , resSrc.get("ROUTNAME")     ); // 아웃바운드라우팅명        
	    	he02.put("toutVal"                  , 60                         ); // 타임아웃값          
	    	he02.put("cmpenSvcPrcssDsticName"   , " "                        ); // 보상서비스처리구분명                 
	    	he02.put("supplDelYn"               , "0"                        ); // 추가삭제여부         
	    	he02.put("hdrCtrlDstcd"             , "01"                       ); // 헤더제어구분코드  
	    	he02.put("hdrRefClsName"            , " "                        ); // 헤더참조클래스명
	    	he02.put("restOption"               , " "                        ); // rest추가 정보
        
	    	he02s.add(he02);
    	}
        return he02s;
	}

	public static List<HashMap<String,Object>> makeHs04(Element inter) throws Exception{
		List<HashMap<String,Object>> results = new ArrayList<HashMap<String,Object>>();
		HashMap<String,Object> hs04 = null;
		List<HashMap<String,Object>> hs05s = null;
		Element attrinfo = inter.getChild(ATTRINFO);
        Element exthe01info = inter.getChild(EXTHE01INFO);
        List<Element> exths01infos = inter.getChildren(EXTHS01INFO);
        
		
		String inf_type = attrinfo.getAttributeValue(INF_TYPE);            //1:취급(당발) 2:개설(타발) 대외거래만 들어옮
		String interface_type =attrinfo.getAttributeValue(INTERFACE_TYPE);;//S:요청 R:응답
        
    	for(Element exths01info : exths01infos){
    		String bzwkSvcKeyName = exths01info.getAttributeValue(BZWK_SVC_KEY_NAME);
    		if (StringUtils.isEmpty(bzwkSvcKeyName)){
    			continue;
    		}
    		hs04 = new HashMap<String,Object>();
    		String eaiSevrDstcd = attrinfo.getAttributeValue(EAI_SYS_DSTCD);
    		hs04.put("bzwkSvcKeyName"   , bzwkSvcKeyName);//업무서비스키명
    		hs04.put("eaiSvcName"       , exthe01info.getAttributeValue(EAI_SVC_NAME));//EAI서비스명
    		hs04.put("eaiTranName"      , attrinfo.getAttributeValue(SYS_INF_CD));//EAI거래명
    		hs04.put("eaiSevrDstcd"     , eaiSevrDstcd);//EAI서버구분코드
    		hs04.put("modfiMgtStusDstcd", " ");//변경관리상태구분코드
    		hs04.put("eaiLastAmndYms"   , DateUtil.getDateTimeMilliSecound());//EAI최종수정일자
    		
    		HashMap<String,String> exths01infoMap = getAttr(exths01info);
    		hs05s = new ArrayList<HashMap<String,Object>>();
    		for(String key : exths01infoMap.keySet()){
    	    	if (!(key.startsWith("header") || key.startsWith("common")) ){
    	    		continue;
    	    	}
    	    	String[] keyarrs = key.split("_",2);
    	    	String replaceKey= keyarrs[0].toUpperCase()+"_"+CamelCaseUtil.converCamelCaseWithoutFirst(keyarrs[1],"_");
    	    	if ("COMMON_ogtranRstrYn".equals(replaceKey)){
    	    		if("O".equals(exths01infoMap.get(key)) ){
    	    			hs05s.add(makeRowHs05(bzwkSvcKeyName, replaceKey,"1"));
    	    		}else{
    	    			hs05s.add(makeRowHs05(bzwkSvcKeyName, replaceKey,"0"));
    	    		}
    	    		continue;
    	    	}
    			hs05s.add(makeRowHs05(bzwkSvcKeyName, replaceKey,exths01infoMap.get(key)));
    		}
   			hs05s.add(makeRowHs05(bzwkSvcKeyName, "HEADER_telgmDmndDstcd",interface_type));//전문요청구분코드	 S : 요청  R : 응답
    		hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_groupCoCd","KB0"));//그룹회사코드
    		
    		if ("1".equals(inf_type) 
    				&& "R".equals(interface_type) 
    				){//당발응답
    			//hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_prcssRtdTranCd","0000"+attrinfo.getAttributeValue(APP_CD)+"00000"));//처리결과수신거래코드
				String eaisvcname = exthe01info.getAttributeValue(EAI_SVC_NAME);
				String startzone =  eaisvcname.substring(eaisvcname.length()-6,eaisvcname.length()-3);
    			hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_prcssRtdTranCd","0000"+startzone+"00000"));//처리결과수신거래코드
    		}else{//타발요청
    			String res_inf_cd = attrinfo.getAttributeValue(RES_INF_CD).trim();
    			if (res_inf_cd.length()==0){
    				//hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_prcssRtdTranCd","0000"+attrinfo.getAttributeValue(APP_CD)+"00000"));//처리결과수신거래코드
    				//hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_prcssRtdTranCd","0000"+exthe01info.getAttributeValue(EAI_SVC_NAME).substring(0,3)+"00000"));//처리결과수신거래코드
    				String eaisvcname = exthe01info.getAttributeValue(EAI_SVC_NAME);
    				String startzone =  eaisvcname.substring(eaisvcname.length()-6,eaisvcname.length()-3);
    				hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_prcssRtdTranCd","0000"+startzone+"00000"));//처리결과수신거래코드
    			}else if (res_inf_cd.length() >11){
    				String a1 = res_inf_cd.substring(3,7);
    				String a2 = res_inf_cd.substring(0,3);
    				String a3 = res_inf_cd.substring(7);
    				String temp = StringUtils.rightPad(a1+a2+a3,14)+"-";
    				hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_prcssRtdTranCd",temp));//처리결과수신거래코드
    			}else{
    				hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_prcssRtdTranCd","0000"+res_inf_cd));//처리결과수신거래코드
    			}
    		}
    		hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_screnNo","1234567890"));//화면번호
    		//////////////////////////
    		//룰 
    		//내부인경우와 내부가 아닌경우로 나누어져야됨
    		//당발요청 S02 , 타발응답 R02
    		//타발요청 S01 , 당발응답 R01
    		// inf_type : 1: 당발 , 2:타발
    		if ("1".equals(eaiSevrDstcd)){//내부서버일 경우 
    			hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_eaiInoPartlDstcd","1"));//EAI 내외부구분코드
    		}else{//내부서버가 아닐경우
	    		if (("1".equals(inf_type) && "S".equals(interface_type) ) || ("2".equals(inf_type) && "R".equals(interface_type)) ){
	    			hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_eaiInoPartlDstcd","2"));//EAI 내외부구분코드
	    		}else {
	    			hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_eaiInoPartlDstcd","1"));//EAI 내외부구분코드
	    		}
    		}
    		hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_cmpxTranDmndDstcd"," "));//복합거래요청구분코드
    		hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_sysOperEvirnDstcd","D"));//시스템운영환경구분코드
    		hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_cnclDstcd","0"));//취소구분코드
    		hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_inoPartlDstcd",attrinfo.getAttributeValue(EAI_SYS_DSTCD)));//내외부구분코드
    		hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_chnlDstcd","06"));//채널구분코드
    		hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_mdiaDstcd","00"));//매체구분코드
    		hs05s.add(makeRowHs05(bzwkSvcKeyName, "COMMON_bnkCd","004"));//은행코드
    		
    		hs04.put("hs05", hs05s);
    		
    		results.add(hs04);
    		
    	}
    	return results;
	}
    public static List<String[]> makeFr04(Element inter,Map<String,String> src) throws Exception{
    	ArrayList<String[]> list = new ArrayList<String[]>();
    	//소스 어댑터가 비표준이면 생성  - 취약점소스 수정 2020.08.26
    	if (src != null && (KBSTANDARD.equals(src.get("ADPTRMSGPTRNCD")))){
    		return list;
    	}
    	Element exthe01info = inter.getChild(MSGINFO);
    	for(int i=1;i<=3;i++){
    		String start = exthe01info.getAttributeValue(MSG_FLD_START_SITU_VAL+i);
    		String len = exthe01info.getAttributeValue(MSG_FLD_LEN+i);
    		
    		//숫자 체크
	    	if (start != null && !"".equals(start) && len != null && !"".equals(len)){
	    		try{
	    			Integer.parseInt(start);
	    			Integer.parseInt(len);
	    		}catch(Exception e){
	    			continue;
	    		}
	    		list.add(new String[]{start,len});
	    	}
    	}
    	
//    	for(int i=0;i<list.size();i++){
//    		for(int j=0;j<list.size()-i;j++){
//    			String data[] =list.get(j);
//    			result.add(makeRowFr04(src.get("ADPTRBZWKGROUPNAME"), src.get("ADPTRMSGDSTCD"),Integer.toString(i+1),Integer.toString(j+1),data[0],data[1]));
//    		}
//    	}
//    	return result;
    	return list;
    }
	
 
	public static HashMap<String,Object> makeRowFr03(String eaiSvcName, String etractDstcd, int fldPrcssNo, String msgDstcd, String bzwkFldName, String eaiSevrDstcd){
		HashMap<String,Object> fr03 = new HashMap<String,Object>();
		fr03.put("eaiSvcName", eaiSvcName);
		fr03.put("etractDstcd", etractDstcd);
		fr03.put("fldPrcssNo", fldPrcssNo);
		fr03.put("msgDstcd", msgDstcd);
		fr03.put("bzwkFldName", bzwkFldName);
		fr03.put("eaiSevrDstcd", eaiSevrDstcd);
		fr03.put("modfiMgtStusDstcd", " ");
		fr03.put("eaiLastAmndHMS", DateUtil.getDateTimeMilliSecound());
		return fr03;
	}
    public static HashMap<String,Object> makeRowFr04(String adptrBzwkGroupName, String msgDstcd, String groupInorNo, String fldPrcssNo, String msgFldStartSituVal, String msgFldLen){
    	HashMap<String,Object> fr04 = new HashMap<String,Object>();
    	fr04.put("adptrBzwkGroupName", adptrBzwkGroupName);
    	fr04.put("msgDstcd", msgDstcd);
    	fr04.put("ioDstcd", "I");
    	fr04.put("fldPrcssNo", fldPrcssNo);
    	fr04.put("bzwkFldName", "전문종별"+fldPrcssNo);
    	fr04.put("clsName", " ");
    	fr04.put("msgFldStartSituVal", msgFldStartSituVal);
    	fr04.put("msgFldLen", msgFldLen);
    	fr04.put("nomalPrcssCtnt", " ");
    	fr04.put("groupInorNo", groupInorNo);
    	return fr04;
    }
    public static HashMap<String,Object> makeRowHs05(String bzwkSvcKeyName, String columnName, String columnValue){
    	HashMap<String,Object> hs05 = new HashMap<String,Object>();
		hs05.put("bzwkSvcKeyName", bzwkSvcKeyName);//
    	hs05.put("columnName"    , columnName);//
    	hs05.put("columnValue"   , columnValue);//
    	return hs05;
    }
	public static HashMap<String,String> getAttr(Element doc){
		if (doc == null) return  new HashMap<String,String>();
		HashMap<String,String> map = new HashMap<String,String>();
        for(Object obj : doc.getAttributes()){
        	if (obj instanceof Attribute){
        		Attribute attr = (Attribute)obj;
        		map.put(attr.getName(), attr.getValue());
        	}
        }
		return map;
	}

	public static InputStream StringToStream(String s){
		ByteArrayInputStream buffer = new ByteArrayInputStream(s.getBytes());
		return buffer;
	}
	public static HashMap<String,Object> parseDelete(String data) throws Exception{
		HashMap<String,Object> map = new HashMap<String,Object>();
    	InputStream is = null;
    	try { 
    		is = StringToStream(data);
			SAXBuilder builder = new SAXBuilder();
	        Document doc = builder.build(is);
	
	        Element delete = doc.getRootElement();
	        HashMap<String,String> deleteInfo = getAttr(delete.getChild(DELETE_INFO));
	        String modid = deleteInfo.get("modid");
	        
	        HashMap<String,String> inter = new HashMap<String,String>();
	        HashMap<String,String> interfaceInfo = getAttr(delete.getChild(INTERFACE));
	        
	        inter.put("eaiSvcName", interfaceInfo.get(ID));
	        inter.put("mmiIfId", interfaceInfo.get(MMI_IF_ID));
	        inter.put("userId"    , modid);
	        
	        
	        List<HashMap<String,String>> formats = new ArrayList<HashMap<String,String>>();
	        for(Object item : delete.getChildren(FORMAT)){
	        	HashMap<String,String> m = getAttr((Element)item);
	        	String id = m.get(ID).substring(2);
	        	String mmi_io_id = m.get(MMI_IO_ID);
	        	formats.add(new HashMap(){{put("loutName",id);put("userId",modid);put("mmiIoId",mmi_io_id);}});
	        }
	        
	        map.put("interface", inter);
	        map.put("formats", formats);
	        
		}catch(Exception e){
			throw e;
    	}finally{
    		if (is != null){try{is.close();}catch(Exception e ){}}
    	}
		
		return map;
	}
	public static String parseVerInfo(String ver){
		String ret = "";
		int verLen = ver.length();
		int zeroCnt = 5-verLen;	//verInfo Default -> 00000 
		for(int i=0; i<zeroCnt; i++){
			ret +="0";
		}
		ret +=ver;
		return ret;
	}
}
class GroupVo{
	private String parent;
	private int index;
	private int depth;
	public GroupVo(String parent,int index,int depth){
		this.parent = parent;
		this.index = index;
		this.depth = depth;
	}
	public String getParent() {
		return parent;
	}
	public int getIndex() {
		return index;
	}
	public int getDepth() {
		return depth;
	}
	
}
