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

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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.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;
//import com.initech.core.util.StringUtil;

public class EIMSParser implements EIMSParserKey {
	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 응답 허용안함   -- EIMS 에서 넘어올때는 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("EIMS 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
						}
						//하나캐피탈 POC수용을 위해 제거
//						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("EIMS 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
						}
						//하나캐피탈 POC수용을 위해 제거
//						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("EIMS 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
							}					
							//하나캐피탈 POC수용을 위해 제거
//							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("EIMS 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
							}		
							//하나캐피탈 POC수용을 위해 제거
//							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("EIMS 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
							}					
							//하나캐피탈 POC수용을 위해 제거
//							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("EIMS 배포시 레이아웃("+layout+") 이 배포가 안됐습니다.변환매핑("+(String)transform.get("cnvsnName")+") 에서 안쓰는 레이아웃인지 확인 하세요.");
							}			
							//하나캐피탈 POC수용을 위해 제거
//							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, HashMap options) 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), options));
	        result.put("he02", makeHe02(inter,adapters.get(TGT),adapters.get(RES_SRC),options));
	        //요청 어댑터가 표준이 나닐경우 실행해야됨
	        if(STANDARD.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);
    	//attrinfo 관련 validation
        result = getAttr(inter.getChild(ATTRINFO));
        if (result != null && result.size() > 0){
	        makeValidation(INTF_TYPE,result.get(INTF_TYPE),new String[]{"S","R"});
	        makeValidation(INF_DST_CD,result.get(INF_DST_CD),new String[]{"M","U","E","F","P","O"});
	        //makeValidation(ORGN_TYPE,result.get(ORGN_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 라우팅명이 없습니다.");
        	}
        	
        }

        //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){
    		if (!org.apache.commons.lang3.StringUtils.startsWith(value, "ISO8583")) {
    			throw new Exception("Invalid value for "+name+".( "+value +" ) . The list of valid values is ( "+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 );
		return makeRowFr03(eaiSvcName,keyType, Integer.parseInt(value), msgDstcd, fullPath, 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){
    			if ("".equals(findPath)) {
    				findPath = findPath + "/*[@layoutId='"+path+"']";
    			}else {
    				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, String userId)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 변경
	        //EAI_FMTST0200100EAI_REQ
	        String cnvsnName = format.getAttributeValue(ID);
	        String desc = format.getAttributeValue(DESC);
	        
	        //서버구분코드가 FM에 있을경우에 FM을 따름 
	        String fmEaiSevrDstcd = format.getAttributeValue(EIMSParserKey.INF_DST_CD);
	        if (StringUtils.isEmpty(fmEaiSevrDstcd) ){
	        	fmEaiSevrDstcd = new String(eaiSevrDstcd);
	        }
	        
	        Element inputMap = format.getChild(MAPPING);
	        String srcLayoutName = inputMap.getAttributeValue(FROM);
	        String tgtLayoutName = inputMap.getAttributeValue(TO);
	        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 id = fld.getAttributeValue(ID);
	        	String link = fld.getAttributeValue(LINK);
	        	String def = fld.getAttributeValue(DEFAULT);
	        	String seq = fld.getAttributeValue(SEQ);
	        	HashMap<String,String> mapping = new HashMap<String,String>();
	        	mapping.put("cnvsnName", cnvsnName);
	        	mapping.put("cnvsnRsultItemPathName", id);
	        	mapping.put("cnvsnCmdName", link);
	        	mapping.put("cnvsnItemBascVal", def);
	        	
	        	if (StringUtils.isEmpty(seq)){
	        		mapping.put("cnvsnItemSerno", "9999");
	        	}else{
	        		mapping.put("cnvsnItemSerno", seq);
	        	}
	        	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)));
	        result.put("author", userId);
	        
	        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(MSG_TYPE);
	        if( "ASCII".equals(msgType) ) {
	        	msgType = "BYTES";
	        } else if( "VASCII".equals(msgType) ) {
	        	msgType = "VBYTES";
	        }
	        String layoutName = format.getAttributeValue(LAYOUT_ID);
	
	        //서버구분코드가 FD에 있을경우에 FD를 따름 
	        String fdEaiSevrDstcd = format.getAttributeValue(EIMSParserKey.INF_DST_CD);
	        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)));
	        vo.put("author",  format.getAttributeValue(AUTHOR));
	        
			// 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){
			e.printStackTrace();
			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()) ) {
            	node = Item.NODE_GROUP;
            } else if(GRID.equals(el.getName())) {
            	node = Item.NODE_GROUP;
            } else if(FLD.equals(el.getName())) {
            	node = Item.NODE_FIELD;
            } else if(ATTR.equals(el.getName())) {
            	node = Item.NODE_ATTR;
            	if ("JSON".equals(msgType) || "UJSON".equals(msgType)){
            		throw new Exception(el.getName()+" is a layout NODE type not supported by "+msgType+"."+el.getAttributeValue(ID));
            	}
            } else {
            	throw new Exception("Layout NODE type("+el.getName()+") not supported."+ el.getAttributeValue(ID));
            }
            
            item.put("loutItemNodePtrnIDName",node);
            
            int loutType = Types.TYPE_UNKNOWN;

            if( GRID.equals(el.getName()) || GROUP.equals(el.getName()) ) {
            	;
            }else{
            	loutType = ConstantUtil.getDataTypeId(el.getAttributeValue(TYPE).toUpperCase(), msgType);
            }
            
            item.put("loutItemPtrnIDName",loutType);
            item.put("loutItemPathName"  ,"");
            //item.put("loutItemLenCnt"    ,StringUtil.isNullEmpty(el.getAttributeValue(LEN)) ? 0 : Integer.parseInt(el.getAttributeValue(LEN)));
            item.put("loutItemLenCnt"    ,StringUtils.isEmpty(el.getAttributeValue(LEN)) ? 0 : Integer.parseInt(el.getAttributeValue(LEN)));
            item.put("loutItemRefInfo"   ,""); //
            
            String rowcount = el.getAttributeValue(COUNT);
            if (!StringUtils.isEmpty(rowcount)){
            	boolean isHangle = false;
            	String findId = "";
            	for(Element findName : items){
            		String findData = "";
            		if (isHangle) {//rowcount가 한글명일경우
            			findData = findName.getAttributeValue(DESC);
            		}else {//rowcount가 영문일경우
            			findData = findName.getAttributeValue(ID);
            		}
            		if (findData.equals(rowcount)){
            			findId = findName.getAttributeValue(ID);
            		}
            	}            	
            	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);
            if (occurNoitm == null) occurNoitm ="";
            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(COUNT)) ? 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(COUNT)) ) {            		
                	} 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); // 레이아웃항목최소발생건수
            
            String defaultVal = null;
            String mask       = el.getAttributeValue("mask");// [Y/N/ ]
            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/ ]
            }
            
            if( "Y".equals(mask) ) { 
            	item.put("loutItemMaskLength",Integer.parseInt(el.getAttributeValue("maskLength")));
            	item.put("loutItemMaskOffset",Integer.parseInt(el.getAttributeValue("maskOffset")));
            } else {
                item.put("loutItemMaskLength",0); 
            }
            
            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",StringUtils.isEmpty(el.getAttributeValue(SCALE)) ? 0 : Integer.parseInt(el.getAttributeValue(SCALE))); // 소수점길이 META에서 "" 이면 "" 으로 표현함/ 
            
            String dataType = "";
            if( el.getAttributeValue(TYPE) == null ||  "".equals(el.getAttributeValue(TYPE))) {            	
            } else {
            	dataType = el.getAttributeValue(TYPE);
            }            
            item.put("loutItemRefPtrnIDName",dataType); // 데이터타입
            item.put("multiLang",""); 

            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(MSG_TYPE,result.get(MSG_TYPE),
	    			new String[]{ "ASCII", "COMBYTES", "VBYTES","BYTES"
	    					    , "EBCDIC", "COMEBCDIC","VEBCDIC"
	    					    , "VFIELD" , "ODDBYTES", "DELIMITER"
	    					    //, "VXML"  as-is vfield 의 상대 tobe에서는 Vfield 가  정상적으로 동작
	    					    , "JSON","UJSON"
	    					    ,"XML"
	    					    ,"ISO8583"
	    					    });
	    	//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, Map<String,String> options) 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_COM_TYPE))
        		&& "S".equals(attrinfo.getAttributeValue(TRG_COM_TYPE))
        		&& "R".equals(attrinfo.getAttributeValue(INTF_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_COM_TYPE))?"ASYN":"SYNC" ); // 서비스동기사용구분코드                      
        }
        
        he01.put("eaiSvcName"                 , exthe01info.getAttributeValue(SYS_SVC_NAME)         );// EAI서비스명
        he01.put("eaiBzwkDstcd"               , attrinfo.getAttributeValue(APP_CD)                  ); // EAI업무구분코드        
        he01.put("svcHMSEonot"                , "0"                                                 ); // 서비스시각유무   
        he01.put("svcPrcesDsticName"          , "SINGLE"                                            ); // 서비스프로세스구분명
        he01.put("internalExternalDvcd"       , attrinfo.getAttributeValue(INTERNAL_EXTERNAL_DVCD)  ); // 내외부 구분코드
        
        //fc 값 sample      :  BASEFC, BASEFC001, B2BFC, B2BFC001, C2RFC, C2RFC001 ...
        //fcBody 값 sample  : BASEFC, B2BFC, C2RFC ...
        //fcIndex 값 sample : "", 001, 002 ...
        
        String fc = exthe01info.getAttributeValue(FLOW_CTRL_ROUT_NAME) ;
        
        String fcBody = "";
        String fcIndex = "";
		Matcher matcher = Pattern.compile("([A-Z0-9]*FC)([0-9]{3})?").matcher(fc);
		if (matcher.find()) {
			fcBody = matcher.group(1);
			fcIndex = matcher.group(2);
			fcIndex = fcIndex == null ? "":fcIndex;
		}
        
        //추가로직 - B2B 관련 
        String b2b = options.get(EIMSParserKey.FC_B2B);
        if (StringUtils.isNotBlank(b2b)){
        	fcBody = "B2BFC";
        }
        
        //추가로직 - Queue 관련
        String queue = options.get(EIMSParserKey.FC_QUEUE);
        if (StringUtils.isNotBlank(queue)){
        	fcIndex = queue;
        }
        
        he01.put("flowCtrlRoutName"           , fcBody + fcIndex  ); // 흐름통제라우팅명
        
        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(INF_NM)              ); // EAI서비스명
        he01.put("eaiSevrDstcd"               , attrinfo.getAttributeValue(INF_DST_CD)           );//EAI서버 구분코드내용
        he01.put("modfiMgtStusDstcd"          , " ");//변경괄리상태구분코드내용
        he01.put("eaiLastAmndYMS"             , DateUtil.getDateTimeMilliSecound());//EAI최종수정일시
        he01.put("eaiGroupCoCd"               , ""                                               );//EAI그룹회사코드내용
        he01.put("tranType"                   , "R"                                                 );//거래처리구분코드내용
        he01.put("useYn"                      , "1"                                                 );//사용여부
        he01.put("verInfo"					  , parseVerInfo(attrinfo.getAttributeValue(VER))			);//서비스코드 버전정보	
        
        //20210401 추가
        he01.put("txId"                       , attrinfo.getAttributeValue(RECV_TRAN_CD)            );//거래id
        String refKey = StringUtils.trim(attrinfo.getAttributeValue(INF_DSTN_KEY1)) 
        		      + StringUtils.trim(attrinfo.getAttributeValue(INF_DSTN_KEY2)) 
        		      + StringUtils.trim(attrinfo.getAttributeValue(INF_DSTN_KEY3));
        he01.put("refKey"                     , refKey                                              );//참조키
        he01.put("extBizCd"                   , attrinfo.getAttributeValue(EXT_BIZ_CD)              );//대외업무구분코드
        he01.put("author"                     , attrinfo.getAttributeValue(AUTHOR)                  );//담당자Id
        
		return he01;
		
	}
	public static List<HashMap<String,Object>> makeHe02(Element inter,Map<String,String> trg, Map<String,String> resSrc, Map<String,String> options) 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_COM_TYPE))
        		&& "S".equals(attrinfo.getAttributeValue(TRG_COM_TYPE))
        		&& "R".equals(attrinfo.getAttributeValue(INTF_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_COM_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(SYS_SVC_NAME) );// EAI서비스명
        he02.put("svcPrcssNo"               , 1                            ); // 서비스처리번호
        //he02.put("psvSysBzwkDstcd"          , exthe01info.getAttributeValue(SYS_SVC_NAME).substring(0,3)       ); // 수동시스템업무구분코드          
        he02.put("psvSysBzwkDstcd"          , StringUtils.trim(attrinfo.getAttributeValue(TRG_SYS_CD))); // 수동시스템업무구분코드
    	he02.put("psvSysIDName"             , "EAIDOM"                     ); // 수동시스템ID명         
    	
    	he02.put("psvSysSvcDsticName"       , " "                          ); // 수동시스템서비스구분명      
    	
    	
        String failover = options.get(EIMSParserKey.FC_FAILOVER);
        if (StringUtils.isNotBlank(failover)){
        	he02.put("flovrYn"                  , failover                          ); // 장애극복여부            
        }else{
        	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                            ); // 다음서비스처리번호     
    	int timeout = 60;
    	try {
    		timeout = Integer.parseInt(attrinfo.getAttributeValue(TIMEOUT)); 
    	}catch(Exception e) {
    	}
    	he02.put("toutVal"                  , timeout );// 타임아웃값          
    	he02.put("cmpenSvcPrcssDsticName"   , " "                          ); // 보상서비스처리구분명                 
    	
    	he02.put("supplDelYn"               , "0"                          ); // 추가삭제여부         
    	he02.put("hdrCtrlDstcd"             , "01"                         ); // 헤더제어구분코드  
    	he02.put("hdrRefClsName"            , " "                          ); // 헤더참조클래스명  
    	he02.put("restOption"               , restOptionData               ); // rest추가 정보
    	
    	String timeoutCd = attrinfo.getAttributeValue(TIMEOUT_CD);
    	if (timeoutCd == null){
    		timeoutCd ="";
    	}
    	he02.put("timeoutCode"              , timeoutCd                    ); // 타임아웃코드
    	
    	
    	he02s.add(he02);
    	
    	if (resSrc != null){//ASYNC SYNC일경우
    		he02 = new HashMap<String,Object>();
	    	he02.put("eaiSvcName"               , exthe01info.getAttributeValue(SYS_SVC_NAME) );// EAI서비스명
	    	he02.put("svcPrcssNo"               , 2                          ); // 서비스처리번호
	    	he02.put("psvIntfacDsticName"       , "ASYN"                     ); // 수동인터페이스구분명        
	    	//he02.put("psvSysBzwkDstcd"          , exthe01info.getAttributeValue(SYS_SVC_NAME).substring(0,3)       ); // 수동시스템업무구분코드          
	    	he02.put("psvSysBzwkDstcd"          , StringUtils.trim(attrinfo.getAttributeValue(TRG_SYS_CD))); // 수동시스템업무구분코드
	    	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추가 정보
	    	he02.put("timeoutCode"              , ""                        );  // 타임아웃코드
        
	    	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(ORGN_TYPE);            //1:취급(당발) 2:개설(타발) 대외거래만 들어옮
		String interface_type =attrinfo.getAttributeValue(INTF_TYPE);;//S:요청 R:응답
        
    	//인터페이스 1개에 내부표준 전문 여러개일 경우 고려
		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(INF_DST_CD);
    		hs04.put("bzwkSvcKeyName"   , bzwkSvcKeyName);//업무서비스키명
    		hs04.put("eaiSvcName"       , exthe01info.getAttributeValue(SYS_SVC_NAME));//EAI서비스명
    		hs04.put("eaiTranName"      , attrinfo.getAttributeValue(INF_ID));//EAI거래명
    		hs04.put("eaiSendRecv"      , attrinfo.getAttributeValue(INTF_TYPE));//요청/응답
    		//hs04.put("eaiDirection"     , exthe01info.getAttributeValue(SYS_SVC_NAME).substring(exthe01info.getAttributeValue(SYS_SVC_NAME).length()-1));//거래방향
    		hs04.put("eaiDirection"     , attrinfo.getAttributeValue(INTERNAL_EXTERNAL_DVCD));//거래방향
    		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>>();
    		hs05s.add(makeRowHs05(bzwkSvcKeyName, "systemHeader.INTF_ID",attrinfo.getAttributeValue(INF_ID)));//INTF_ID 인터페이스ID
    		if ("S".equals(attrinfo.getAttributeValue(INTF_TYPE))){ //intfType = S:요청,R:응답  :: DB = I:요청,O:응답  
    			hs05s.add(makeRowHs05(bzwkSvcKeyName, "systemHeader.IPOP_DVSN_CD","I"));//IPOP_DVSN_CD 입출력구분코드
    		}else {
    			hs05s.add(makeRowHs05(bzwkSvcKeyName, "systemHeader.IPOP_DVSN_CD","O"));//IPOP_DVSN_CD 입출력구분코드
    		}
    		hs05s.add(makeRowHs05(bzwkSvcKeyName, "systemHeader.DLNG_ID",attrinfo.getAttributeValue(RECV_TRAN_CD)));//TX_ID 거래ID
    		for(String key : exths01infoMap.keySet()){
    	    	if (!(key.startsWith("systemHeader") || key.startsWith("commonHeader") || key.startsWith("dataHeader")) ){
    	    		continue;
    	    	}
    			hs05s.add(makeRowHs05(bzwkSvcKeyName, key,exths01infoMap.get(key)));
    		}
    		if ("1".equals(attrinfo.getAttributeValue(ORGN_TYPE))) {//orgnType = 1:당발,2:타발  :: DB = D:당발,T:타발  
    			hs05s.add(makeRowHs05(bzwkSvcKeyName, "dataHeader.externalInfo.OUTTX_OIWD_DVSN_CD","D"));//OUTTX_OIWD_DVSN_CD 당타발구분코드
    		}else {
    			hs05s.add(makeRowHs05(bzwkSvcKeyName, "dataHeader.externalInfo.OUTTX_OIWD_DVSN_CD","T"));//OUTTX_OIWD_DVSN_CD 당타발구분코드
    		}
    		
    		//인터페이스 실행 타입(S:요청인터페이스, R:정상응답인터페이스, E:오류응답인터페이스) 
    		String infTranType = attrinfo.getAttributeValue(INF_TRAN_TYPE);
    		if (StringUtils.isEmpty(infTranType)){
    			hs05s.add(makeRowHs05(bzwkSvcKeyName, "dataHeader.externalInfo.OTWD_RSPNS_NORM_YN",""));//OTWD_RSPNS_NORM_YN 당발응답정상여부
    		}else{
    			if ("S".equals(infTranType)) {//orgnType = 1:당발,2:타발  :: DB = D:당발,T:타발  
        			hs05s.add(makeRowHs05(bzwkSvcKeyName, "dataHeader.externalInfo.OTWD_RSPNS_NORM_YN",""));//OTWD_RSPNS_NORM_YN 당발응답정상여부
    			}else if ("R".equals(infTranType)) {
        			hs05s.add(makeRowHs05(bzwkSvcKeyName, "dataHeader.externalInfo.OTWD_RSPNS_NORM_YN","Y"));//OTWD_RSPNS_NORM_YN 당발응답정상여부
    			}else if ("E".equals(infTranType)) {
        			hs05s.add(makeRowHs05(bzwkSvcKeyName, "dataHeader.externalInfo.OTWD_RSPNS_NORM_YN","N"));//OTWD_RSPNS_NORM_YN 당발응답정상여부
    			}
    		}
    		
    		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 && (STANDARD.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 =null;
		try {
			buffer = new ByteArrayInputStream(s.getBytes("UTF-8"));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		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(INF_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 id = m.get(ID);
	        	String mmi_io_id = m.get(EIMS_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;
	}
	public static String parseDeleteLayoutName(String data)throws Exception{
		
    	InputStream is = null;
    	try { 
    		is = StringToStream(data);
			SAXBuilder builder = new SAXBuilder();
	        Document doc = builder.build(is);
	
	        Element format = doc.getRootElement();
	        validationLayout(format);
	        

	        String layoutName = format.getAttributeValue(LAYOUT_ID);
	        String delYn = format.getAttributeValue(DEL_YN);
	        
	        if (delYn != null && "Y".equals(delYn)){
	        	return layoutName;
	        }else{
	        	return null;
	        }
	
		}catch(Exception e){
			e.printStackTrace();
			throw new Exception("layout parsing error "+e.getMessage(),e);
    	}finally{
    		if (is != null){try{is.close();}catch(Exception e ){}}
    	}
		
	}
	public static String parseDeleteTransformName(String data)throws Exception{
		InputStream is = null;
		try { 
			is = StringToStream(data);
			SAXBuilder builder = new SAXBuilder();
			Document doc = builder.build(is);
			
			Element format = doc.getRootElement();
			
			return  format.getAttributeValue(ID);
		}catch(Exception e){
			e.printStackTrace();
			throw new Exception("layout parsing error "+e.getMessage(),e);
		}finally{
			if (is != null){try{is.close();}catch(Exception e ){}}
		}
		
	}
    public static List<String> parseBzwkSvcKeyNames(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();
    		List<Element> exths01infos = inter.getChildren(EXTHS01INFO);
        	//인터페이스 1개에 내부표준 전문 여러개일 경우 고려
    		for(Element exths01info : exths01infos){
        		String bzwkSvcKeyName = exths01info.getAttributeValue(BZWK_SVC_KEY_NAME);
        		if (StringUtils.isEmpty(bzwkSvcKeyName)){
        			continue;
        		}
        		result.add(bzwkSvcKeyName);
    		}
    	}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 String getResourceName(String xmlstring, String resourceType) {
		
		try {
			SAXBuilder builder = new SAXBuilder();
	        Document doc = builder.build(StringToStream(xmlstring));

	        Element format = doc.getRootElement();
			
			if("LAYOUT".equals(resourceType)) {
				return format.getAttribute("layoutId").getValue();
			} else if ("TRANSFORM".equals(resourceType)) {
				return format.getAttribute("id").getValue();
			} else {
				return "";
			}
		} catch (Exception e) {
			return resourceType + "_CANNOTPARSE_RESOURCE";
		}
		
	}
}
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;
	}
	
}
