package com.eactive.eai.transformer.message;

import com.eactive.eai.transformer.SystemKeys;
import com.eactive.eai.transformer.layout.Layout;
import com.eactive.eai.transformer.layout.LayoutManager;
import com.eactive.eai.transformer.layout.LayoutNotFoundException;
import com.eactive.eai.transformer.util.Logger;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;

public class MessageFactory {
	private static Logger logger = Logger.getLogger("transformer");
	
	static Cache cache = null;    
	static Cache cachePermenent = null;
	
	private int cacheSize = 0;
	private int cacheIdle = 0;
	private int permCacheSize = 0;
	private boolean cacheOnStartup = false;
	
    public void initCache() {
    	try {
    		cacheSize = Integer.parseInt(System.getProperty(SystemKeys.TRANSFROMER_LAYOUT_CACHE_SIZE, SystemKeys.LAYOUT_CACHE_SIZE_DEFAULT));
            cacheIdle = Integer.parseInt(System.getProperty(SystemKeys.TRANSFROMER_LAYOUT_CACHE_IDLE_SEC, SystemKeys.LAYOUT_CACHE_IDLE_DEFAULT));
            permCacheSize = Integer.parseInt(System.getProperty(SystemKeys.TRANSFROMER_LAYOUT_PERMCACHE_SIZE, SystemKeys.LAYOUT_PERMCACHE_SIZE_DEFAULT));

            cacheOnStartup = SystemKeys.isLayoutCacheOnStartup();

    		int layoutSize = LayoutManager.getManager().getLayouts().size();
    		if(cacheOnStartup) {
    			cacheSize = layoutSize + 100;
    			logger.warn("MessageFactory layoutSize -> cacheSize : "+ layoutSize);
        	}
    		CacheManager manager = CacheManager.create();
            logger.warn(">> MessageFactory initCache");
        	logger.warn(String.format("%s = %s", SystemKeys.TRANSFROMER_LAYOUT_CACHE_SIZE, cacheSize));
            logger.warn(String.format("%s = %s", SystemKeys.TRANSFROMER_LAYOUT_CACHE_IDLE_SEC, cacheIdle));
            logger.warn(String.format("%s = %s", SystemKeys.TRANSFROMER_LAYOUT_PERMCACHE_SIZE, permCacheSize));
            
            cache = new Cache("layout", cacheSize, false, false, 0, cacheIdle);
            cachePermenent = new Cache("permanentlayout", permCacheSize, false, false, 0, 0);
            manager.addCache(cache);
            manager.addCache(cachePermenent);
            
            if(cacheOnStartup) {
            	long ms = System.currentTimeMillis();
	            String[] layoutNames = LayoutManager.getManager().getAllLayoutName();
	    		for(int p=0; p<layoutNames.length; p++) {
	    			instance.getMessage(layoutNames[p]);
	    		}
	    		logger.warn( String.format("MessageFactory load to cache layouts : %,d, elapse ms : %,d"
	    				, layoutNames.length, (System.currentTimeMillis() -ms)) );
            }
                		
        } catch(Exception e) {
            logger.error("MessageFactory cache create error",e);
        }
    }
    
	public static Cache getCachePermenent() {
		return cachePermenent;
	}

	public static void setCachePermenent(Cache cachePermenent) {
		MessageFactory.cachePermenent = cachePermenent;
	}

	public int getCacheSize() {
		return cacheSize;
	}

	public void setCacheSize(int cacheSize) {
		cacheSize = cacheSize;
	}

	public int getCacheIdle() {
		return cacheIdle;
	}

	public static void setCacheIdle(int cacheIdle) {
		cacheIdle = cacheIdle;
	}

	public int getPermCacheSize() {
		return permCacheSize;
	}

	public static void setPermCacheSize(int permCacheSize) {
		permCacheSize = permCacheSize;
	}

	private static MessageFactory instance = new MessageFactory();

	public static MessageFactory getFactory() {
		return instance;
	}
	
	//----------------------------------------------------
	// Cache 작업 : 2009.11.18
	// 메모리 동기화시에 수행해야 함
	public boolean removeCache(String layoutName) {
		boolean permanet = false;
		boolean temp = false;
		if (cachePermenent != null) {
			permanet = cachePermenent.remove(layoutName);
		}

		if (cache != null) {
			temp = cache.remove(layoutName);
		}

		return (permanet || temp);
	}
	
	public boolean removeCache() {
		try {
			cachePermenent.removeAll();
		}
		catch(Exception e) {
			return false;
		}
		try {
			cache.removeAll();
		}
		catch(Exception e) {
			return false;
		}
		return true;
	}
	public boolean checkPerment(String layoutName){
		Object obj = null;
		try{
			obj = cachePermenent.get(layoutName);
		}catch(Exception e){
			return false;
		}
		if (obj== null){
			return false;
		}
		return true;
	}	
	//----------------------------------------------------
	public void init(String layoutName) {
    	try{
			Layout layout = LayoutManager.getManager().getLayoutByName(layoutName);
	
			if (layout == null) {
				throw new LayoutNotFoundException("해당 레이아웃을 찾지 못했습니다. - '" + layoutName + "'", layoutName);
			}
			
	    	Message message = null;
	    	message = (Message) layout.getRootItem();
	        message = (Message) message.clone();
	    	message.createObject();
	    	message.initOccMin();
	    	cachePermenent.put(new net.sf.ehcache.Element(layoutName, message));
    		logger.info("permanent cache load success : "+layoutName);
    	}catch(Exception e){
    		logger.error("permanent cache load fail : "+layoutName);
    	}
	}
	
