package com.eactive.eai.transformer.engine;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.eactive.eai.transformer.TransformerException;
import com.eactive.eai.transformer.layout.Item;
import com.eactive.eai.transformer.layout.Layout;
import com.eactive.eai.transformer.layout.LayoutInitializationException;
import com.eactive.eai.transformer.layout.LayoutNotFoundException;
import com.eactive.eai.transformer.layout.Types;
import com.eactive.eai.transformer.message.ISO8583Message;
import com.eactive.eai.transformer.message.InvalidAccessException;
import com.eactive.eai.transformer.message.Message;
import com.eactive.eai.transformer.message.MessageFactory;
import com.eactive.eai.transformer.transform.Transform;
import com.eactive.eai.transformer.transform.TransformItem;
import com.eactive.eai.transformer.transform.TransformManager;
import com.eactive.eai.transformer.util.HexUtil;
import com.eactive.eai.transformer.util.Logger;
import com.eactive.eai.transformer.util.MemoryLogger;
import com.eactive.eai.transformer.util.StringUtil;


/**
 * 변환 룰에 맞춰서 메시지를 변환하는 기능을 제공한다.
 */
public class Transformer {
    private static Logger logger = Logger.getLogger("transformer");
    public static final int INDEX_RESULT = -1;
    public static final int INDEX_QUEUE = -2;
    public static final int SINGLE_MAPPING = -1;
    public static final int DYNAMIC_MAPPING = -2;
  
//  transformLine 함수에서 [*] 형태가 존재할 경우 -> 각 item 별 실행
    static char[] findChars = {'(', '+', ' '};
    private static boolean isSimpleInstruction(String message) {
    	if(message.charAt(message.length()-1) == ')') return false;
    	for(int i=0; i<findChars.length; i++) {
			if(message.indexOf(findChars[i]) > -1) {
				return false;
			}
		}
		return true;
	}
    
    Transformer() {
    }

    private static final char[] FUNCTION_SEPARATORS = { ' ', ',' };
    /**
     * Column 구분자 '[*]'를 index 값으로 변경해주는 메소드
     *  함수구분자 ' ', 혹은 ',' 별 첫번째 * 만 변경한다.
     *
     * 예제>
     * 호줄 : replaceAsteriskToIndex("(abc[*].d*ef[*].ghi*) + (*jk[*].lm[*].no)", 12);
     * 결과 : (abc[12].d*ef[*].ghi*) + (*jk[12].lm[*].no)
     *
     * @param src 대상 문자열
     * @param index 변경할 index 값
     * @return 결과값
     */
    private static String replaceAsteriskToIndex(String src, int idx) {
        String index = Integer.toString(idx);
        char[] orgChars = src.toCharArray();
        char[] settingChars = index.toCharArray();
        StringBuilder sb = new StringBuilder(orgChars.length);

        boolean doChange = true;
        boolean isChanged = false;

        for(int i = 0; i < orgChars.length;i++) {
            char c = orgChars[i];
            if (doChange && c == '*'
                    && i - 1 > -1 && i + 1 < orgChars.length
                    && orgChars[i - 1] == '[' && orgChars[i + 1] == ']' ) {
                isChanged = true;
                doChange = false;

                for (char settingChar : settingChars) {
                    sb.append(settingChar);
                }
            } else {
                sb.append(c);
            }
            for(char functionSeparator : FUNCTION_SEPARATORS){
                if(c == functionSeparator) {
                    doChange = true;
                    break;
                }
            }
        }

        if(!isChanged) {
//        	현재 아래 예외처리를 통해 Grid -> Grid만 되도록 cnvsnrsultitempathname 안에 path에 [*]있는지 체크하고 예외 발생.
//        	Grid to Group 맵핑 해야할 경우가 생겨, 예외 주석처리.
//        	throw new NullPointerException("변환인자 '[*]' 가 존재하지 않습니다. - "+src);
            logger.debug("타겟 변환인자에 '[*]' 가 존재하지 않습니다. - "+src); 
        }
        return sb.toString();
    }
    
