package com.eactive.eai.adapter.wca;

import com.eactive.eai.adapter.wca.cfg.SNAAdapter;
import com.eactive.eai.adapter.wca.cfg.SNAAdapterManager;
import com.eactive.eai.adapter.wca.cfg.SessionGroupDataEx;
import com.eactive.eai.adapter.wca.exception.WCAException;
import com.eactive.eai.adapter.wca.global.WCADefine;
import com.eactive.eai.adapter.wca.servlet.TableInfoEx;
import com.eactive.eai.adapter.wca.util.MyUtil;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.Logger;

/** 
* 1. 기능 :  WCA 세션 정보
* 2. 처리 개요 : 
* 3. 주의사항 
*
* @author  : 
* @version : v 1.0.0
* @see     : 
* @since   : 2005. 6. 22. 오후 5:53:46
*/  
public class WCASession {    
    /**
     * SNAAdapter critical한 정보 로깅을 위한 logger 
     */
    Logger adapter_logger = Logger.getLogger(WCADefine.ADAPTER_LOGGER_NAME);
    
    private String					sNodeName			= "";			// Softlink Node Name
    private String					sIpAddr             = null;     // Softlink Ip 주소                
    private int 					nPortNo             = 0;        // SoftLink Port 번호    
    private Thread					threadSession;                  // Softlink 수신 처리를 담당하는 스레드
    private String 					sAdapterGrpName     = null;     // 어댑터 그룹 이름
    private String 					sAdapterName        = null;     // 어댑터 이름
    private String 					sGroupCode          = null;     // LU 그룹 이름
    private WCASessionThread		wcaSessionThread    = null;     // Softlink 수신 처리를 담당하는 WCA 세션 Runnable 클래스
    private int						nSessNum;                        // WCA 세션 수
    private boolean                 bBackupSessionPool  = false;    // Backup 세션 여부 (true: 백업 세션)
	
    private boolean                 bLogYN              = true;     // 로깅 여부
    private int                     nLogLevel           = 1;        // 로그 레벨
    private int                     nLogSize            = 4;        // 로그 파일 사이즈 
	private int                     nTransTimeout       = WCADefine.DEFAULT_TRANSACTION_TIMEOUT * 1000; // 트랜잭션 타임아웃
    
    private boolean					bBackupEnableFlag = true;		// 백업 세션 사용 가능여부 플래그
    private SNAAdapter				snaAdapter = null;				// WCA 세션을 포함하고 있는 SNAAdapter 오브젝트
    
    public boolean getBackupEnableFlag() {
    	return bBackupEnableFlag;
    }
    
    public void setBackupEnableFlag(boolean bBackupEnableFlag) {
    	this.bBackupEnableFlag = bBackupEnableFlag;
    	return;
    }
    
    /** 
     * 1. 기능 : 노드 이름 설정 
     * 2. 처리 개요 : 
     * 3. 주의사항 
     * 
     * @param sNodName 노드이름
     **/  
     public void setNodeName(String sNodeName) {
         if (sNodeName == null) { sNodeName = ""; }
         this.sNodeName = sNodeName.trim();   
     }
     
     /** 
     * 1. 기능 :  노드 이름 반환
     * 2. 처리 개요 : 
     * 3. 주의사항 
     * 
     * @return    노드이름
     **/
     public String getNodeName() {
         return sNodeName; 
     }
     
    /** 
    * 1. 기능 : 세션 정보 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return 세션 정보
    **/       
    public String toString() {
        StringBuffer	sTemp = new StringBuffer();
        
        // 20090810 Start
        // sTemp.append(" " + sAdapterGrpName + "-" + sGroupCode + "-" +  nSessNum);
        sTemp.append(" " + sAdapterGrpName + "-" + sNodeName + "-" + sGroupCode + "-" +  nSessNum);
        // 20090810 End
        
        if (bBackupSessionPool) { sTemp.append(":BACKUP "); }
        else { sTemp.append(" "); }
        
        return sTemp.toString();
    }
    
