package com.eactive.eai.adapter.wca.util;


import com.eactive.eai.adapter.wca.global.WCADefine;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 1. 기능 :
 * 2. 처리 개요 :
 * 		- 
 * 3. 주의사항
 * 		- 
 * 
 * @author : Administrator
 * @version : 2005. 6. 16.
 * @see :
 * @since : 2005. 6. 16. 오후 4:04:20
 */
public class MyLog {
    private String[] saLogLevelMsg = null;
    DateUtil dateUtil = new DateUtil();
    
    private void setLogLevelMsg() {
        saLogLevelMsg = new String[7];
        saLogLevelMsg[0] = "DE";
        saLogLevelMsg[1] = "IN";
        saLogLevelMsg[2] = "NO";
        saLogLevelMsg[3] = "WA";
        saLogLevelMsg[4] = "ER";
        saLogLevelMsg[5] = "CR";
        saLogLevelMsg[6] = "EM";

        return;
    }
    
    /* Log Level 정의 */
    public static final int DEBUG	= 1;
    public static final int INFO	= 2;
    public static final int NOTICE	= 3;
    public static final int WARN	= 4;
    public static final int ERROR	= 5;
    public static final int ALERT	= 6;
    public static final int EMERGENCY = 7;

    /* Trace On/Off 정의 */
    public static final boolean TRC_ON 		= true;
    public static final boolean TRC_ONFF 	= false;
    
    /* 현재 설정 정보 */
    private boolean 	bTrcFlag 		= true;
    private int 		nLogLevel		= 1;   

	
	public static final int 	CHECK_LOG_CNT = 1000;
	
	// Maximum log file size(MB)
	private int 	MAX_LOG_FILE_SIZE = 4;		
	
	// Default log directory name
	private String 	DEFAULT_LOG_DIR = "C:\\app\\Log";	
	
	// Default log file name
	private String 	DEFAULT_LOG_FILE = "mylog.log";	
	
	// If logfile is opened, true
	boolean isLogFileOpen  = false;			
	
//	private String 	logFilePath = null;		// 로그 파일의 Path를 저장할 String Object
//	private File 	logFile = null;			// 로그 파일의 Name를 저장할 File Class Object
	private File	logDir = null;			// 로그 파일의 Directory를 저장할 File Class Object
	private File	logPath = null;			// 로그 파일의 Path를 저장할 File Class Object
	
	private boolean isOK = false;			// 각종 함수의 리턴값을 저장할 변수
	
	// 로그 파일에 데이터를 저장할 때 사용하는 BufferedWriter Class Object
	public BufferedWriter	myWriter = null;
	
	int				nLogCnt = 0;
	
	/**
	 * 메세지 및 바이너리 데이터를 파일에 로깅하기 위해 LogWrite 클래스를 생성한다.<BR>
	 * 최대 로그 파일 크기와 로그 파일 패스는 디폴트 값으로 설정된다.<BR>
	 * 메세지나 데이터를 로그 파일에 로깅하다가 로그 파일 크기가 최대 로그 파일 크기를 넘어서면
	 * 현재 로그 파일을 백업하고 새로운 파일을 만들어서 계속 로깅한다.
	 * <P>
	 * 디폴트 최대 로그 파일 크기 : 4M<BR>
	 * 디폴트 로그 파일 패스 : "C:\LogWrite.log"
	 */
	public MyLog() {
		try {
		    nLogCnt = 0;
		    setLogLevelMsg();
			logDir  = new File(DEFAULT_LOG_DIR);
			logPath = new File(logDir, DEFAULT_LOG_FILE);
			
			isOK = initLogDir(logDir);
			
			isOK = initLogFile(logPath);
		}
		catch (Exception e) {
			nLogCnt = 0;
		}

		return;
	}
	