    /**
     * 변환 메소드 (변환 결과 메시지는 자동 생성).
     * transformName을 이용해서 어떠한 변환룰을 적용할지 결정됨.
     * TransformOption이 null일 경우 기본값을 사용함.
     * 운본 메시지를 생성하지 않고 데이터만 전달, 내부적으로 Message를 생성해서 사용됨.
     * @see Message
     * @see TransformOption
     */
    public TransformResult transform(String transformName,
        Object[] sourceDatas, TransformOption option)
        throws TransformerException {
        Transform tr = TransformManager.getManager().getTransform(transformName);
        Message[] sourceMessages = new Message[sourceDatas.length];

        try {
            for (int i = 0; i < sourceDatas.length; i++) {
                Layout layout = tr.getSourceLayout(i);
                sourceMessages[i] = MessageFactory.getFactory().getMessage(layout.getName());
                sourceMessages[i].setData(sourceDatas[i]);
            }
        } catch (Exception e) {
            throw new TransformException("error when set data. - " + e.getMessage(), 
                transformName, 
                null, 
                sourceMessages, 
                option, e);
        }

        return transform(transformName, null, sourceMessages, option);
    }

    /**
     * 변환 메소드 (변환 결과 메시지는 자동 생성).
     * transformName을 이용해서 어떠한 변환룰을 적용할지 결정됨.
     * TransformOption이 null일 경우 기본값을 사용함.
     * @see Message
     * @see TransformOption
     */
    public Message transform(String transformName, Message[] sourceMessages)
        throws TransformerException {
        TransformResult result = transform(transformName, null, sourceMessages,
                null);

        return result.getResultMessage();
    }

    /**
     * 변환 메소드 (변환 결과 메시지는 자동 생성).
     * transformName을 이용해서 어떠한 변환룰을 적용할지 결정됨.
     * TransformOption이 null일 경우 기본값을 사용함.
     * @see Message
     * @see TransformOption
     */
    public TransformResult transform(String transformName,
        Message[] sourceMessages, TransformOption option)
        throws TransformerException {
        return transform(transformName, null, sourceMessages, option);
    }

    /**
     * 변환 메소드 (변환 결과 메시지는 자동 생성).
     * transformName을 이용해서 어떠한 변환룰을 적용할지 결정됨.
     * TransformOption이 null일 경우 기본값을 사용함.
     * @see Message
     * @see TransformOption
     */
    public TransformResult transform(String transformName,
        Message targetMessage, Message[] sourceMessages)
        throws TransformerException {
        return transform(transformName, targetMessage, sourceMessages, null);
    }

    /**
     * 변환 메소드 (변환 결과 메시지 제공).
     * transformName을 이용해서 어떠한 변환룰을 적용할지 결정됨.
     * TransformOption이 null일 경우 기본값을 사용함.
     * @see Message
     * @see TransformOption
     */
    public TransformResult transform(String transformName,
        Message targetMessage, Message[] sourceMessages, TransformOption option)
        throws TransformerException {
    	
    	List<String> errors = new ArrayList<String>();
    	
    	try {
	    	/**
	         * [1] 변환 정보 조회
	         */
	        Transform transform = TransformManager.getManager().getTransform(transformName);

	        if (transform == null) {
	            throw new TransformException("Failed to look up this conversion rule. - " +
	                transformName, transformName, targetMessage, sourceMessages, option);
	        } else if (transform.getSourceLayoutCount() != sourceMessages.length) {
	            throw new TransformException("The number of parameter messages specified in the conversion rule does not match the number of parameters provided.["+transform.getSourceLayoutCount()
	            +","+sourceMessages.length+"]",
	                transformName, targetMessage, sourceMessages, option);
	        }
	
	        /**
	         * [2] 소스 메시지 내용 유효성 확인
	         */
	        try {
	            checkValidSourceMessages(transform, sourceMessages);
	        } catch (Exception e) {
	            throw new TransformException("Invalid original message. : " + e.getMessage(),
	            		transformName, 
	            		targetMessage, 
	            		sourceMessages,
	            		option, e);
	        }
	
	        /**
	         * [3] 변환 옵션이 제공 안되었을 경우 기본 옵션을 할당
	         */
	        if (option == null) {
	            option = TransformOption.DEFAULT_OPTION;
	        }
	
	        /**
	         * [4] 결과 메시지가 null 이라면 생성
	         */
	        if (targetMessage == null) {
	            try {
	                targetMessage = MessageFactory.getFactory().getMessage(transform.getTargetLayout().getName());
	                
	            } catch (LayoutNotFoundException e) {
	                throw new TransformException("target message not found.", 
	                		transformName,
	                		targetMessage, 
	                		sourceMessages, 
	                		option, e);
	            } catch (LayoutInitializationException e) {
	                throw new TransformException("target message init failed.", 
	                		transformName,
	                		targetMessage, 
	                		sourceMessages, 
	                		option, e);
	            } catch(Exception e) {
	                throw new TransformException(e.getMessage(), 
	                		transformName,
	                        targetMessage, 
	                        sourceMessages, 
	                        option, e);
	            }
	            
	        }
	
	        /**
	         * [5] 변환 룰에 정의된 명령 수행
	         */
	        for (Iterator<?> itr = transform.getTransformItemList().iterator(); itr.hasNext();) {
	            TransformItem transformItem = (TransformItem) itr.next();
	            transformLine(transformItem, targetMessage, sourceMessages, option, errors);
	        }
	        
	        if (targetMessage instanceof ISO8583Message) {
	        	((ISO8583Message) targetMessage).assembleDataBytes();
	        }
	
	        TransformResult transformResult = new TransformResult();
	        transformResult.setSourceMessages(sourceMessages);
	        transformResult.setResultMessage(targetMessage);
	        transformResult.setTransformOption(option);

	        if (!errors.isEmpty() && (logger.isWarnEnabled())) {
        		StringBuilder sb = new StringBuilder();
	    		sb.append("Transformer | transform error - \n");
	    		for (Iterator<String> iter = errors.iterator(); iter.hasNext();) {
	    			sb.append(iter.next());
	    			if (iter.hasNext()) {
	    				 sb.append("\n");
	    			}
	    		}
    			String msg = transformName + " | " + sb.toString();
	    		logger.warn(msg);
    			MemoryLogger.error("<WARN> " + msg);
	        }
	        return transformResult;
    	} catch(TransformerException e) {
    		logger.error("", e);
    		throw e;
    	}
    }
    

