package com.eactive.eai.transformer.message;

import java.util.Iterator;

import com.eactive.eai.transformer.layout.Item;
import com.eactive.eai.transformer.layout.Types;
import com.eactive.eai.transformer.util.ByteUtil;
import com.eactive.eai.transformer.util.Constants;
import com.eactive.eai.transformer.util.XmlUtil;


/**
 * 모니터링 을 위한 VariableBytesMessage 
 * Error 처리 안함
 * @author 
 *
 */
public class MonitoringVBytesMessage extends BytesMessage {
    public static final String NAME = "MVBYTES";

    public MonitoringVBytesMessage() {
        super();
    }

    protected void doSetData(Object data) {
        this.data = (byte[]) data;
//        int rcvLength = this.data.length;
        
        byte[] _data = ByteUtil.copy(this.data);
        
    	if(_data != null) {
//    		byte[] result = setDataBytes((byte[]) _data);
    		setDataBytes((byte[]) _data);
    	}

    }
    
    protected byte[] setDataBytes(byte[] data) {
//    	int originalLength = data.length;
    	Item item = null;
    	
		for (Iterator iter = iterator(); iter.hasNext();) {
			item = (Item) iter.next();
			
			if(item == null) {
				continue;
			}
			/**
			 * occType = * | + | (occMax>occMin) 일 경우
			 * occRef를 참조하여 그 갯수만큼 item을 생성한다.
			 */
	        if (item.getIndex()==-1 && ("*".equals(item.getOccType()) || "+".equals(item.getOccType()) || item.getOccMax()>item.getOccMin())) {
	            int occCount = 0;
	            String path = "";
	            try {
	            	//occCount = item.getRoot().getInt(item.getParent().getItemPath() + Types.FIELD_SEPARATOR + item.getOccRef());
	            	path = getOccRefItem(item);
	            	occCount = item.getRoot().getInt(path);
	            }
	            catch(Exception oe) {
//	            	throw new InvalidAccessException(item.getName() +"의 반복참조정보 값이 숫자가 아닙니다 - " + " : " + oe.getMessage() , item.getParent().getItemPath() + Types.FIELD_SEPARATOR + item.getOccRef());
	            	logger.warn("반복참조정보 값 에러", oe);
	            }
	            
	            if (occCount < item.getOccMin() 
	            	|| (!"*".equals(item.getOccType()) && !"+".equals(item.getOccType()) && occCount > item.getOccMax())) { 
	                throw new InvalidAccessException("반복횟수가 OccMin~OccMax 의 범위를 벗어납니다. , " + item.getName(), item.getItemPath());
	            }
	            /**
	             * 반복횟수 참조정보가 비정상적으로 클때 방어로직
	             * 그리드 오류처리로직) 자식배열 길이합계 * 반복횟수 참조정보 > 셋팅하는 실제 데이터 
	             * 필드   오류처리조직) 필드 길이            * 반복횟수 참조정보 > 셋팅하는 실제 데이터
	             */
	            int sumChildLength = 0;
	            Item childItem= null;
	            if (item.isGroup()){
		            for(int i=0;i<item.getChildList().size();i++){
		            	childItem = item.getChild(i);
		            	if (childItem.getIndex() == -1){
		            		continue;
		            	}
		            	sumChildLength += item.getChild(i).getLength();
		            }
		            if (sumChildLength * occCount > data.length){
		            	//throw new InvalidAccessException(item.getName() +"의 반복참조정보 값("+occCount+") * 자식배열 길이합계("+sumChildLength+") = 계산된길이("+(sumChildLength * occCount)+") 보다 실제데이터 길이("+data.length+")가 작습니다. "  , item.getParent().getItemPath() + Types.FIELD_SEPARATOR + item.getOccRef());
		            	throw new InvalidAccessException(item.getName() +"의 반복참조정보 값("+occCount+") * 자식배열 길이합계("+sumChildLength+") = 계산된길이("+(sumChildLength * occCount)+") 보다 실제데이터 길이("+data.length+")가 작습니다. "  , path);
		            }
	            }else{
	            	if (item.getLength() * occCount > data.length){
		            	//throw new InvalidAccessException(item.getName() +"의 반복참조정보 값("+occCount+") * 길이("+item.getLength()+") = 계산된길이("+(item.getLength() * occCount)+") 보다 실제데이터 길이("+data.length+")가 작습니다. "  , item.getParent().getItemPath() + Types.FIELD_SEPARATOR + item.getOccRef());
		            	throw new InvalidAccessException(item.getName() +"의 반복참조정보 값("+occCount+") * 길이("+item.getLength()+") = 계산된길이("+(item.getLength() * occCount)+") 보다 실제데이터 길이("+data.length+")가 작습니다. "  , path);
		            }
	            }
	            item.createItem(item, 
	            		item.getRoot().normalizeFullName(item.getParent().getItemPath() + Types.FIELD_SEPARATOR + item.getName() + "[" + (occCount-1) + "]"), 
	            		false);

	            /**
	             * item 이 속해있는 childList 크기가 증가로 인해, iterator를 다시 생성한다.
	             */
	            iter = item.getRoot().iterator();
	            for (;iter.hasNext();) {	
	            	if (item.equals(iter.next())) {
	            		break;
	            	}
	            }
	        }
	        
			/**
			 * index == -1 인 경우는 무시한다
			 */
			if (item.getIndex() == -1) {		
				continue;
			}

	        switch (item.getNodeTypeId()) {
			case NODE_FIELD:
				try {
	            	item.setValue(ByteUtil.cut(data, item.getLength()));
				} catch(Exception e) {
					// Padding space
					byte[] space = new byte[item.getLength()];
					for (int i=0; i<item.getLength(); i++) {
						space[i] = (byte)0x20;
					}
					item.setValue(space);

				}
				
				try {
					if(data != null && data.length >= item.getLength()) {
						data = ByteUtil.sub(data, item.getLength());
					}
				} catch(Exception e) {
					logger.warn("byte hadling error.", e);
				}
	            break;
			}
		}		
        
        return data;
    }
    
    public String toString() {
        
        StringBuffer sb = new StringBuffer();
        sb.append("[MVBYTES message]");

        sb.append("\n" + super.toString());
        sb.append("\n");

        return sb.toString();
    }
    public String toXMLString() {
    	StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"euc-kr\"?>");
        sb.append("\n" + "<error>");
        sb.append("\n" + Constants.TAB + "<comment>정상적으로 파싱된게 아닙니다. 오류 발견을 용이하게 하기 위해서 파싱을 했습니다.</comment>");
        sb.append(Constants.TAB + "   " + XmlUtil.removeXMLHeader(super.toXMLString()));
        sb.append("\n" + "</error>");
        return sb.toString();
    } 
}