	/**
	 * 메세지 및 바이너리 데이터를 파일에 로깅하기 위해 LogWrite 클래스를 생성한다.<BR>
	 * logFilePath에 포함되는 디렉토리가 없을 경우에는 새로 생성된다.<BR>
	 * 메세지나 데이터를 로그 파일에 로깅하다가 로그 파일 크기가 최대 로그 파일 크기를 넘어서면
	 * 현재 로그 파일을 백업하고 새로운 파일을 만들어서 계속 로깅한다.	 
	 * 로그 파일 패스 파라미터는 절대 패스나 상대 패스를 모두 지원한다.
	 * @param nMaxLogFileSize 	로그 파일 최대 크기
	 * @param logFilePath 		로그 파일 패스(예 : "C:\kab@iTeller\Log\LogWrite.log" or "Log\LogWrite.log" or "LogWrite.Log")
	 */
	public MyLog(boolean bLogYN, int nLogLevel, int nMaxLogFileSize, String logFilePath) {
		try {
		    nLogCnt = 0;
		    setLogLevelMsg(); 
            this.setTraceOnOff(bLogYN);
            this.setLogLevel(nLogLevel);
            
			MAX_LOG_FILE_SIZE = nMaxLogFileSize;
			File tempLogPath = new File(logFilePath);
			
			logPath = new File(tempLogPath.getAbsolutePath());
			logDir = new File(logPath.getParent());
			
			isOK = initLogDir(logDir);
			
			isOK = initLogFile(logPath);
		}
		catch (Exception e) {
			nLogCnt = 0;
		}
			
		return;	
	}
	// 현재 사용되는 로그 파일의 크기가 로그 파일 최대 크기를 넘었는지 
	// 검사하고, 넘었을 경우에 기존의 로그 파일을 백업하고, 새로운 
	// 로그 파일을 생성한다.
	private void checkLogFileSize() {
		File backupLogPath = null;
	
		try {	
			isOK = isOverMaxFileSize(logPath);
			if (!isOK) {
				return;
			}

			backupLogPath = new File(logPath.toString() + "-");
			if (backupLogPath.exists()) {
				backupLogPath.delete();
			}
					
			myWriter.close();
			myWriter = null; 
			
			isLogFileOpen = false;
			
			// 기존에 파일이 이미 있으면 Fail
			logPath.renameTo(backupLogPath);

			logPath.createNewFile();
			
			openLogStream(logPath);
		}
		catch (Exception e) {
			return;
		}		
	}
	
	/**
	 * 버퍼에 들어있는 내용을 로그파일에 기록하고 로그 파일을 닫는다.
	 */
	protected void finalize() {
		try {
			if (isLogFileOpen) { 
				if (myWriter != null) {
					myWriter.close();
					myWriter = null;
				}
			}
		}
		catch(Exception e) {
			return;
		}
	}
	
	/**
	 * 현재 사둉되는 로그 파일의 절대 패스를 리턴
	 * @return 로그 파일의 절대 패스
	 */	
	public String getLogFilePath() {
		return logPath.toString();
	}
	
	/**
	 * 현재 사용되는 로그 파일의 최대 크기를 리턴(단위 : MB)
	 * @return 로그 파일 최대 크기
	 */
	public int getMaxLogFileSize() {
		return MAX_LOG_FILE_SIZE;
	}
	
    public void setMaxLogFileSize(int nMaxLogFileSize) {
    	MAX_LOG_FILE_SIZE = nMaxLogFileSize;
    }
    
	// 로그 파일이 저장될 디렉토리를 초기화
	private boolean initLogDir(File logDir) {
		try {
			return logDir.mkdirs();
		}
		catch (Exception e) {
			return false;
		}
	}
	
	// 바이너리 데이터및 메세리를 로깅하기 위해서 사용되는 
	// 로그 파일 및 관련 클래스 초기화
	private boolean initLogFile(File logPath) {
		File backupLogPath = null;
	
		try {	
			if (logPath.exists()) {
			    /*
				isOK = isOverMaxFileSize(logPath);
				if (isOK) {
					backupLogPath = new File(logPath.toString() + "-");
					if (backupLogPath.exists()) {
						backupLogPath.delete();
					}
						
					// 기존에 파일이 이미 있으면 Fail
					logPath.renameTo(backupLogPath);
				}
				*/			
				backupLogPath = new File(logPath.toString() + "-");
				if (backupLogPath.exists()) {
					backupLogPath.delete();
				}
					
				// 기존에 파일이 이미 있으면 Fail
				logPath.renameTo(backupLogPath);
				logPath.createNewFile();
			}
			else {
				logPath.createNewFile();
			}
			
			openLogStream(logPath);
		}
		catch(Exception e) {
			return false;
		}
		
		return true;
	}
	
	// 현재 사용되는 로그 파일의 크기가 로그 파일 최대 크기를 넘는지 검사
	private boolean isOverMaxFileSize(File logPath) {
		try {
			// Throw SecurityException
			if (logPath.length() > (1024 * 1024 * MAX_LOG_FILE_SIZE)) {
				return true;
			}
			else {
				return false;
			}
		}
		catch (Exception e) {
			return false;
		}
	}
	