    /**
     * transform item - line(record) 단위의 작업
     */
    protected void transformLine(TransformItem transformItem, Message targetMessage,
        Message[] sourceMessages, TransformOption option, List<String> errors)
        throws TransformerException {

        Item resultItem = null;

        String resultItemPath = transformItem.getResultItemPath();
        String instruction = transformItem.getInstruction();
        
        /**
         * 좌항 또는 우항이 빈 공백일 경우 (excel 경우 발생)
         */
		if ("".equals(resultItemPath.trim()) || "".equals(instruction))
			return;    
		
		/**
		 * data target기준 copy (예외처리한거임 ) JUN ADD
		 */
		if (instruction.indexOf("DATACOPY") >= 0){
			if ( sourceMessages[0].getData() instanceof byte[] ){
				if (sourceMessages[0].getLength() > targetMessage.getLength() ){
					byte [] src = (byte[])sourceMessages[0].getData();
					ByteBuffer bb = ByteBuffer.allocate(sourceMessages[0].getLength());
					bb.put(src);
					byte [] dst = new byte[targetMessage.getLength()];
					bb.flip();
					bb.get(dst, 0, dst.length);
					targetMessage.setData(dst);
					
				}else if (sourceMessages[0].getLength() < targetMessage.getLength() ){
					byte [] src = (byte[])sourceMessages[0].getData();
					ByteBuffer bb = ByteBuffer.allocate(targetMessage.getLength());
					bb.put(src);
					for (int i=src.length;i < targetMessage.getLength();i++ ){
						bb.put(" ".getBytes());
					}
					byte [] dst = new byte[targetMessage.getLength()];
					bb.flip();
					bb.get(dst, 0, dst.length);
					targetMessage.setData(dst);
				}else{
					targetMessage.setData(sourceMessages[0].getData());
				}
			}else if ( sourceMessages[0].getData() instanceof String ){
				if (sourceMessages[0].getLength() > targetMessage.getLength() ){
					String src = (String)sourceMessages[0].getData();
					targetMessage.setData(src.substring(0,targetMessage.getLength()));
					
				}else if (sourceMessages[0].getLength() < targetMessage.getLength() ){
					String src = (String)sourceMessages[0].getData();
					String dst ="";
					for (int i=src.length() ;i < targetMessage.getLength();i++ ){
						dst = dst + " ";
					}
					targetMessage.setData(src + dst);
				}else{
					targetMessage.setData(sourceMessages[0].getData());
				}
			}
			return;
		}
    
		/**
		 * item[*] 형태일 경우
		 */
        int idx = StringUtil.isMulti(instruction);
        
        if (idx > 0) {
            String prefix = instruction.substring(0, idx);
            int p = StringUtil.findStart(prefix);
            if (p > 0) {
                prefix = instruction.substring(p+1, idx) + "[-1]";
            }  
            // occurance 가 * (0, 1, ...) 경우 에러 수정 :2009.04.20
            else {
            	prefix = prefix + "[-1]";
            }

            Item item = null;
            for (int i = 0; i < sourceMessages.length; i++) {
                try {
                    item = ((Item) sourceMessages[i]).getItem(prefix, true);
                    if (item != null) {
                        break;
                    }
                } catch (Exception e) {
                	; // do nothing
                }
            }

            if (item == null) {  
                errors.add(" Expression : " + transformItem.getResultItemPath() +
                		   " = " + transformItem.getInstruction() +
                		   " | Item (" + prefix + ")can not be found in Source Message. Check conversion rules - ");
                for (int i = 0; i < sourceMessages.length; i++) {
                	errors.add(sourceMessages[i].toString());
                }
                return;
            }
            
            int count = item.arraySize();

            for (int i = 0; i < count; i++) {
                TransformItem trItem = new TransformItem();
                trItem.setTransform(transformItem.getTransform());
                trItem.setInstruction(replaceAsteriskToIndex(instruction, i ));
                trItem.setResultItemPath(replaceAsteriskToIndex(resultItemPath, i ));
                transformLine(trItem, targetMessage, sourceMessages, option, errors);
            }
            return;
        }
        
        /**
         * result item 설정
         */
    	String itemPath = transformItem.getResultItemPath();
    	
        /**
         * result item path 가 message 명으로 시작하지 않을 경우 -> 메시지명을 앞에 붙여준다.
         */
    	// FIXME : 정상적으로 등록되었다면 불필요한 로직임
//    	if (!itemPath.startsWith(transformItem.getTransform().getTargetLayout().getName())) {
//    		itemPath = transformItem.getTransform().getTargetLayout().getName() + Types.FIELD_SEPARATOR + itemPath;
//    	}
        resultItem = ((Item) targetMessage).getOrCreateItem(itemPath, true);
        
        if (resultItem == null) {  
            errors.add(" Expression : " + transformItem.getResultItemPath() +
            		   " = " + transformItem.getInstruction() +
            		   " | Item (" + itemPath + ") can not be found in Target Message. Check conversion rules - ");
            errors.add(targetMessage.toString());
            return;
        }


        
        //변환에서 src->target으로 값이 맵핑된적이 있나? Grid to Group 같은 경우에는 첫그리드 index 항목에서 맵핑후, 
        //같은 path의 Group 항목에 중첩될것이니 flag는 true. 그렇다면 PASS 왜냐하면 고객요건이 Grid to Group에서 Grid 첫번째 항목만 맵핑되었으면 함.
        //해당 로직없으면 계속 덮어씌기가 되며 맨 마지막 index 항목이 맵핑됨.
        if ( resultItem.isMappingFlag() ) { 
        	return;
        }
        
        resultItem.mapped();
		 

        /**
         * 
         *   1. field|attribute : transform 을 바로 진행한다. (transformEach)
         *   2. group|message : 아래의 sub 구성 요소로 분리하여 transformLine을 재귀 호출한다.
         * attribute : for test of kesa xml attribute type (DHLEE)
         */
        if (resultItem.isField() || resultItem.isAttr()) {
        	/**
        	 * 튜닝 - Instruction(Expression) 이 Simple할 경우 JEP Parsing을 할 필요가 없다.
        	 */
        	if ( isSimpleInstruction(transformItem.getInstruction().trim()) ) {
            	transformAtomWithoutParsing(transformItem, targetMessage, sourceMessages, option, errors);
        	} else {
        		transformAtom(transformItem, targetMessage, sourceMessages, option, errors);
        	}
        } else {
            Parser parser = null;
            try {
                parser = ParserFactory.getParser();
                Item item = null;
        
                try {
                    parser.parse(transformItem.getInstruction());
                } catch (Exception e) {
                    logger.error("[Transformer] Expression : " +
                        transformItem.getResultItemPath() + " = " +
                        transformItem.getInstruction(), e);
                    throw new TransformException("Error during parse instruction : " + e.getMessage(),
                        transformItem.getResultItemPath() + " = " + transformItem.getInstruction(), 
                        targetMessage, 
                        sourceMessages,
                        option, e);
                }
        
                String[] symbols = parser.getSymbols();
                String sourceItemPath = null;
                
                if (symbols.length > 0) {
                    sourceItemPath = symbols[0];
                    for (int i = 0; i < sourceMessages.length; i++) {
                        try {
                            item = ((Item) sourceMessages[i]).getItem(sourceItemPath, true);
    
                            if (item != null) {
                                break;
                            }
                        } catch (Exception e) {
                        }
                    }
                }
                
                if (item == null) {
                    throw new TransformException("I can not do conversion work. Please check the conversion rules. Expression : ",
                        transformItem.getResultItemPath() + " = " + transformItem.getInstruction(), 
                        targetMessage,
                        sourceMessages, 
                        option, null);
                }
                
                if (item.isField() || item.isAttr()) {
                	// set value to Group
                	if ( isSimpleInstruction(transformItem.getInstruction().trim()) ) {
                		transformAtomWithoutParsing(transformItem, targetMessage, sourceMessages, option, errors);
                	} else {
                		transformAtom(transformItem, targetMessage, sourceMessages, option, errors);
                	}
                	return;
                }
                
                List<Item> children = item.getChildList();                
                
                for (int i = 0; i < children.size(); i++) {
                    Item child = (Item) children.get(i);

                    if (child.getIndex() < 0) {
                        continue;
                    }

					TransformItem trItem = new TransformItem();
					trItem.setTransform(transformItem.getTransform());
					
					trItem.setResultItemPath(transformItem.getResultItemPath().replace(
							transformItem.getResultItemPath(),
							transformItem.getResultItemPath() + Types.FIELD_SEPARATOR + child.getName() + "[" + child.getIndex() + "]"));
					
					String sourceItemName = transformItem.getResultItemPath().replace(targetMessage.getName(), sourceMessages[0].getName());
					trItem.setInstruction(transformItem.getInstruction().replace(
							sourceItemName, 
							sourceItemName + Types.FIELD_SEPARATOR + child.getName() + "[" + child.getIndex() + "]"));

					transformLine(trItem, targetMessage, sourceMessages, option, errors);
                }
            } catch (Exception e) {
                throw new TransformException(e.getMessage(), null, targetMessage, sourceMessages, option, e);
            } finally {
                if (parser != null)
                    try {
                        ParserFactory.putParser(parser);
                    } catch(Exception e) {}
            }
        }
    }
   
