package com.eactive.eai.transformer.layout;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.Iterator;

import com.eactive.eai.transformer.SystemKeys;
import com.eactive.eai.transformer.message.BytesMessage;
import com.eactive.eai.transformer.message.EbcdicMessage;
import com.eactive.eai.transformer.util.IConv;
import com.eactive.eai.transformer.util.XmlUtil;


public abstract class Leaf extends Item {
	private static final long serialVersionUID = -5946408429750358257L;
	
	protected Leaf() {
		super();
	}		

    public void clearValue() {
        setValue(null);
    }
    
    public Item findItemByPath(String path) {
        if (path.equals(this.path)) {
            return this;
        }
        return null;
    }
    
    public void setDefaultValue(String defaultValue) {
        if (defaultValue == null) {
            this.defaultValue = defaultValue;
            return;
        }
    	//빈값처리 jun's 20210607
    	if ("".equals(defaultValue)){
    		this.defaultValue = null;
    		return;
    	}
    	
        switch (getDataTypeId()) {
        case Types.TYPE_UNKNOWN:
            break;

        case Types.TYPE_STRING:
            this.defaultValue = defaultValue;
            break;

        case Types.TYPE_INT:
            this.defaultValue = new Integer(defaultValue);
            break;

        case Types.TYPE_LONG:
            this.defaultValue = new Long(defaultValue);
            break;

        case Types.TYPE_SHORT:
            this.defaultValue = new Short(defaultValue);
            break;

        case Types.TYPE_DOUBLE:
            this.defaultValue = new Double(defaultValue);
            break;

        case Types.TYPE_FLOAT:
            this.defaultValue = new Float(defaultValue);
            break;

        case Types.TYPE_BIGDECIMAL:
            this.defaultValue = new BigDecimal(defaultValue);
            break;

        // BYTE ARRAY
        case Types.TYPE_BYTEARRAY:
            this.defaultValue = defaultValue.getBytes();
            break;

        // USER DEFINED JAVA OBJECT
        case Types.TYPE_OBJECT:
        	this.defaultValue = defaultValue;
            break;

        default:
            break;
        }
    }    
    
    public void initDefaultValue() {
    	// GRID의 하위항목일 경우, 이전값의 복제로 인한 문제발생 수정
    	this.value = getDefaultValue();
    }
    
    public void initDepth(int depth) {
    	this.depth = depth;
    }
    
    public void initInclude() {
    	// do nothing
    }
    
    /**
     * OccMin 설정
     * - min 갯수 만큼 sibling을 만든다.
     */
    public void initOccMin() {
    	if (getIndex() != -1) {
        	return;
        }
    	
    	/**
    	 * 맨 왼쪽의 item일 경우 -> sibling(clone)을 만들어 줘야 한다.
    	 */
        int min = getOccMin();
        String itemPath = null;
        Item clone = null;

        /**
         * min 갯수 만큼 sibling(clone)을 만든다.
         */
        for (int i = 0; i < min; i++) {
            itemPath = normalizeFullName(getItemPath().trim().substring(0,
                    getItemPath().lastIndexOf('[')) + "[" + i + "]");
            clone = getTop().getOrCreateItem(itemPath);

            /**
             * default 값도 설정해 준다.
             */
            if (clone.getDefaultValue() != null) {
            	initDefaultValue();
            }
        }
    }
    
    public int initItemParentId(int seq, int parentId){
        int id = 1000 + (seq++);
    	setItemId(id);
    	setParentId(parentId);        
        return seq;
    }
    
    public boolean existMask() {
		return "Y".equals(getMask());
	}
    
    protected Item getItem(String itemPath) {
    	/**
    	 * leaf (FIELD | ATTRIBUTE) 일 경우, 
    	 * 또는 Group/Included Message를 Locating하는 경우
    	 */
        //normalize 이후는 이런 일은 없겠지?
        if (itemPath.equals(name)) {
            return this;
        } else if (itemPath.endsWith("]") && itemPath.equals(name + "[" + index + "]")) { 
            return this;
        } else {
            return null;
        }
    }
    
    protected Item getOrCreateItem(String itemPath) {
        /**
         * 1. leaf node 일 경우
         *    1.1 item 이름과 같을 경우 -> return this
         *    1.2 item 이름에 index를 붙인 이름과 같을 경우 (item[index]) -> return this
         *    1.3 위의 경우가 아닐 경우 -> return null
         */
        if (itemPath.equals(name)) {
            return this;
        // 튜닝 - 작업
        } else if (itemPath.equals((new StringBuffer(32)).append(name).append("[").append(Integer.toString(index)).append("]").toString())) {
            return this;
        } else {
            return null;
        }
    }
    
    /**
     * iterator 
     */
    @Override
    public Iterator iterator() {
    	return new NullIterator();
    }		
    
    @Override
    public Iterator fullIterator() {
    	return iterator();
    }	
    

    @Override
    public Object clone() {
    	Item clone = (Item) super.clone();
       	clone.initDefaultValue();
        clone.setMappedValue(false); //반복횟수 참조변수가 맵핑 되었는지
        clone.mappingFlag = false; //SRC->TGT 전문으로 값이 맵핑된적이 있는지에 대한 플래그 위에 flag(mappedValue)랑 헷갈리면 안됨.
        return clone;
    }
    