    public String getLogPrefix() {
    	StringBuffer	sTemp = new StringBuffer();
            
        sTemp.append("[" + sAdapterGrpName + "][" + sNodeName + "][" + sGroupCode + "][" + nSessNum + "]");
        if (bBackupSessionPool) { sTemp.append("[BACKUP]"); }

        return sTemp.toString();   	
    }
    
    /** 
     * 1. 기능 : WCA 세션 생성자
     * 2. 처리 개요 : 
     * 3. 주의사항 
     * 
     * @param sIpAddr            Softlink Ip 주소
     * @param nPortNo            SoftLink Port 번호
     * @param sAdapterGrpName    어댑터 그룹 이름
     * @param sAdapterName       어댑터 이름
     * @param sGroupCode         LU 그룹 이름
     * @param nSessId            WCA 세션 수       
     **/       
    public WCASession(String sIpAddr, int nPortNo, String sAdapterGrpName, String sAdapterName, String sGroupCode,  int nSessNum) {
        this.sIpAddr = sIpAddr;
        this.nPortNo = nPortNo;
        this.sAdapterGrpName = sAdapterGrpName;
        this.sAdapterName = sAdapterName;
        this.sGroupCode = sGroupCode;
        this.nSessNum = nSessNum;  
        snaAdapter = SNAAdapterManager.getInstance().selectSnaAdapter(sAdapterGrpName);
    }

   /** 
    * 1. 기능 : 어댑터 그룹 이름 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    어댑터 그룹 이름
    **/           
    public String getAdapterGroupName() {
        return sAdapterGrpName;
    }
    
   /** 
    * 1. 기능 : LU 그룹 이름 반환 
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    LU 그룹 이름
    **/           
    public String getGroupCode() {
        return sGroupCode;
    }
    
   /** 
    * 1. 기능 : 트랜잭션 타임아웃 설정
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    timeout    트랜잭션 타임아웃
    **/     
    public void setTranTimeout(int timeout) {
        this.nTransTimeout = timeout;
    }
   

   /** 
    * 1. 기능 : 트랜잭션 타임아웃 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    트랜잭션 타임아웃
    **/    
    public int getTranTimeout() {
        return this.nTransTimeout;
    }
    
   
   /** 
    * 1. 기능 : Sotlink 세션 정보 설정
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    sIpAddr         Softlink Ip 주소  
    * @param    nPortNo         SoftLink Port 번호    
    * @param    nSessNum        WCA 세션 수
    **/   
    public void setSessionInfo(String sIpAddr, int nPortNo, int nSessNum) {
        this.sIpAddr = sIpAddr;
        this.nPortNo = nPortNo;
        this.nSessNum = nSessNum;
    }
    
    public void setSessionInfo(String sIpAddr, int nPortNo) {
        this.sIpAddr = sIpAddr;
        this.nPortNo = nPortNo;
    }
   
    /** 
     * 1. 기능 : Sotlink 세션 정보 갱신
     * 2. 처리 개요 : 
     * 3. 주의사항 
     * 
     * @param    sessgroup    LU 세션 그룹 정보 
     **/     
    public void updateSessionInfoEx(SessionGroupDataEx sessgroup) {
    	 // 로컬 세션인 경우 
         if (!isBackupSessionPool()) {
        	 setSessionInfo(sessgroup.getSoftLinkSevrName(), sessgroup.getPort());       	 
         }
         // 백업 세션인 경우
         else {
             setSessionInfo(sessgroup.getBackupNodeName(), sessgroup.getBackupPort());
         }
         
         setLogInfo(sessgroup.isLogWritable(), sessgroup.getLogLevel(), sessgroup.getLogSize() );
         setTranTimeout(sessgroup.getTranTimeout());
         setBackupEnableFlag(sessgroup.getBackupEnableFlag());         
         
         wcaSessionThread.updateSessionInfoEx(sessgroup);         
     }
        
    /** 
     * 1. 기능 : WCA APP CODE 정보 갱신 (updateSessionInfoEx 함수를 참조하여 개발)
     * 2. 처리 개요 : 
     * 3. 주의사항 
     * 
     * @param    sessgroup    LU 세션 그룹 정보 
     **/     
    public void updateWcaAppCodeEx() {
         wcaSessionThread.updateWcaAppCodeEx();         
     }
    