	/**
	 * 모니터링 화면에서만 사용하기 위해서
	 * @param layoutName
	 * @return
	 */
	public Message getMessageForMonitoring(String layoutName){
		String layoutTypeName = "";
		try {
            	Layout layout = LayoutManager.getManager().getLayoutByName(layoutName);

        		if (layout == null) {
        			throw new LayoutNotFoundException("해당 레이아웃을 찾지 못했습니다. - '" + layoutName + "'", layoutName);
        		}
        		layoutTypeName = layout.getLayoutType().getName();
        		
            	Message message = null;
            	message = (Message) layout.getRootItem();
                message = (Message) message.clone();
            	message.createObject();
            	message.initOccMin();
				//------------------------------------------------------
				return (Message) message.clone();
            
		} catch (Exception e) {
			throw new MessageException("cannot create message - (" + layoutTypeName + ", '"
					+ layoutName + "')", e);
		}
	}
	public Message getMessage(String layoutName) {

		String layoutTypeName = "";
		try {
			net.sf.ehcache.Element element = cache.get(layoutName);
			if (element == null){
				element = cachePermenent.get(layoutName);
			}
            if (element != null) {            	
            	Message message = null;
            	message = (Message)element.getValue();
            	message = (Message) message.clone();
            	return message;
            }
            else {
            	Layout layout = LayoutManager.getManager().getLayoutByName(layoutName);
            	long c = System.currentTimeMillis();
        		if (layout == null) {
        			throw new LayoutNotFoundException("해당 레이아웃을 찾지 못했습니다. - '" + layoutName + "'", layoutName);
        		}
        		layoutTypeName = layout.getLayoutType().getName();
        		
            	Message message = null;
            	message = (Message) layout.getRootItem();
            	//------------------------------------------------------
				// TEST 메모리 문제로 임시로 처리하도록함
				// Layout.init() 에서 주석처리함
				// 2009.07.06
				// Message Clone & createObject : 2009.11.17
                message = (Message) message.clone();
                message.createObject();
            	message.initOccMin();
				cache.put(new net.sf.ehcache.Element(layoutName, message));
				//------------------------------------------------------
				return (Message) message.clone();
            }
            
		} catch (Exception e) {
			throw new MessageException("cannot create message - (" + layoutTypeName + ", '"
					+ layoutName + "')", e);
		}
	}

	public Message createMessage(String layoutTypeName) {
		if ("ASCII".equals(layoutTypeName) || "BYTES".equals(layoutTypeName)) {
			return new BytesMessage();
//		} else if ("FML".equals(layoutTypeName) || "FML32".equals(layoutTypeName)) {
//			return new FMLMessage();
		} else if ("OBJECT".equals(layoutTypeName)) {
			return new ObjectMessage();
		} else if ("XML".equals(layoutTypeName)) {
			return new XMLMessage();
//		} else if ("UXML".equals(layoutTypeName)) {
//			return new UXMLMessage();
		} else if ("JSON".equals(layoutTypeName)) {
			return new JSONMessage();
//		} else if ("UJSON".equals(layoutTypeName)) {
//			return new UJSONMessage();
//		} else if ("HJSON".equals(layoutTypeName)) {
//			return new HJSONMessage();
		} else if ("EBCDIC".equals(layoutTypeName)) {
			return new EbcdicMessage();
		} else if ("CARD".equals(layoutTypeName)) {
			return new CardMessage();
		} else if ("COMBYTES".equals(layoutTypeName)) {
			return new CommonBytesMessage();
		} else if ("COMEBCDIC".equals(layoutTypeName)) {
			return new CommonEbcdicMessage();
		} else if ("VASCII".equals(layoutTypeName) || "VBYTES".equals(layoutTypeName)) {
			return new VariableBytesMessage();
		} else if ("VFIELD".equals(layoutTypeName)) {
			return new VariableFieldMessage();
		} else if ("VEBCDIC".equals(layoutTypeName)) {
			return new VariableEbcdicMessage();
		} else if ("FULLBYTES".equals(layoutTypeName)) {//바이패스 위해서
			return new FullBytesMessage();
		} else if ("MVBYTES".equals(layoutTypeName)) {//오류 파싱을 위해서
			return new MonitoringVBytesMessage();
		} else if ("MVEBCDIC".equals(layoutTypeName)) {//오류 파싱을 위해서
			return new MonitoringVEbcdicMessage();
		} else if ("ODDBYTES".equals(layoutTypeName)) {//인뱅 금결원 응답전문 
			return new OddBytesMessage();
		} else if ("DELIMITER".equals(layoutTypeName)) {
			return new DelimiterMessage();
		} else {
			throw new MessageException("cannot create message. unsupported layout type - "
					+ layoutTypeName);
		}

	}
}