	/**
	 * 바이너리 데이터를 로그 파일에 로깅
	 * @param cFlag		bDataBuff 파라미터에 들어있는 데이터의 문자 코드
	 * @param nDataLen	bDataBuff 파라미터에 들어있는 데이터 길이
	 * @param bDataBuff	로깅할 바이너리 데이터가 들어있는 바이트 어레이
	 */
	// 20030804 hslee 화면번호 Parameter 추가
	public void logData(char cFlag, int nDataLen, byte[] bDataBuff)	{
        
		int		i, j;
		int		end_flag;		// 출력할 라인 수 
		int		rem_flag;		// 맨 마지막줄의 출력할 데이터 길이
		int		nRemainDataLen = 0;
		byte[]	tempData = null;
		int		tempLen = 0;
		
		if (bTrcFlag == false) {
		    return;
		}
		
		if (!isLogFileOpen) {
			return;	
		}
			
		tempData = new byte[16];
		
		try {
			checkLogFileSize();
            
            // 파일이 존재하지 않으면 생성
            createNewFile();
			
            if (myWriter == null) { return; }
            
			myWriter.write("\r\n====================================================================\r\n");

			// Format the current time.			
			DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd=HH:mm:ss.SSS");
			String dateString = formatter.format(ZonedDateTime.now());
            
			myWriter.write(dateString + " : " + "Data Length = " + nDataLen + "\r\n");
		
			// 출력할 라인 수 계산
			end_flag = nDataLen / 16;
			if ((nDataLen % 16) != 0) {
				end_flag++;
			}
		
			// 맨 마지막줄의 출력할 데이터 길이 계산
			rem_flag = nDataLen - (16 * (end_flag - 1));

			nRemainDataLen = nDataLen;
		    
			// 매 라인마다 인쇄루틴 For 루프
			for (i = 0; i < end_flag; i++) {
				int nTempLen = i * 16;
				
				// 데이터 수를 문자열로 변환
				String  strLength = Integer.toString(nTempLen);
				int		strLen = strLength.length();
				
				strLen = 6 - strLen;
				
				for (int x = 0; x < strLen; x++) {
					myWriter.write("0");
				}
					
				myWriter.write(strLength);	
				
				// 넘겨받은 데이터에서 16바이씩 잘라서 복사
				// Bug!!!
				if (nRemainDataLen > 16) {
					MyUtil.memcpy(tempData, bDataBuff, 0, i * 16, 16);
					tempLen = 16;
					nRemainDataLen -= 16;
				}
				else {
					MyUtil.memcpy(tempData, bDataBuff, 0, i * 16, nRemainDataLen);
					tempLen = nRemainDataLen;
				}
		
				for (j = 0; j < 16; j++) {
					if ((j % 4) == 0) {
						myWriter.write("  ");
					}
					
					// 인쇄할 라인이 마지막 라인이 아니거나 
					// 인쇄할 데이터 위치가 마지막 바이트가 아닐 경우
					if ((i != (end_flag - 1)) || (j < rem_flag)) {
						myWriter.write(MyUtil.toHex3(tempData[j]));
					}
					else {
						myWriter.write("  ");
					}
				}					
				
				myWriter.write("    |");
		        
				// 라인별로 데이터에 해당하는 문자열 인쇄 
				for (j = 0; j < 16; j++) {
					// 인쇄할 라인이 마지막 라인이 아니거나 
					// 인쇄할 데이터 위치가 마지막 바이트가 아닐 경우
					if ((i != end_flag - 1) || (j < rem_flag)) {
						// cFlag값은 'a'값(ASCII)일 경우, ASCII 문자로 인쇄
						if (cFlag == WCADefine.ASCII_CODE) {
							// 데이터가 인쇄할 수 있는 범위안에 있으면, 
							// Character형으로 인쇄하고, 아니면 "." 문자로 대체하여 인쇄
							if ((tempData[j] > 0x1f) && (tempData[j] < 0x7e)) {
								myWriter.write(tempData[j]);
							}
							else {
								myWriter.write(".");
							}
						} 
						// cFlag값은 'e'값(EBCDIC)일 경우, EBCDIC 문자를 변환하여 인쇄
						else if (cFlag == WCADefine.EBCDIC_CODE) {
							byte xx = CodeCvrt.cvrtEbc2Ksc2(tempData[j]);
							if ((xx <= 0x1f) || (xx >= 0x7e)) {
								myWriter.write(".");
							}
							else {
								myWriter.write(xx);
							}
						}
					}
					// 인쇄할 마지막 라인의 마지막 데이터를 넘겼을 경우,공백으로 인쇄
					else {
						myWriter.write(" ");
					}
				}
		        
				// 구분선 인쇄
				myWriter.write("|\r\n");
			}
			
			myWriter.write("====================================================================\r\n\r\n");
			myWriter.flush();

			return;
		}
		catch (Exception e) {
			return;
		}
	}
	