    /*
    * 1. 기능 : 로그 설정
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    bLogYN       로깅 여부
    * @param    nLogLevel    로깅 레벨
    * @param    nLogSize     로깅 파일 사이즈
    **/    
    public void setLogInfo(boolean bLogYN, int nLogLevel, int nLogSize) {
        this.bLogYN         = bLogYN; 
        this.nLogLevel      = nLogLevel;
        this.nLogSize       = nLogSize;
    }
    
    
    /** 
    * 1. 기능 : 백업 세션 여부 설정 (true: 백업 세션)
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    flag       백업 세션 여부
    **/    
    public void setBackupSessionPool(boolean flag) {
        bBackupSessionPool = flag;
    }
    
    /** 
    * 1. 기능 : 백업 세션 여부 반환 (true: 백업 세션)
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    백업 세션 여부
    **/   
    public boolean isBackupSessionPool() {
        return bBackupSessionPool;
    }
    
    /** 
    * 1. 기능 : 데이터 송신별 수신 데이터를 대기할 Queue를 등록
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    objKey   HashMap에 저장될 unique한 key (UUID)
    * @param    objData  HashMap에 저장될 값 (송신에 대한 Queue 데이타)
    * @return   0
    **/   
	public int registerRcvQueue(Object objKey, Object objData) {
	    wcaSessionThread.registerRcvQueue(objKey, objData);
		return 0;
	}
    
    /** 
    * 1. 기능 :  Queue에 등록된 송신에 대한 Queue 데이타 삭제
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    objKey   HashMap에 저장될 unique한 key (UUID)
    **/
    public void unregisterRcvQueue(Object objKey) {
	    wcaSessionThread.unregisterRcvQueue(objKey);
	}
    
   /** 
    * 1. 기능 :  Softlink와 연결된 세션수를 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    Softlink와 연결된 세션수
    **/
    public int getConnectedSessNum() {
        return wcaSessionThread.getConnectedSessNum();
    }
    
    /** 
    * 1. 기능 :  세션에 해당하는 Thread Group 이름 반환
    * 2. 처리 개요 : 
    *       - Thread Group 이름은 LU 그룹 이름으로 한다.
    *       - 백업 세션일 경우 ":BACKUP"을 추가한다.
    * 3. 주의사항
    * 
    * @return    Thread Group 이름
    **/
    private String getThreadGroupName() {
        StringBuffer	sTemp = new StringBuffer();
        
        // LU 그룹 이름이 rule에 따라 설정되지 않을 가능성을 대비하여 어댑터 그룹명까지 포함한다.
        // LU 그룹 이름이 동일한 경우가 있을 경우, 스레드 그룹 이름이 동일하여 
        // 해당 어댑터를 종료할때 제대로 종료되지 않을 가능성이 있다.
        // sTemp.append(sAdapterGrpName + "-" + sGroupCode);
        sTemp.append(sAdapterGrpName + "-" + sNodeName + "-" + sGroupCode);
        if (bBackupSessionPool) { sTemp.append(":BACKUP"); }
        return sTemp.toString();
    }
    
    /** 
    * 1. 기능 :  세션에 해당하는 Thread Group 반환
    * 2. 처리 개요 : 
    * 3. 주의사항
    * 
    * @return    Thread Group
    **/
    private ThreadGroup getThreadGroup() {
    	ThreadGroup threadGroup = snaAdapter.getThreadGroup(sNodeName, sGroupCode);
        if (threadGroup == null) {
            threadGroup = snaAdapter.putThreadGroup(sNodeName, sGroupCode, getThreadGroupName());
        }
        
        return threadGroup;
    }
    