    protected void transformAtom(TransformItem transformItem, Message targetMessage, Message[] sourceMessages
    		, TransformOption option, List<String> errors)
        throws TransformerException {    
    	
        Parser parser = null;
        try {
        	/**
        	 * [1] parse expression
        	 */
            parser = ParserFactory.getParser();
            try {
                parser.parse(transformItem.getInstruction());
            } catch (Exception e) {               
                throw new TransformException("Error during parse instruction : " + e.getMessage(),
                    transformItem.getResultItemPath() + " = " + transformItem.getInstruction(), 
                    targetMessage, 
                    sourceMessages,
                    option, e);
            }
    
            Object value = null;    
            String[] symbols = parser.getSymbols();
    
            for (int i = 0; i < symbols.length; i++) {
                for (int j = 0; j < sourceMessages.length; j++) {
                    try {
                    	/**
                    	 * transformItem 에 default value 가 설정되어 있다면
                    	 */
                        if (symbols[i].equals("DEFAULT_VALUE") && (transformItem.getDefaultValue() != null)) {
                            value = transformItem.getDefaultValue();
                            if (((String) value).startsWith("0x") || ((String) value).startsWith("0X")) {
                                value = HexUtil.hex2bytes((String) value);
                            }
                        } else {
                            try {
                                if (symbols[i].startsWith(sourceMessages[j].getName())) {
                                    value = sourceMessages[j].getObject(symbols[i]);
                                } else {
                                	if (sourceMessages.length == 1) {
                            			value = sourceMessages[j].getObject(symbols[i]);
                                	} else {
                                		continue;
                                	}
                                }
                            } catch(InvalidAccessException e) {
                            	errors.add("Transformer | ITEM Error during conversion (source message) - Continue - " + e.getMessage());
                                continue;
                            }
                        }
                        parser.addVariable(symbols[i], value);
                        break;
                    } catch (Exception e) {
                        errors.add("Transformer | " + e.getMessage() + " | " + transformItem.toString());
                    }
                }
            }
    
            /**
             * [2] check (evaluated) value
             */
            if ((value == null) && (symbols.length > 0)) {
            	if(logger.isDebugEnabled()) {
            		String msg = "[WARN] Transformer | cannot assign null value to right-hand side of expression, " +
            				"check if item is composite(messsage or group) - " + transformItem.toString();
                    logger.debug(msg);
                    MemoryLogger.txlog(msg);
                }
                return;
            }
    
            Object result = null;
            try {
                result = parser.getValueAsObject();
            } catch (Exception e) {
                throw new TransformException("Error during evaluate : " + e.getMessage(),
                    transformItem.getResultItemPath() + " = " + transformItem.getInstruction(), 
                    targetMessage, 
                    sourceMessages,
                    option, e);
            }
    
            /**
             * [3] set result to targetMessage
             */
            try {
                targetMessage.setObject(transformItem.getResultItemPath(), result);
            } catch (Exception e) {             
                throw new TransformException(
                    "An error occurred when setting conversion data to result message. - " + e.getMessage(),
                    transformItem.getResultItemPath() + " = " + transformItem.getInstruction(), 
                    targetMessage, 
                    sourceMessages,
                    option, e);
            }
        } catch(Exception e) {
            throw new TransformException("Error occurred during conversion : " + e.getMessage(),
                transformItem.getResultItemPath() + " = " +
                transformItem.getInstruction(), 
                targetMessage, 
                sourceMessages,
                option, e);
        } finally {            
            if (parser != null)
                try {
                    ParserFactory.putParser(parser);
                } catch(Exception e) {}
        }
    }
    