    private void createNewFile()
    {
        /*
        try {
            if (!logPath.exists()) {
                logPath.createNewFile();
                openLogStream(logPath);
            }
        }
        catch(Exception e) { }
        */
    }
    
	/**
	 * 메세지를 로그 파일에 기록(시간 정보가 포함됨)
	 * @param logMsg 로그 파일에 기록할 메세지
	 */
	public void logMsg(String logMsg) {
		if (!isLogFileOpen) {
			return;		
		}
        
		try {
            // 파일이 존재하지 않으면 생성
            createNewFile();
            
            if (myWriter == null) { return; }
            
			// Format the current time.
            
			DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd=HH:mm:ss.SSS");
			String dateString = formatter.format(ZonedDateTime.now());
            
			myWriter.write(dateString + " : " + logMsg + "\r\n");
			myWriter.flush();
		}
		catch (Exception e) {
			return;
		}
	}
	
	/**
	 * 메세지를 로그 파일에 기록(시간 정보가 포함됨)
	 * @param logMsg 로그 파일에 기록할 메세지
	 */	
	public void logMsg(int nLogLevel, String logMsg) {
	    if ((nLogLevel < this.nLogLevel) || (nLogLevel > EMERGENCY)) { 
	        return;
	    }
	    
		if (!isLogFileOpen) {
			return;		
		}
		
		nLogCnt++;
		if (nLogCnt > CHECK_LOG_CNT) {
		    nLogCnt = 0;
		    checkLogFileSize();
		}
		
		try {
            // 파일이 존재하지 않으면 생성
            createNewFile();
            
            if (myWriter == null) { return; }
            
			// Format the current time            
			DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd=HH:mm:ss.SSS");
			String dateString = formatter.format(ZonedDateTime.now());
            
			myWriter.write("[" + saLogLevelMsg[nLogLevel - 1] +  "] " + dateString + " : " + logMsg + "\r\n");
			myWriter.flush();
		}
		catch (Exception e) { 
			return; 
		}
	}
	
	/**
	 * 메세지를 로그 파일에 기록(시간 정보가 포함되지 않음)
	 * @param logMsg 로그 파일에 기록할 메세지
	 */
	public void logMsg2(String logMsg) {
		if (!isLogFileOpen) {
			return;		
		}
			
		try {
            // 파일이 존재하지 않으면 생성
            createNewFile();
            
            if (myWriter == null) { return; }
            
			myWriter.write(logMsg + "\r\n");
			myWriter.flush();
		}
		catch (Exception e) {
			return;
		}
	}
	
	// 로그 파일과 연결된 BufferedWriter 클래스 오브젝트 생성
	private void openLogStream(File logPath) {
		try {
			if (isLogFileOpen) {
				if (myWriter != null) { 
					myWriter.close();
					myWriter = null;
				}
				
				isLogFileOpen = false;
			}
			
			myWriter = new BufferedWriter(new FileWriter(logPath.toString(), true));
			isLogFileOpen = true;		
            
            logMsg("TRACE ON/OFF = " + bTrcFlag);
            logMsg("LOG LEVLE = " + nLogLevel + ", LOG SIZE = " + MAX_LOG_FILE_SIZE + "M");
		}
		catch (Exception e) {
			// System.out.println("openLogStream error -"+e.toString());
		}
	}
	
	public void closeLogStream() {
		try {
			if (isLogFileOpen) {
				isLogFileOpen = false;
				if (myWriter != null) { 
					myWriter.close(); 
					myWriter = null;
				}
			}
		}
		catch (Exception e) {
			// System.out.println("closeLogStream error -"+e.toString());
		}
	}

    public void setTraceOnOff(boolean bOnOff) { 
        bTrcFlag = bOnOff; 
        return; 
    }
    
    public boolean getTraceOnOff() { 
        return bTrcFlag; 
    }

    public void setLogLevel(int nLogLevel) {
        this.nLogLevel = nLogLevel;
        return;
    }
    
    public int getLogLevel() {
        return nLogLevel;
    }	
}
