package com.eactive.eai.transformer.transform;

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

import com.eactive.eai.transformer.TransformerException;
import com.eactive.eai.transformer.engine.Parser;
import com.eactive.eai.transformer.layout.Item;
import com.eactive.eai.transformer.layout.Layout;
import com.eactive.eai.transformer.layout.Types;
import com.eactive.eai.transformer.message.InvalidAccessException;
import com.eactive.eai.transformer.message.Message;
import com.eactive.eai.transformer.util.Logger;
import com.eactive.eai.transformer.util.MemoryLogger;

public class TransformValidator {
    private static Logger logger = Logger.getLogger("transformer");
    
    private TransformValidator() {
    	super();
    }
    
    public static void validate(Map transformMap) {    	
        for (Iterator iter = transformMap.values().iterator(); iter.hasNext();) {
        	validate((Transform) iter.next(), false);
        }
	}
    
    
    public static void trasnFormValidate(Map transformMap, Map<String,Object> transFuncMap) {    	
        for (Iterator iter = transformMap.values().iterator(); iter.hasNext();) {
        	trasnFormValidate((Transform) iter.next(), transFuncMap);
        }
	}
    
    /**
     * validate transform expression
     */
    public static void validate(Transform transform, boolean isBatch) {
		List errors = new ArrayList();
    	
    	try {
    		if (!transform.getTransformItemList().iterator().hasNext()) {
//    			throw new TransformerException("source layout does not exist");
    			throw new TransformerException("전문레이아웃 매핑에 원천 레이아웃이 없습니다.");
    		}    		

    		if (transform.getTargetLayout() == null) {
//    			throw new TransformerException("target layout does not exist");
    			throw new TransformerException("전문레이아웃 매핑에 타겟 레이아웃이 없습니다.");
    		}    		
    		
        	for (Iterator iter = transform.getTransformItemList().iterator(); iter.hasNext(); ) {
        		TransformItem transformItem = (TransformItem) iter.next();
        		try {
        			if(transformItem == null) {
        				throw new Exception("transformItem is null");
        			}
        			else {
        				validate(transform, transformItem, isBatch);
        			}
        		} catch(Exception e) {
        			errors.add(e.getMessage());
        		}
        	}
        	
        	if (errors.size() > 0) {
	    		StringBuilder sb = new StringBuilder();
	    		for (Iterator 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("TransformManager | 전문레이아웃 매핑 오류 : ");
			sb.append(transform.getName());
			sb.append(" (원천레이아웃 = ");
			for (Iterator iter = transform.getSourceLayoutNames(); iter.hasNext(); ) {
	    		sb.append(iter.next());
	    		sb.append(",");
	    	}
			if (transform.getTargetLayout() != null) {
				sb.append(" | 타겟레이아웃 = " + transform.getTargetLayout().getName() + ")");
			}
			
			sb.append(" - \n");
			sb.append(e.getMessage());
			logger.warn(sb.toString());
			MemoryLogger.error("<WARN> " + sb.toString());
		}
    }

    private static void validate(Transform transform, TransformItem transformItem, boolean isBatch) {
		if ("".equals(transformItem.getInstruction().trim())) {
			return;
		}
		
        /**
         * [1] validate all transform expressions 
         */
        Parser parser = new Parser();
        
		try {
			parser.parse(transformItem.getInstruction());
			String[] symbols = parser.getSymbols();
			for (int i=0; i<symbols.length; i++) {
				if (symbols[i].equals("e") || symbols[i].equals("pi")) {
					continue;
				}
				
		        /**
		         * 
		         */
				Item item = null;
				for (Iterator iter = transform.getSourceLayouts(); iter.hasNext();) {
					Layout layout = (Layout) iter.next();
					if (isBatch) {
						layout.init();
					}
					Message source = (Message) layout.getRootItem();
					
                    if (symbols[i].equals("DEFAULT_VALUE") && (transformItem.getDefaultValue() != null)) {
                        // ignore
                    } else {
                    	String itemPath = symbols[i].replaceAll("\\[(\\*|[0-9]+)\\]", "").replaceAll("\\.", "[-1].") + "[-1]";

                    	if (symbols[i].startsWith(source.getName())) {
                        	item = ((Item) source).getItem(itemPath, true);
                        } else {
                        	if (transform.getSourceLayoutCount() == 1) {
                    			item = source.getItem(source.getName() + Types.FIELD_SEPARATOR + itemPath, true);
                        	} else {
                        		continue;
                        	}
                        }
                    	
                        if (item != null) {
            				break;
                        }
                    }
                }
				
                if (item == null && !symbols[i].equals("DEFAULT_VALUE")) {
    				throw new TransformerException("매핑오류 : 소스 레이아웃에 없는 항목(" + symbols[i]+") 입니다.");
                }
			}
		} catch(Exception e) {
			StringBuilder sb = new StringBuilder();
			sb.append("    * ");			
			sb.append(transformItem.getResultItemPath());
			sb.append(" = ");
			sb.append(transformItem.getInstruction());
			sb.append(" - " + e.getMessage());
			throw new TransformerException(sb.toString());
		}
		
        /**
         * [2] validate all transform result 
         */
		try {
			String originalItemPath = transformItem.getResultItemPath().trim();
        	String itemPath = originalItemPath.replaceAll("\\[(\\*|[0-9]+)\\]", "").replaceAll("\\.", "[-1].") + "[-1]";
			Message target = (Message) transform.getTargetLayout().getRootItem();
			if (isBatch) {
				target.getLayout().init();
			}
			Item item = null;
        	if (itemPath.startsWith(target.getName())) {
            	item = ((Item) target).getItem(itemPath, true);
            } else {
    			item = target.getItem(target.getName() + Types.FIELD_SEPARATOR + itemPath, true);
            }
        	
            if (item == null) {
//            	throw new TransformerException("(in target) layout item does not exist in message : " + originalItemPath);
            	throw new TransformerException("매핑오류 : 타겟 레이아웃에 없는 항목(" + originalItemPath + ")입니다.");
            }
		} catch(Exception e) {
			StringBuilder sb = new StringBuilder();
			sb.append("    * ");			
			sb.append(transformItem.getResultItemPath());
			sb.append("=");
			sb.append(transformItem.getInstruction());
			sb.append(" - " + e.getMessage());
			throw new TransformerException(sb.toString());
		}		
    }   
    
    
    /**
     * validate transform expression
     */
    public static void trasnFormValidate(Transform transform, Map<String,Object>  transFuncMap) {
		List errors = new ArrayList();
    	
    	try {
    		if (!transform.getTransformItemList().iterator().hasNext()) {
//    			throw new TransformerException("source layout does not exist");
    			throw new TransformerException("전문레이아웃 매핑에 원천 레이아웃이 없습니다.");
    		}    		

    		if (transform.getTargetLayout() == null) {
//    			throw new TransformerException("target layout does not exist");
    			throw new TransformerException("전문레이아웃 매핑에 타겟 레이아웃이 없습니다.");
    		}    		
    		
        	for (Iterator iter = transform.getTransformItemList().iterator(); iter.hasNext(); ) {
        		TransformItem transformItem = (TransformItem) iter.next();
        		try {
        			trasnFormValidate(transform, transformItem, transFuncMap);
        		} catch(Exception e) {
        			errors.add(e.getMessage());
        		}
        	}
        	
        	if (errors.size() > 0) {
	    		StringBuilder sb = new StringBuilder();
	    		for (Iterator 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("TransformManager | invalid transform rules : ");
//			sb.append(transform.getName());
//			sb.append(" (sources = ");
//			for (Iterator iter = transform.getSourceLayoutNames(); iter.hasNext(); ) {
//	    		sb.append(iter.next());
//	    		sb.append(",");
//	    	}
//			if (transform.getTargetLayout() != null) {
//				sb.append(" | target = " + transform.getTargetLayout().getName() + ")");
//			}
			
			sb.append("TransformManager | 전문레이아웃 매핑 오류 : ");
			sb.append(transform.getName());
			sb.append(" (원천레이아웃 = ");
			for (Iterator iter = transform.getSourceLayoutNames(); iter.hasNext(); ) {
	    		sb.append(iter.next());
	    		sb.append(",");
	    	}
			if (transform.getTargetLayout() != null) {
				sb.append(" | 타겟레이아웃 = " + transform.getTargetLayout().getName() + ")");
			}
			
			sb.append(" - \n");
			sb.append(e.getMessage());
			logger.warn(sb.toString());
			MemoryLogger.error("<WARN> " + sb.toString());
		}
    }
    
    
    private static void trasnFormValidate(Transform transform, TransformItem transformItem, Map<String,Object>  transFuncMap) {
  		if ("".equals(transformItem.getInstruction().trim())) {
  			return;
  		}
  		
          /**
           * [1] validate all transform expressions 
           */
          Parser parser = new Parser();

  		try {
  			parser.parse(transformItem.getInstruction());
  			String[] symbols = parser.getSymbols();
  			for (int i=0; i<symbols.length; i++) {
  				
  				// find symbol in function list
  				
  				if(transFuncMap.get(symbols[i]) != null){
  					continue;
  				}
  				
  				if (symbols[i].equals("e") || symbols[i].equals("pi")) {
  					continue;
  				}
  				
  		        /**
  		         * 
  		         */
  				Item item = null;
  				for (Iterator iter = transform.getSourceLayouts(); iter.hasNext();) {
  					Layout layout = (Layout) iter.next();
  					
  					Message source = (Message) layout.getRootItem();

                      if (symbols[i].equals("DEFAULT_VALUE") && (transformItem.getDefaultValue() != null)) {
                          // ignore
                      } else {
                    	  String itemPath = symbols[i].replaceAll("\\[(\\*|[0-9]+)\\]", "").replaceAll("\\.", "[-1].") + "[-1]";
                      	
                    	  if (symbols[i].startsWith(source.getName())) {
						  	item = ((Item) source).getItem(itemPath, true);
                    	  } else {
                    		  if (transform.getSourceLayoutCount() == 1) {
                    			  item = source.getItem(source.getName() + Types.FIELD_SEPARATOR + itemPath, true);
                    		  } else {
                    			  continue;
                    		  }
                    	  }
						  if (item != null) {
							  break;
						  }
                      }
                  }
  				
                  if (item == null && !symbols[i].equals("DEFAULT_VALUE")) {
//      				throw new TransformerException("(in instruction) layout item does not exist in message : " + symbols[i]);
      				throw new TransformerException("매핑오류 : 원천 레이아웃에 없는 항목(" + symbols[i]+")입니다.");
                  }
  			}
  		} catch(Exception e) {
  			StringBuilder sb = new StringBuilder();
  			sb.append("    * ");			
  			sb.append(transformItem.getResultItemPath());
  			sb.append(" = ");
  			sb.append(transformItem.getInstruction());
  			sb.append(" - " + e.getMessage());
  			throw new TransformerException(sb.toString());
  		}
  		
          /**
           * [2] validate all transform result 
           */
  		try {
  			String originalItemPath = transformItem.getResultItemPath().trim();
          	String itemPath = originalItemPath.replaceAll("\\[(\\*|[0-9]+)\\]", "").replaceAll("\\.", "[-1].") + "[-1]";
  			Message target = (Message) transform.getTargetLayout().getRootItem();
  			
  			Item item = null;
          	if (itemPath.startsWith(target.getName())) {
              	item = ((Item) target).getItem(itemPath, true);
              } else {
      			item = target.getItem(target.getName() + Types.FIELD_SEPARATOR + itemPath, true);
              }
          	
              if (item == null) {
//              	throw new TransformerException("(in target) layout item does not exist in message : " + originalItemPath);
              	throw new TransformerException("매핑오류 : 타겟 레이아웃에 없는 항목(" + originalItemPath + ")입니다.");
              }
  		} catch(Exception e) {
  			StringBuilder sb = new StringBuilder();
  			sb.append("    * ");			
  			sb.append(transformItem.getResultItemPath());
  			sb.append("=");
  			sb.append(transformItem.getInstruction());
  			sb.append(" - " + e.getMessage());
  			throw new TransformerException(sb.toString());
  		}		
      }   
}