    /**
     * instruction 이 simple 할 경우 (JEP Parsing 단계를 skip한다)
     * 1. message...field | message...attribute 일 경우
     * 2. 상수일 경우
     * 3. default value 일 경우
     */
	protected void transformAtomWithoutParsing(TransformItem transformItem, Message targetMessage, Message[] sourceMessages
			, TransformOption option, List<String> errors)
    throws TransformerException {		
		String instruction = transformItem.getInstruction().trim();
		Object value = null;
		boolean findSource = true;
        for (int j = 0; j < sourceMessages.length; j++) {
            try {
            	/**
            	 * transformItem 에 default value 가 설정되어 있다면
            	 */
                if (instruction.equals("DEFAULT_VALUE") && (transformItem.getDefaultValue() != null)) {
                    value = transformItem.getDefaultValue();
                    if (((String) value).startsWith("0x") || ((String) value).startsWith("0X")) {
                        value = HexUtil.hex2bytes((String) value);
                    }
                } else {
                    try {
                        if (instruction.startsWith(sourceMessages[j].getName())) {
                            value = sourceMessages[j].getObject(instruction);
                        } else {
                        	if (sourceMessages.length == 1) {
                    			value = sourceMessages[j].getObject(instruction);
                        	} else {
                        		continue;
                        	}
                        }
                    } catch(InvalidAccessException e) {
                    	e.printStackTrace();
                		errors.add("Transformer] ITEM Error during conversion (source message access) - continue- " + e.getMessage());
                		value ="";
                		findSource = false;
                        continue;
                    }
                }
                break;
            } catch (Exception e) {			
                if(logger.isWarnEnabled()) {
                    logger.warn("[Transformer] " + e.getMessage() +
                    " | Expression : " + transformItem.getResultItemPath() +
                    " = " + transformItem.getInstruction());
                }
            }
        }

        try {
        	// FIX-ME : 소스메시지를 찾은 경우에만 설정하도록 함 
        	if(findSource) targetMessage.setObject(transformItem.getResultItemPath(), value);
        } catch (Exception e) {             
            throw new TransformException(
                "An error occurred when setting conversion data to result message. - " + e.getMessage(),
                transformItem.getResultItemPath() + " = " + transformItem.getInstruction(), 
                targetMessage, 
                sourceMessages,
                option, e);
        }
    }
	
    private void checkValidSourceMessages(Transform transform,
        Message[] messages) throws Exception {
        if (messages == null) {
            throw new Exception("Source Message is null.");
        }
        for (int i = 0; i < messages.length; i++) {
            if (messages[i] == null) {
                throw new Exception("Source Message["+i+"] is null.");
            }

            Layout layout = transform.getSourceLayout(((Item) messages[i]).getName());
            
            if (layout == null) {
                throw new Exception("Source Message <" + ((Item) messages[i]).getName() +
                    ">is a message that is not defined in transform <" + transform.getName() + ">.");
            }
        }
    }  
}
