package com.eactive.eai.common.util;

import java.io.File;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;

import java.io.File;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;

import com.eactive.eai.common.util.logger.CustomPatternLayoutEncoder;
import com.eactive.eai.batch.common.StringUtil;
import com.eactive.eai.common.property.FileLoggerPropertyChangeListener;
import com.eactive.eai.common.property.PropManager;

//import com.eactive.eai.common.property.PropManager;
//import com.eactive.eai.common.server.EAIServerManager;


//import com.eactive.eai.common.property.FileLoggerPropertyChangeListener;
//import com.eactive.eai.common.property.PropManager;
//import com.eactive.eai.common.server.EAIServerManager;
//import com.eactive.eai.common.util.logger.CustomPatternLayoutEncoder;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.jul.LevelChangePropagator;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;

import com.eactive.eai.batch.doc.BatchDoc;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;

/**
 * 1. 기능 : Log4j을 통한 화일로그를 관리하는 Utility Class 2. 처리 개요 :
 *
 * 3. 주의사항
 *
 * @author :
 * @version : v 1.0.0
 * @see :
 * @since :
 */
public class Logger implements LogKeys, Serializable {
	//Logger list (프라퍼티에 설정된 Logger 및 Dafault Console Logger 를 담는다.)
	protected static Hashtable<String, Logger> loggers = new Hashtable<String, Logger>(5);
  
	private org.slf4j.Logger loggerImpl;
	private static Properties props;
	