   /** 
    * 1. 기능 :  세션 초기화
    * 2. 처리 개요 : 
    *          - Softlink 수신 처리를 담당하는 WCA 세션 Runnable 클래스 생성 및 세션 정보를 설정한다.
    *          - 수신 Thread 생성 및 start 시킨다.
    * 3. 주의사항
    * 
    * @return    성공여부 (성공 : 0, 실패 : -1)
    **/
    public int initWCASession() {
        try {	        
            String eventListenerClass = PropManager.getInstance().getProperty(TableInfoEx.T_SNAADPTER_PROP_GROUP_NAME, "sna.event.listener.class");
            WCAEventListener listener = (WCAEventListener)(Class.forName(eventListenerClass).newInstance());
            
            // 20090810 Start
            // wcaSessionThread = new WCASessionThread(sIpAddr, nPortNo, sAdapterGrpName, sAdapterName, sGroupCode, nSessNum, bBackupSessionPool, bLogYN, nLogLevel, nLogSize);            
            wcaSessionThread = new WCASessionThread(sNodeName, sIpAddr, nPortNo, sAdapterGrpName, sAdapterName, sGroupCode, nSessNum, bBackupSessionPool, bLogYN, nLogLevel, nLogSize);
            // 20090810 End
            
            wcaSessionThread.setTranTimeout(nTransTimeout);
            wcaSessionThread.registerEventHandler(listener);
            
            // 20090810 Start
            wcaSessionThread.setBackupEnableFlag(bBackupEnableFlag);
            // 20090810 End
            
			//threadSession = new Thread(getThreadGroup(),wcaSessionThread, wcaSessionThread.toString());
            
            // " " + sNodeName + "-" + sAdapterGrpName + "-" + sGroupCode + "-" +  nSessNum + " " 
            String sThreadName = MyUtil.replaceString(toString(), "<", "");
            sThreadName = MyUtil.replaceString(sThreadName, ">", "");
            threadSession = new Thread(getThreadGroup(), wcaSessionThread, sThreadName);
	        threadSession.setDaemon(false);
	        threadSession.start();     
            
	        return 0;
        }
        catch (Exception e) {
            if(adapter_logger.isError())  adapter_logger.error("initWCASesion] - [" + WCAException.E_ETC + "] " + toString() + " : " + e.toString(), e);
            return -1;
        }
	}
    
    /** 
    * 1. 기능 :  세션 종료
    * 2. 처리 개요 : 
    *          - WCA 세션 Runnable 클래스의 running 상태를 false로 설정한다.
    *          - Softlink TCP 세션 close한다.
    * 3. 주의사항
    **/
    public void stopAdapter() {
        wcaSessionThread.stopAdapter();     
        wcaSessionThread.closeSoftLink();
    }
    
    /** 
    * 1. 기능 :  INBOUND 핸들러 등록
    * 2. 처리 개요 : 
    *          - WCA 세션 Runnable 클래스의 INBOUND 핸들러 등록한다.
    * 3. 주의사항
    **/
    public void registerEventHandler(Object objHandler) {
        wcaSessionThread.registerEventHandler(objHandler);
        return;
    }
    
    /** 
    * 1. 기능 :  수신 Thread TCP 세션 상태를 설정
    * 2. 처리 개요 : 
    *          - WCA 세션 Runnable 클래스의 TCP 세션 상태를 설정한다.
    *            0 : 연결안됨, 1 : TCP 세션 연결, 2 : TCP 세션 사용중 (사용안함)
    * 3. 주의사항
    **/
    /*
    public void setSessionStat(int nSessStat) {
        wcaSessionThread.setSessionStat(nSessStat);
        return;
    }
    */
    
   /** 
    * 1. 기능 :  OUTBOUND 데이타 송신
    * 2. 처리 개요 : 
    * 3. 주의사항
    **/
    public int sendData(int nLen, byte[] pBuff) throws WCAException {
        return wcaSessionThread.sendData(nLen, pBuff);
    }
    
    /** 
    * 1. 기능 :  Softlink TCP 세션 가능 여부 반환
    * 2. 처리 개요 : 
    * 3. 주의사항
    * 
    * @return  Softlink TCP 세션 가능 여부 (true : 사용가능)
    **/
    public boolean isAvailable() {
        return wcaSessionThread.isAvailable();
    }
    
    /** 
    * 1. 기능 :  Softlink TCP 세션 close
    * 2. 처리 개요 : 
    * 3. 주의사항
    **/
    public void closeSoftLink() throws WCAException { 
        wcaSessionThread.closeSoftLink();
    }
}
