package com.eactive.eai.transformer.layout;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.eactive.eai.transformer.TransformerException;
import com.eactive.eai.transformer.message.BytesMessage;
import com.eactive.eai.transformer.message.MessageException;
import com.eactive.eai.transformer.message.XMLMessage;
import com.eactive.eai.transformer.util.Logger;
import com.eactive.eai.transformer.util.MemoryLogger;


public class LayoutValidator {
    private static Logger logger = Logger.getLogger("transformer");
    
    private LayoutValidator() {
    	
    }
    
    public static void validate(Map transformMap) {    	
        for (Iterator iter = transformMap.values().iterator(); iter.hasNext();) {
        	Layout layout = (Layout) iter.next();
        	try {
	        	validate(layout);
    		} catch(Exception e) {
    			StringBuilder sb = new StringBuilder();
    			sb.append("LayoutValidator | invalid layout : ");
    			if(layout != null) {
    				sb.append(layout.getName() + " - \n" + e.getMessage() + "\n" + layout.getRootItem());
    			}
    			else {
    				sb.append(" - \n" + e.getMessage());
    			}
    			
    			logger.warn(sb.toString());
    			MemoryLogger.error(sb.toString());		
    		}
        }
	}
	
    /**
     * validate Layout expression
     */
    public static void validate(Layout layout) {
		List<String> errors = new ArrayList<>();
    	try {
    		HashMap<String, Integer> pathMap = new HashMap<>();
    		String path = "";
        	for (Iterator<Item> iter = layout.getRootItem().fullIterator(); iter.hasNext(); ) {
        		Item Item = iter.next();
        		try {
        			validate(layout, Item);
        		} catch(Exception e) {
        			errors.add(e.getMessage());
        		}
        		
        		path = Item.getItemPath();
        		if(pathMap.get(path) != null) {
    				throw new Exception("거래(입|출)력항목명(영문)이 중복되었습니다 (" + path + ") 일련번호("+ Item.getSeqNo() +")");
    			}
    			else {
    				pathMap.put(path, Item.getSeqNo());
    			}
        	}
        	
        	if (!errors.isEmpty()) {
	    		StringBuilder sb = new StringBuilder();
	    		for (Iterator<String> iter2 = errors.iterator(); iter2.hasNext();) {
	    			sb.append("    " + iter2.next());
	    			if (iter2.hasNext()) {
	    				 sb.append("\n");
	    			}
	    		}
	    		
	        	throw new TransformerException(sb.toString());
        	}
		} catch(Exception e) {
			StringBuilder sb = new StringBuilder();
			sb.append("레이아웃 검증 오류 : ");
			sb.append("\n" + e.getMessage());
			throw new MessageException(sb.toString(), e);
		}
    }

    private static void validate(Layout layout, Item item) {
    	/**
    	 * depth 체크
    	 */
    	if (item.getDepth() <= 0)
    		throw new TransformerException("항목명(" + layout.getName() + "/" + item.getName() + ")의 DEPTH(" + item.getDepth() + ")는 0 보다 커야 함");

    	/**
    	 * node type 체크
    	 * 2014.04.17 VariableXMLMessage 개발에 의한 로직 변경 KSH
    	 * 2020.04.14 XML, UJSON, JSON 모두 가능하도록 변경 (보류)
    	 */
    	if (item.getNodeTypeId() == Item.NODE_ATTR) {
    		if (!(item.getRoot() instanceof XMLMessage) ) {
    			throw new LayoutInitializationException(layout.getLayoutType().getName() +
					", " + layout.getName() + ", " + item.getName() + 
					" | ATTR type node cannot be added to BytesMessage/EbcdicMessage", layout.getName());
    		}
    	}
    	
    	/**
    	 * occType=*|+ 일 경우, occRef missing check
    	 */
    	if (item.getOccType() != null && item.getOccType().matches("\\*|\\+") && item.getRoot() instanceof BytesMessage ) {
    		if (item.getOccRef() == null || "".equals(item.getOccRef().trim())) {
				throw new MessageException(layout.getName() + " - 항목명(" + item.getName() + ")의 반복횟수참조정보 미등록 에러");
    		}
    	}
    	
    	/**
    	 * occRef 의 존재 여부 체크
    	 */
    	if (item.getOccRef() != null && !"".equals(item.getOccRef().trim())) {
    		/**
    		 * layout2 에서 - occRef 에 한글필드명 (description) 을 쓸 경우 처리를 위해
    		 */
    		item.getOccRefItem();
    	} 
    	
    	/**
    	 * FMLMessage 의 경우 Group의 occType = occMin = occMax = 1 이어야 한다. (삭제됨)
    	 */
//    	if (layout.getLayoutType().getName().startsWith("FML")) {
//    		if (item.getNodeTypeId() == Item.NODE_GROUP) {
//    			if ("".equals(item.getOccType()))
//    				item.setOccType("1");	
////    			if (!item.getOccType().equals("1") || item.getOccMin() != 1 || item.getOccMax() != 1)
////    				throw new MessageException(layout.getName() + " - " + item.getName() + " - FMLMessage group item's occType, occMin, occMax must be '1'");
//    		}
//    	}    	

    	/**
    	 * FMLMessage 의 경우 path 값이 반드시 존재해야 한다. (삭제됨)
    	 */
//    	if (layout.getLayoutType().getName().startsWith("FML")) {
//    		if (item.getNodeTypeId() == Item.NODE_FIELD) {
//    			if (item.getPath()==null || "".equals(item.getPath()))
////    				throw new MessageException(layout.getName() + " - " + item.getName() + " - FMLMessage item 'path' must have value");
//    				throw new MessageException(layout.getName() + " - FML 레이아웃의 항목(" + item.getName() + ")은 비고에 'path'를 정의해야 함");
//    		}
//    	}    	
    }   
}