	public static void  initBatLoggers() {
		Logger logger = null;
		logger = new Logger(LOGGER_ADAPTER);
		loggers.put(LOGGER_ADAPTER, logger);
		logger = new Logger(LOGGER_FILEEVENT);
		loggers.put(LOGGER_FILEEVENT, logger);
		logger = new Logger(LOGGER_SCHEDULER);
		loggers.put(LOGGER_SCHEDULER, logger);
	}
	public void setLoggerImpl(org.slf4j.Logger slf4jLogger) {
		loggerImpl = slf4jLogger;
	}
	public org.slf4j.Logger getLoggerImpl() {
		return loggerImpl;
	}
	/**
     * 1. 기능 : Logger factory method
     * 2. 처리 개요 :
     *    - Logger Factory를 생성한다.
     * 3. 주의사항
     *
     * @param	name	Logger name
	 * @return	Logger object
     **/
	static public synchronized Logger getLogger(String name) {
		try {
			Logger logger = null;
			if(name == null) {
				throw new Exception("Logger Name can not be null");
			}
			else {		    	
		        logger = loggers.get(name);
		        if (logger==null) {
		            logger = new Logger(name);
		            loggers.put(name, logger);
		        }
			}
		    return logger;
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return null;
    }


 
	/**
	 *	Constructor
	 */
    private Logger(String name) {
    	if(name == null || name.equals("") || name.equals("root")) {
    		this.loggerImpl = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
    	} else {
    		this.loggerImpl = LoggerFactory.getLogger(name);
    	}
    	
    	if(this.loggerImpl == null) {
    		this.loggerImpl =  LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
    	}
    }
    
	public String getName() {
		return this.loggerImpl.getName();
	}

    /**
     * 1. 기능 : PropManager를 통해 Log4j의 환경을 설정
     * 2. 처리 개요 :
     *    - PropManager를 통해 Log4j의 환경을 설정
     * 3. 주의사항
     *
     * @exception
     **/
    public static void doConfigure()
    {
        try
        {
        	System.out.println("@ Logger is initializing. ========================================");
        	//========================================================
			//1. 파일 Logger 기본 프라퍼티 정보 체크
			//========================================================
			PropManager pmanager = PropManager.getInstance();
            Properties loggerInfo= pmanager.getProperties(LOGGER_INFO);
            String defaultLayout = loggerInfo.getProperty(PATTERN_LAYOUT);
			//초기화시 메모리에 적재할 Logger 이름 리스트
            String loggerList    = loggerInfo.getProperty(INITIAL_LOGGER_LIST);
            if(loggerList==null || loggerList.equals("")) throw new RuntimeException("BECEAICUL005");

			//초기화시 Logger 에 설정해줄 파일 Appender 이름 리스트
            String appenderList  = loggerInfo.getProperty(INITIAL_APPENDER_LIST);
            if(appenderList==null || appenderList.equals("")) throw new RuntimeException("BECEAICUL006");


			//========================================================
			//2. 프라퍼티에 설정된 모든 Appender 생성 후 HashMap에 저장
			//========================================================
			//이후 Logger 생성시 필요한 Appender 찾아서 붙여줌
            LoggerContext lc =  (LoggerContext) LoggerFactory.getILoggerFactory();
            lc.reset();
	        
	        LevelChangePropagator propagator = new LevelChangePropagator();
	        propagator.setContext(lc);
	        propagator.setResetJUL(true);
	        propagator.start();
	        
	        lc.addListener(propagator);
	
	        CustomPatternLayoutEncoder ple = new CustomPatternLayoutEncoder();
	        ple.setPattern( defaultLayout );
	        ple.setContext(lc);
	        ple.start();
	        
	        ConsoleAppender<ILoggingEvent> consoleAppender = new ConsoleAppender<ILoggingEvent>();
	        consoleAppender.setName(CONSOLE_APPENDER);
	        consoleAppender.setEncoder( ple );
	        consoleAppender.setContext( lc );
	        consoleAppender.start();
            String[] appenderNameList = StringUtil.getStrArray(appenderList, ",");
            HashMap<String, RollingFileAppender<ILoggingEvent>> fa = new HashMap<String, RollingFileAppender<ILoggingEvent>>();
	        
	        for(int i=0;i<appenderNameList.length;i++) {
	        	
	            RollingFileAppender<ILoggingEvent> appender = addFileAppender(appenderNameList[i]);
	            if ( appender == null ) {
	            	continue;
	            }
	            CustomPatternLayoutEncoder fple = new CustomPatternLayoutEncoder();
	            fple.setContext( lc );
	            
	            String appenderLayout = pmanager.getProperty(appenderNameList[i], PATTERN_LAYOUT);
	            if (appenderLayout == null){
	                fple.setPattern( defaultLayout );
	            }else{
	            	fple.setPattern( appenderLayout );
	            }
	            String encoding = pmanager.getProperty(appenderNameList[i],ENCODING);
	            if(encoding==null) {
	                encoding = "EUC-KR";
	            }else {
	            	encoding = encoding.trim();
	            }
	    		if (StringUtils.isNotBlank(encoding)) {
	    			fple.setCharset(Charset.forName(encoding));
	    		}
	            
	            fple.start();
	            
	            appender.setEncoder( fple );
	            appender.start();
	            
	            fa.put( appenderNameList[i], appender );
	        }
        
	        
			//========================================================
			//3. 프라퍼티에 설정된 모든 파일 Logger 생성
			//========================================================
            String[] loggerNameList = StringUtil.getStrArray(loggerList, ",");		//log4j Logger 생성
            ch.qos.logback.classic.Logger logger = null;

            for(int i=0; i<loggerNameList.length; i++) {
                logger = addLogger(loggerNameList[i]);

                if ( logger == null ) {
	            	continue;
	            }
	            logger.detachAndStopAllAppenders();
				
	            String console = loggerInfo.getProperty(LOGGER_CONSOLE);
	            if((console!=null) && console.equals("on")) {
	                logger.addAppender(consoleAppender);
	                System.out.println("@ add ConsoleAppender to " + logger.getName());
	            }

	            String appenderNames = pmanager.getProperty(loggerNameList[i], LOGGER_APPENDER_LIST);
	            if(appenderNames==null) {
	            	continue;
	            }
				for(String appenderName : appenderNames.split(",")){
		            RollingFileAppender<ILoggingEvent> appender = 
		            		(RollingFileAppender<ILoggingEvent>)fa.get(appenderName);
		            if(appender==null) {
		            	continue;
		            }
		            
		            logger.addAppender(appender);
		            System.out.println("@ add FileAppender to "+logger.getName()+" - "+appender.getName());
				}
            }

        	PropManager prptManager = PropManager.getInstance();
        	prptManager.addPropertyChangeListener( new FileLoggerPropertyChangeListener() );

        } catch(Exception e) {
        	System.out.println(e.getMessage());
        }

    }
    
    public static void setLoggerLevel(String loggerName) {

    	ch.qos.logback.classic.Logger logger = null;
    	Level asisLevel = null;
    	Level toLevel = null;

    	try {
	    	PropManager pmanager = PropManager.getInstance();
	        String logLevel = pmanager.getProperty(loggerName, LOGGER_LEVEL);
	        
	        if(loggerName.startsWith(org.slf4j.Logger.ROOT_LOGGER_NAME)){
	        	logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
	        }else{
	        	logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(loggerName);
	        }
	        toLevel = Level.toLevel(logLevel, null);
	        
	        if ( logger == null || toLevel == null) {
		        System.out.println("@@ Logger setLoggerLevel | loggerName [" 
		        						+ loggerName + "] or Level [" + logLevel + "] is incorrect");	        	
	        	return;
	        }

	        asisLevel = logger.getLevel();	        
	        if ( asisLevel.toInt() != toLevel.toInt() ) {
	        	logger.setLevel( toLevel );
		        System.out.println("@@ Logger setLoggerLevel | " + loggerName 
		        					+ " AS-IS [" + asisLevel.toString() + "] TO [" + toLevel.toString() + "]");	        	
	        }

    	} catch (Exception e) {
	        System.err.println("@@ Logger setLoggerLevel Error | " 
	        						+ loggerName + " | " + e.getMessage() );
    	}
    }

    /**
     * 1. 기능 : logback의 logger를 추가
     * 2. 처리 개요 : 
     *    - logback API를 통해 logger를 추가
     * 3. 주의사항
     *
     * @exception
     **/
    public static ch.qos.logback.classic.Logger addLogger(String loggerName) {

    	ch.qos.logback.classic.Logger logger = null;
    	
    	try {
    		PropManager pmanager = PropManager.getInstance();
           
    		props = pmanager.getProperties(loggerName);
	        String logLevel = props.getProperty( LOGGER_LEVEL);
	        String aditivity = props.getProperty( LOGGER_ADITIVITY);
	       
//	        logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(loggerName);
	        Logger fileLogger = loggers.get(loggerName);
	        if(fileLogger != null)
	        	logger = (ch.qos.logback.classic.Logger)fileLogger.getLoggerImpl();
	        else {
	        	fileLogger = new Logger(loggerName);
	        }
	        	logger = (ch.qos.logback.classic.Logger)fileLogger.getLoggerImpl();//(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(loggerName);
	        try {
	        	logger.setAdditive(new Boolean(aditivity).booleanValue());
	        } catch(Exception e) {
	        	logger.setAdditive(false);   
	        }
			
			if(logLevel==null || logLevel.equals(DEBUG)) {
				logger.setLevel(Level.DEBUG);
			} else if(logLevel.equals(INFO)) {
				logger.setLevel(Level.INFO);
			} else if(logLevel.equals(WARN)) {
				logger.setLevel(Level.WARN);
			} else if(logLevel.equals(ERROR)) {
				logger.setLevel(Level.ERROR);
			} else if(logLevel.equals(TRACE)) {
				logger.setLevel(Level.TRACE);
			} else {
				logger.setLevel(Level.DEBUG);
			}
			loggers.put(loggerName, fileLogger);
//			Logger fileLogger = loggers.get(loggerName);
//			if(fileLogger != null) 
//				fileLogger.setLoggerImpl(logger);
    	} catch (Exception e) {
	        System.err.println("@@ Logger Configure Error.===================");
	        System.err.println("@@ addFileAppender | " + loggerName + " | " + e.getMessage() );
	        logger = null;
    	}
    	
		return logger;
    }

    /**
     * 1. 기능 : logback의 FileAppender를 추가
     * 2. 처리 개요 : 
     *    - logback API를 통해 FileAppender를 추가
     * 3. 주의사항
     *
     * @exception
     **/
    public static RollingFileAppender<ILoggingEvent> addFileAppender(String appenderName) {
    	
    	RollingFileAppender<ILoggingEvent> appender = null;
    	
    	try {
    		PropManager pmanager = PropManager.getInstance();
    		props = pmanager.getProperties(appenderName);     
	    
	        
	        String logDirectory = props.getProperty(APPENDER_LOG_DIRECOTRY);
	        if(logDirectory==null || logDirectory.equals("")) {
	            throw new RuntimeException("RECEAICUL004");
	        }
	        String datePattern = props.getProperty(APPENDER_DATE_PATTERN);
	        if(datePattern==null || datePattern.equals("")) {
	            throw new RuntimeException("RECEAICUL008");
	        }
	        if(datePattern.equals("'-'yyyy.MM.dd")){
	        	datePattern = "-%d{yyyy.MM.dd}";
	        }
			String sMaxBackupIndex =props.getProperty(MAX_BACKUP_INDEX);

			int maxBackupIndex = 0;
			try{
				maxBackupIndex = Integer.parseInt(sMaxBackupIndex);
			}catch(Exception e) {
				maxBackupIndex = 60;
			}
	        
			String localServer = System.getProperty("inst.Name");
			appender = new RollingFileAppender<ILoggingEvent>();
			String logFile = props.getProperty(APPENDER_LOG_FILENAME);
			TimeBasedRollingPolicy<ILoggingEvent> rollingPolicy = new TimeBasedRollingPolicy<ILoggingEvent>();
			rollingPolicy.setFileNamePattern( logDirectory + localServer + File.separator + logFile + datePattern);
			rollingPolicy.setContext( (LoggerContext) LoggerFactory.getILoggerFactory() );
			rollingPolicy.setParent(appender);
			rollingPolicy.setMaxHistory(maxBackupIndex);
			rollingPolicy.start();			
			
			appender.setFile( logDirectory + localServer + File.separator + logFile );
			appender.setRollingPolicy( rollingPolicy );	
			try {
				String append = props.getProperty(APPENDER_FILE_APPEND);
	            appender.setAppend(new Boolean(append).booleanValue());
	        } catch(Exception e) {
	            appender.setAppend(true);
	        }
			appender.setContext( (LoggerContext) LoggerFactory.getILoggerFactory() );
			appender.setName(appenderName);
			
    	} catch (Exception e) {
	        System.err.println("@@ Logger Configure Error.===================");
	        System.err.println("@@ addFileAppender | " + appenderName + " | " + e.getMessage() );
	        appender = null;
    	}
    	
        return appender;	
    }

    static public synchronized void reloadLogLevel(String loggerName) {
		try {
				LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
				Properties props = PropManager.getInstance().getProperties(loggerName);
				if( props == null )
					return;
				
				String logLevel = props.getProperty(LOGGER_LEVEL);
				if(lc != null) {
					Level level = Level.ERROR;
					if ("DEBUG".equals(logLevel)){
						level = Level.DEBUG;
					}else if ("INFO".equals(logLevel)){
						level = Level.INFO;
					}else if ("WARN".equals(logLevel)){
						level = Level.WARN;
					}else if ("ERROR".equals(logLevel)){
						level = Level.ERROR;
					}
					lc.getLogger(loggerName).setLevel(level);
				}
		}
		catch (Exception e) {
			System.err.println("@@ Logger ReloadLevel Error.===================");
		}
    }
 
	/**
     * 1. 기능 : Banner 형태의 로그를 출력
     * 2. 처리 개요 :
     *    - Banner 형태의 로그를 출력
     * 3. 주의사항
     *
     * @param	msg	Object
     * @exception
     **/
    public void banner(Object msg) {
        try {
        	this.loggerImpl.debug("===========================================================");
        	this.loggerImpl.debug(msg.toString());
        	this.loggerImpl.debug("===========================================================");
        } catch (Throwable t) {
            printOut(t, msg);
        }
    }

	/**
     * 1. 기능 : debug Level의 로그를 출력
     * 2. 처리 개요 :
     *    - debug Level의 로그를 출력
     * 3. 주의사항
     *
     * @param	msg	Object
     * @exception
     **/
    public void debug(Object msg) {
        try {        	
        		this.loggerImpl.debug(msg.toString()); 
        	} catch (Throwable t) {
            printOut(t, msg);
        }
    }

    /**
     * 1. 기능 : error Level의 로그를 출력
     * 2. 처리 개요 : 
     *    - error Level의 로그를 출력 (ErrorCode를 사용할 경우)
     * 3. 주의사항
     *
     * @param	code String
     * @param	msg Object
     * @exception
     **/
    public void debug(String code, Object msg) {
        try {        	
            this.loggerImpl.debug(format(code,msg));           
        } catch (Throwable t) {
            printOut(t, msg);
        }
    }

    /**
     * 1. 기능 : info Level의 로그를 출력
     * 2. 처리 개요 :
     *    - info Level의 로그를 출력
     * 3. 주의사항
     *
     * @param	msg Object
     * @exception
     **/
    public void info(Object msg) {
    	try {
            this.loggerImpl.info(msg.toString());
        } catch (Throwable t) {
            printOut(t, msg);
        }
    }

    /**
     * 1. 기능 : error Level의 로그를 출력
     * 2. 처리 개요 : 
     *    - error Level의 로그를 출력 (ErrorCode를 사용할 경우)
     * 3. 주의사항
     *
     * @param	code String
     * @param	msg Object
     * @exception
     **/
    public void info(String code, Object msg) {
        try {
        	this.loggerImpl.info("===========================================================");
            this.loggerImpl.info(format(code,msg));
            this.loggerImpl.info("===========================================================");
        } catch (Throwable t) {
            printOut(t, msg);
        }
    }
    
   

    /**
     * 1. 기능 : warn Level의 로그를 출력
     * 2. 처리 개요 :
     *    - warn Level의 로그를 출력
     * 3. 주의사항
     *
     * @param	msg Object
     * @exception
     **/
    public void warn(Object msg) {
    	 try {
             this.loggerImpl.warn(msg.toString());
         } catch (Throwable t) {
             printOut(t, msg);
         }
    }

    /**
     * 1. 기능 : warn Level의 로그를 출력
     * 2. 처리 개요 :
     *    - warn Level의 로그를 출력
     * 3. 주의사항
     *
     * @param	msg Object
     * @param	t	Throwable
     * @exception
     **/
    public void warn(Object msg, Throwable t) {
    	try {
            this.loggerImpl.warn(msg.toString(), t);
        } catch (Throwable th) {
            printOut(t, th, msg);
        }
    }
    /**
     * 1. 기능 : error Level의 로그를 출력
     * 2. 처리 개요 : 
     *    - error Level의 로그를 출력
     * 3. 주의사항
     *
     * @param	msg Object
     * @exception
     **/
    public void error(Object msg) {
        try {
        	this.loggerImpl.error("===========================================================");
            this.loggerImpl.error(msg.toString());
            this.loggerImpl.error("===========================================================");
        } catch (Throwable t) {
            printOut(t, msg);
        }
    }
    
     /**
     * 1. 기능 : error Level의 로그를 출력
     * 2. 처리 개요 : 
     *    - error Level의 로그를 출력 (ErrorCode를 사용할 경우)
     * 3. 주의사항
     *
     * @param	code String
     * @param	msg Object
     * @exception
     **/
    public void error(String code, Object msg) {
        try {
        	this.loggerImpl.error("===========================================================");
            this.loggerImpl.error(format(code,msg));
            this.loggerImpl.error("===========================================================");
        } catch (Throwable t) {
            printOut(t, msg);
        }
    }
    /**
    * 1. 기능 : error Level의 로그를 출력
    * 2. 처리 개요 : 
    *    - error Level의 로그를 출력
    * 3. 주의사항
    *
    * @param	msg Object
    * @param	t	Throwable
    * @exception
    **/
   public void error(String msg, Throwable t) {
       try {
    	   this.loggerImpl.error("===========================================================");
           this.loggerImpl.error(msg, t);
           this.loggerImpl.error("===========================================================");
       } catch (Throwable th) {
           printOut(t, th, msg);
       }
   }
   
    /**
    * 1. 기능 : error Level의 로그를 출력
    * 2. 처리 개요 : 
    *    - error Level의 로그를 출력 (ErrorCode를 사용할 경우)
    * 3. 주의사항
    *
    * @param	code String
    * @param	msg Object
    * @param	t	Throwable
    * @exception
    **/
   public void error(String code, Object msg, Throwable t) {
       try {
    	   this.loggerImpl.error("===========================================================");
           this.loggerImpl.error(format(code,msg), t);
           this.loggerImpl.error("===========================================================");
       } catch (Throwable th) {
           printOut(t, th, msg);
       }
   }
     /**
     * 1. 기능 : fatal Level의 로그를 출력
     * 2. 처리 개요 :
     *    - fatal Level의 로그를 출력
     * 3. 주의사항
     *
     * @param	msg Object
     * @exception
     **/
    public void fatal(Object msg) {
    	error(msg);
    }
    
    /**
     * 1. 기능 : ErrorCode와 메시지의 출력 포맷을 정의
     * 2. 처리 개요 : 
     *    - ErrorCode와 메시지의 출력 포맷을 정의
     * 3. 주의사항
     *
     * @param	code String
     * @param	msg Object
     * @exception
     **/
    private String format(String code, Object msg) {
        StringBuffer sb = new StringBuffer();
        sb.append("[").append(code).append("]")
          .append(" ").append(msg);
          
        return sb.toString();   
    }
    /**
     * 1. 기능 : debug Level의 로그를 출력 가능여부 확인
     * 2. 처리 개요 :
     *    - debug Level의 로그를 출력 가능여부 확인
     * 3. 주의사항
     *
     * @return	boolean
     * @exception
     **/
    public boolean isWarnEnabled() {
        return this.loggerImpl.isWarnEnabled();
    }
    /**
     * 1. 기능 : warn Level의 로그를 출력 가능여부 확인
     * 2. 처리 개요 :
     *    - warn Level의 로그를 출력 가능여부 확인
     * 3. 주의사항
     *
     * @return	boolean
     * @exception
     **/
    public boolean isDebugEnabled() {
        return this.loggerImpl.isDebugEnabled();
    }
    /**
     * 1. 기능 : info Level의 로그를 출력 가능여부 확인
     * 2. 처리 개요 :
     *    - info Level의 로그를 출력 가능여부 확인
     * 3. 주의사항
     *
     * @return	boolean
     * @exception
     **/
    public boolean isInfoEnabled() {
        return this.loggerImpl.isInfoEnabled();
    }

  
    /**
     * 1. 기능 : Log4j를 통해 로그를 남길 수 없는 경우 표준출력 제공
     * 2. 처리 개요 :
     *    - Log4j를 통해 로그를 남길 수 없는 경우 표준출력 제공
     * 3. 주의사항
     *
     * @param	t	Throwable
     * @param	msg Object
     * @exception
     **/
    private void printOut(Throwable t, Object msg) {
        System.out.println("can't write to log file!! Because of " + t);
        System.out.println("the message will be printed to System.out");
        System.out.println(msg);
    }

    /**
     * 1. 기능 : Log4j를 통해 로그를 남길 수 없는 경우 표준출력 제공
     * 2. 처리 개요 :
     *    - Log4j를 통해 로그를 남길 수 없는 경우 표준출력 제공
     * 3. 주의사항
     *
     * @param	t	Throwable
     * @param	th	Throwable
     * @param	msg Object
     * @exception
     **/
    private void printOut(Throwable t, Throwable th, Object msg) {
        System.out.println("can't write to log file!! Because of " + t);
        System.out.println("the message will be printed to System.out");
        System.out.println(th);
        System.out.println(msg);
    }

    /*
        debug(1000) : debug, info, warn, error, fatal
        info (2000) : info, warn, error, fatal
        warn (3000) : warn, error, fatal
        error(4000) : error, fatal
        fatal(5000) : fatal

        if(logger.isError) logger.error();
    */
    public boolean isDebug() {
        return this.loggerImpl.isDebugEnabled();
    }
    public boolean isInfo() {
        return this.loggerImpl.isInfoEnabled();
    }
    public boolean isWarn() {
        return this.loggerImpl.isWarnEnabled();
    }
    public boolean isError() {
        return this.loggerImpl.isErrorEnabled();
    }
	public static void addInstLog(BatchDoc batchDoc) {
		// TODO Auto-generated method stub
		Logger logger = Logger.getLogger(LOGGER_DEFAULT);
		batchDoc.setLogger(Logger.getLogger(Logger.LOGGER_DEFAULT));
		try {
			// 기관별 로그 설정 확인
			String processCode = batchDoc.getBatchMsg().getHeader().getProcessCode();
			String institutionCode = batchDoc.getBatchMsg().getHeader().getInstitutionCode();
			
			Properties instInfo = PropManager.getInstance().getProperties( 
	    			"TelegramInfo{" + processCode + "_" + institutionCode + "}");
			
			// 프라퍼티가 없는 경우
			if (instInfo == null) {
				return;
			}
			
			String instLog = instInfo.getProperty(LogKeys.INST_LOG);
			
			logger.debug("instlog processCode=["+processCode+"],institutionCode=["+institutionCode+"], instLog=["+instLog+"]");
			
			if (!"Y".equalsIgnoreCase(instLog)) {
				return;
			}
			
			String appenderName = processCode + "_" + institutionCode;
			String loggerName = "INST_" + appenderName;
			
			final LoggerContext ctx =(LoggerContext) LoggerFactory.getILoggerFactory();
		
			createBapFileAppender(LogKeys.APPENDER_INST, appenderName, processCode, institutionCode);
				
			batchDoc.setLogger(Logger.getLogger(loggerName));
		} catch (Exception e) {
			logger.error("BatchDoc = " + batchDoc, e);
		}
	}
	
	public static void createBapFileAppender(String appenderPropertiesGroup, String appenderName, String processCode, String institutionCode) {
		Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
		try {			
			Properties props = PropManager.getInstance().getProperties(appenderPropertiesGroup);
			if (props == null) {
				if(logger != null)
					logger.error("★★★★★ '" + appenderPropertiesGroup + "' FileAppender 프라퍼티 정보가 없습니다. ★★★★★");
				return;
			}

			// 로그파일 저장 디렉토리 절대경로
			String logDirectory = props.getProperty(APPENDER_LOG_DIRECOTRY);
			if (logDirectory == null || logDirectory.equals("")) {
				if(logger != null)
					logger.error("★★★★★ '" + appenderPropertiesGroup + "' FileAppender 프라퍼티의 디렉토리 정보가 없습니다. ★★★★★");
				return;
				// throw new Exception("BECEAICUL004");
			}

			String loggerName = "INST_" + appenderName;
			// 로그파일 명
			String logFilename = institutionCode + ".log";

			// 로그파일 날자별 생성 규칙
			String datePattern = props.getProperty(APPENDER_DATE_PATTERN, "-%d{yyyy.MM.dd}");

			// 로그 패턴 문자열
			String patternLayout = props.getProperty(APPENDER_PATTERN_LAYOUT, "[%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5p %F[%L] %m%n");

			// 로그파일 로그Append 여부
			String fileAppend = props.getProperty(APPENDER_FILE_APPEND, "true");

			String maxBackupIndex = props.getProperty(MAX_BACKUP_INDEX);
			if(logger != null)
				logger.info("patternLayout = " + patternLayout);
			try {
				Integer.parseInt(maxBackupIndex);
			} catch (Exception e) {
				maxBackupIndex = "30";
			}
			
			// 로그 파일 갯수
			String logFileCount = props.getProperty(LOG_FILE_COUNT, "100");
			try {
				Integer.parseInt(logFileCount);
			} catch (Exception e) {
				if(logger != null)
					logger.error("{" + LOG_FILE_COUNT +"} = {"+ logFileCount +"}" );
			}
			// 로그 파일 크기
			String fileSize = props.getProperty(FILE_SIZE, "200M");


			String localServer = EAIServerManager.getInstance().getLocalServerName();
			String logPath = logDirectory.replaceAll(Pattern.quote("${inst.name}"), localServer);
			
			if (!logPath.endsWith(File.separator)) {
				logPath += File.separator;
			}
			
			logPath += processCode + File.separator;
			
			File dir = new File(logPath);

	        if (!dir.exists()) {
	            dir.mkdir();
	        }
	        File f = new File(dir, logFilename);
			if (!f.exists()) {
				File parent = f.getParentFile();
				if (parent != null && !parent.exists()) {
					parent.mkdir();
				}
			}
			RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<ILoggingEvent>();
			TimeBasedRollingPolicy<ILoggingEvent> rollingPolicy = new TimeBasedRollingPolicy<ILoggingEvent>();
			rollingPolicy.setFileNamePattern( logPath + logFilename + datePattern);
			rollingPolicy.setContext( (LoggerContext) LoggerFactory.getILoggerFactory());
			rollingPolicy.setParent(appender);
			rollingPolicy.setMaxHistory(Integer.parseInt(maxBackupIndex));
			rollingPolicy.start();			
			try {
	            appender.setAppend(new Boolean(fileAppend).booleanValue());
	        } catch(Exception e) {
	            appender.setAppend(true);
	        }
			
			appender.setFile( logPath + logFilename );
			appender.setRollingPolicy( rollingPolicy );	
			
			try {
	            appender.setAppend(new Boolean(fileAppend).booleanValue());
	        } catch(Exception e) {
	            appender.setAppend(true);
	        }
			
			appender.setContext( (LoggerContext) LoggerFactory.getILoggerFactory());
			appender.setName(appenderName);
			
			LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
			CustomPatternLayoutEncoder fple = new CustomPatternLayoutEncoder();
            fple.setContext( lc );
            
          	fple.setPattern( patternLayout );
           
            String encoding ="EUC-KR";
    		if (StringUtils.isNotBlank(encoding)) {
    			fple.setCharset(Charset.forName(encoding));
    		}
            
            fple.start();
            
            appender.setEncoder( fple );
            appender.start();
            
            ch.qos.logback.classic.Logger instLogger = addLogger(loggerName);
            if(instLogger == null) {
            	if(logger != null)
    				logger.debug("  - 기관 배치 파일로거 '"+ loggerName +"' Appender 생성 실패.");
            	return;
            }
            
            instLogger.detachAndStopAllAppenders();	
            instLogger.addAppender(appender);
            
			if(logger != null)
				logger.debug("  - 배치 파일로거 '"+ appenderName +"' Appender 생성됨.");
			
			
			if(logger != null)
				logger.info("  - 배치 파일로거 '" + appenderName + "' Appender 생성됨.");
		} catch (Exception ex) {
			if(logger != null)
				logger.error("Create Inst Logger Fail" + ex.getMessage());
		}
	}
	
}