    public String toString(String tab, boolean bShowAllFlag) {	
    	/**
    	 * index==-1 인 경우 index>=0 인 sibling 이 있으면 표시하지 않는다. 
    	 */
    	if (index == -1 && next != null && getName().equals(next.getName())) {
    		return "";
    	}
        
        StringBuilder sb = new StringBuilder();

        /**
         * name
         */
        sb.append("+ " + getClass().getSimpleName() + " - ").append(name).append("[");
        sb.append(index + "").append("] ");

        /**
         * length , decimalpoint
         */
        sb.append("{").append(length==-1 ? "" : length+"").append(",").append(decimalPointLength==-1 ? "" : decimalPointLength+"").append("} "); 

        /**
         * data type
         */
        sb.append("(").append(Types.getType(dataTypeId).substring(5));
        if (dataTypeRef.startsWith("PIC")) {
        	sb.append(", " + dataTypeRef);
        }
        sb.append(") ");
        
        /**
         * path (if FMLMessage)
         */
//    	if (getRoot() instanceof FMLMessage) {
//    		sb.append("(path=" + (path==null ? "" : path) + ") ");
//    	}        
        
        /**
         * occurrence
         */
        sb.append("(occ=").append(occType);
        sb.append(",").append(occMin);
        sb.append(",").append(occMax);
        sb.append(",").append(occRef);
        sb.append(") ");
        
        /**
         * value
         */
        Object newValue = value;
        if(value != null) {
	        if (value instanceof byte[]) {
	        	if (getRoot() instanceof EbcdicMessage) {
	        		newValue =  IConv.ebcdicToASCIISOSISpaceEX((byte[]) value);
	        	} 
	        	else if (getRoot() instanceof BytesMessage) {
	        		try {
	        			newValue = new String((byte[]) value, SystemKeys.getBytesMessageCharset());
					} catch (UnsupportedEncodingException e) {
						newValue = new String((byte[]) value);
					}
	        	} else {
	        		newValue = new String((byte[]) value);
	        	}
	        } else if (value instanceof String) {
	        	if (getRoot() instanceof EbcdicMessage) {
	        		newValue =  IConv.ebcdicToASCIISOSISpaceEX(((String) value).getBytes());
	        	} else {
	        		newValue = new String(((String) value).getBytes());
	        	}        
	        } else if (value instanceof BigDecimal) {
	        	newValue = ((BigDecimal)value).toPlainString();
	        }
        }
        sb.append("(");
        if (value != null) {
            sb.append(value.getClass().getName().substring(value.getClass().getName()
                                                          .lastIndexOf(Types.FIELD_SEPARATOR) +
                                                          1));
        }
        sb.append(":");
        sb.append(newValue);
        sb.append(") ");
        

        /**
         * default value
         */
        if (defaultValue != null) {
        	if (defaultValue instanceof byte[]) {
        		if (((byte[]) defaultValue).length != 0)
        			sb.append("(default='").append(new String((byte[]) defaultValue)).append("')");
        	} else {
        		if (!"".equals(defaultValue.toString()))
        			sb.append("(default='").append(defaultValue).append("')");
        	}
        }
        /**
         * multi lang
         */
        if (multiLang != null && multiLang.trim().length() > 0){
        	sb.append("(multi=").append("Y").append(")");
        }else{
        	sb.append("(multi=").append("N").append(")");
        }
        
        return sb.toString();
    }
    
    public String toXMLString(String tab, boolean bShowAllFlag) {	
    	/**
    	 * index==-1 인 경우 index>=0 인 sibling 이 있으면 표시하지 않는다. 
    	 */
    	if (index == -1 && next != null && getName().equals(next.getName())) {
    		return "";
    	}
        
        StringBuilder sb = new StringBuilder();

        /**
         * name
         */
        sb.append("<"+name+ " desc=\""+description+"\""+( length==-1 ? "" : " length=\""+length )+"\">");
        
        /**
         * value
         */
        String newValue = null;
        if(value != null) {
	        if (value instanceof byte[]) {
	        	if (getRoot() instanceof EbcdicMessage) {
	        		newValue = IConv.ebcdicToASCIISOSISpaceEX((byte[]) value);
	        	} else if (getRoot() instanceof BytesMessage) {
	        		try {
	        			newValue = new String((byte[]) value, SystemKeys.getBytesMessageCharset());
					} catch (UnsupportedEncodingException e) {
						newValue = new String((byte[]) value);
					}
	        	} else {
	        		newValue = new String((byte[]) value);
	        	}
	        } else if (value instanceof String) {
	        	if (getRoot() instanceof EbcdicMessage) {
	        		newValue = IConv.ebcdicToASCIISOSISpaceEX(((String) value).getBytes());
	        	} else {
	        		newValue = (String)value;
	        	}        
	        }  else if (value instanceof BigDecimal) {
	        	value = ((BigDecimal)value).toPlainString();
	        	if (getRoot() instanceof EbcdicMessage) {
	        		newValue = IConv.ebcdicToASCIISOSISpaceEX(((String) value).getBytes());
	        	} else {
	        		newValue = (String)value;
	        	}        
	        }
	        else if (value instanceof Integer) {
	        	value = ((Integer) value).toString();
	        	if (getRoot() instanceof EbcdicMessage) {
	        		newValue = IConv.ebcdicToASCIISOSISpaceEX(((String) value).getBytes());
	        	} else {
	        		newValue = (String)value;
	        	}        
	        }
	        else if (value instanceof Long) {
	        	value = ((Long) value).toString();
	        	if (getRoot() instanceof EbcdicMessage) {
	        		newValue = IConv.ebcdicToASCIISOSISpaceEX(((String) value).getBytes());
	        	} else {
	        		newValue = (String)value;
	        	}        
	        }
        }
        sb.append(XmlUtil.escapeTags(newValue));
        sb.append("</"+name+">");
        
        return sb.toString();
    }    
}
