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

import com.eactive.eai.adapter.wca.WCASession;
import com.eactive.eai.adapter.wca.exception.WCAException;
import com.eactive.eai.adapter.wca.global.WCADefine;
import com.eactive.eai.adapter.wca.jdbc.JDBCException;
import com.eactive.eai.adapter.wca.jdbc.JDBCFactory;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.Logger;

import java.util.ArrayList;
import java.util.HashMap;


/** 
* 1. 기능 : SNAAdpaterManager(WCA) 관리, Singleton 패턴
* 2. 처리 개요 : 
* 3. 주의사항
*
* @author  : 
* @version : v 1.0.0
* @see : 
* @since   : 2005. 6. 22. 오후 4:49:17
*/
public class SNAAdapterManager 
{
    /**
     * SNAAdapter critical한 정보 로깅을 위한 logger 
     */
    Logger adapter_logger = Logger.getLogger(WCADefine.ADAPTER_LOGGER_NAME);    
       
    /** 
     * Adapter 맵
     * 키 : 어댑터 그룹 이름
     * 값 : SNAAdapter 클래스 오브젝트
     */
    HashMap 	adapterMap;    
    
    /** 
     * LU 정보 List (LU 이름이 정의되어 있을 경우 해당 LU 세션 그룹으로 데이타 송신하기 위함)
     * 키 : LU 이름
     * 값 : LUInfoDataEx 클래스 오브젝트
     */
    HashMap 	luMap;
         
    /**
     * SNAAdapterManager Single Instance
     */
    static SNAAdapterManager	smanager   = new SNAAdapterManager();
    
    /** 
     * 1. 기능 :  Default Constructor
     * 2. 처리 개요 : 
     *       - LU 정보를 로딩한다.
     * 3. 주의사항 
     **/
    private SNAAdapterManager() {
    	adapterMap 	= new HashMap();	// 어댑터 정보 Map 오브젝트 생성
    	luMap    	= new HashMap();	// LU 정보 Map 오브젝트 생성
        
    	// 모든 LU 정보를 LU 정보 테이블에서 로드하여 HashMap(luMap)에 저장    	
        loadLUInfos();
    }
   
    /** 
     * 1. 기능 :  모든 LU 정보를 LU 정보 테이블에서 로드하여 HashMap(luMap)에 저장
     * 2. 처리 개요
     * 3. 주의사항
     **/
    public synchronized void loadLUInfos() {
        JDBCFactory     	factory   	= JDBCFactory.newInstance();
        LUInfoJDBCEx      	jdbc        = null;

        try {
           	adapter_logger.warn("SNAAdapterManager:loadLUInfos> Start To Load Adapter LU Info.");
            
            jdbc    = (LUInfoJDBCEx)factory.create(LUInfoJDBCEx.class);
            luMap 	= jdbc.getLUInfos(EAIServerManager.getInstance().getLocalServerHostName());
                                   
        	adapter_logger.warn("SNAAdapterManager:loadLUInfos> Success To Load LU Info.");
        }
        catch (java.net.UnknownHostException host) {
            adapter_logger.error("SNAAdapterManager:loadLUInfos> " + host.getMessage(), host);  
        }
        catch (JDBCException e) {
//            e.printStackTrace();
           	adapter_logger.error("SNAAdapterManager:loadLUInfos> " + e.getMessage(), e);   
        }
    }   
    
    /** 
     * 1. 기능 :  LU 이름에 해당하는 LU 그룹 노드 이름 및 LU 그룹 이름 반환
     * 2. 처리 개요 : 
     * 		- LU 이름이 정의 되어 있으면 해당 LU 그룹 세션을 구한다.
     *      - 특정 LU로 데이터를 전송할때, 해당 LU를 포함하고 있는 노드 및 LU 그룹 정보를 추출하기 위해 사용된다.
     * 3. 주의사항 
     *
     * @param 	luName 	LU 이름
     * 
     * @return 	LU에 해당하는 LU 그룹 노드 이름 및 LU 그룹 이름을 포함하는 ArrayList	
     **/
    public ArrayList getNodeAndGroupName(String luName) throws WCAException {
     	ArrayList	alInfo = new ArrayList();
     	
        if (luName == null) {
        	adapter_logger.error("SNAAdapterManager:getNodeAndGroupName> LU Name is NULL");        	
         	alInfo.add("");		// Dummy 노드 이름
         	alInfo.add("");		// Dummy LU 그룹 이름
         	return alInfo;
        }
        
        if (luName.trim().equals("")) {
        	adapter_logger.error("SNAAdapterManager:getNodeAndGroupName> LU Name Length is 0");        	
         	alInfo.add("");
         	alInfo.add("");
         	return alInfo;
        }
         
        LUInfoDataEx luInfo = (LUInfoDataEx)luMap.get(luName);
        if (luInfo == null) {
        	adapter_logger.error("SNAAdapterManager:getGroupCode> " + WCAException.displayError(WCAException.E_LUNAME_NO_EXIST, "LU 이름  = " + luName));
            throw new WCAException(WCAException.E_LUNAME_NO_EXIST, "LU 이름  = " + luName);
        }
         
        alInfo.add(luInfo.getNodeName());
        alInfo.add(luInfo.getGroupName());
         
        return alInfo; 
    }
     
    /** 
     * 1. 기능 :  SNAAdapterManager Singleton Object 반환
     * 2. 처리 개요 : SNAAdapterManager Singleton Object 반환한다.
     * 3. 주의사항 
     *
     * @return   SNAAdapterManager Singleton object
     **/
    public static SNAAdapterManager getInstance() {
		if (smanager == null) {  
			smanager = new SNAAdapterManager();
		}
		
		return smanager;
    }    
    
    /** 
     * 1. 기능 : 어댑터 그룹에 해당하는 SNA Adapter 오브젝트를 어댑터 맵에 추가한다.
     * 2. 처리 개요 : 
     * 3. 주의사항
     * 
     * @param    sAdapterGrpName     어댑터 그룹 이름
     * @param    sessgroups          SessionGroupData Object를 저장한 HashMap
     **/
    public void insertSnaAdapter(String adapterGroupName, SNAAdapter snaAdapter) {
    	adapter_logger.warn("SNAAdapterManager:insertAdapterToMap> Put Adapter in Adapter Map, sAdapterGrpName = " + adapterGroupName);    	
    	synchronized (adapterMap) {
    		adapterMap.put(adapterGroupName, snaAdapter);
    	}
     	return;
    }    
    
    /** 
     * 1. 기능 :  어댑터 그룹에 해당하는 어댑터 오브젝트를 구함
     * 2. 처리 개요 : 
     * 3. 주의사항
     * 
     * @param    sAdapterGrpName     어댑터 그룹 이름
     * 
     * @param    SNAAdapter 오브젝트
     **/    
    public SNAAdapter selectSnaAdapter(String adapterGroupName) {
    	SNAAdapter snaAdapter = (SNAAdapter)adapterMap.get(adapterGroupName);
     	return snaAdapter;    	
    }
    
    /** 
     * 1. 기능 :  어댑터 맵에서 어댑터 그룹에 해당하는 SNA Adapter 오브젝트를 삭제한다.
     * 2. 처리 개요 : 
     *       - SNAAdapter를 HashMap(adapters)에 삭제한다.  
     * 3. 주의사항 
     *
     * @param    sAdapterGrpName     어댑터 그룹 이름
     **/
    public void deleteSnaAdapter(String adapterGroupName) {
    	adapter_logger.warn("SNAAdapterManager:deleteSnaAdapter> Delete Adapter in Adapter Map, sAdapterGrpName = " + adapterGroupName);     	
        try {   
        	synchronized (adapterMap) {
        		adapterMap.remove(adapterGroupName);
        	}
        }
        catch (Exception e) {
        	adapter_logger.warn("SNAAdapterManager:deleteSnaAdapter> Exception", e);        	
        	// e.printStackTrace();
        }
    }
        
   
    /** 
     * 1. 기능 :  어댑터 그룹 이름에 해당하는 SNA 어댑터를 종료한다.
     * 2. 처리 개요 :
     * 3. 주의사항 
     *
     * @param	adapterGroupName    어댑터 그룹 이름
     * @param	adapterName			어댑터 이름
     **/
    public void stopAdapter(String adapterGroupName, String adapterName) {
    	String sLogStr = "[" + adapterGroupName + "][" + adapterName + "]";
    	
    	adapter_logger.warn("SNAAdapterManager:stopAdapter> Try To Stop Adapter, " + sLogStr);
    	
        SNAAdapter snaAdapter = selectSnaAdapter(adapterGroupName);
        if (snaAdapter == null) {
        	adapter_logger.warn("SNAAdapterManager:stopAdapter> There is No Adapter, So Return, " + sLogStr);
        	return;        	
        }
        
        adapter_logger.warn("SNAAdapterManager:stopAdapter> Strart To Stop Adapter, " + sLogStr);        
        snaAdapter.stopAdapter();
        
        /*
        adapter_logger.warn("SNAAdapterManager:stopAdapter> Try To Delete Adapter From Adapter Map, " + sLogStr);        
        deleteSnaAdapter(adapterGroupName);
        */
        
        adapter_logger.warn("SNAAdapterManager:stopAdapter> Success To Stop Adapter, " + sLogStr);        
    }
    
    /** 
     * 1. 기능 :  어댑터 그룹, LU 그룹에 해당하는 WCA 세션 반환
     * 2. 처리 개요 :
     * 3. 주의사항 
     *
     * @param    sAdapterGrpName     어댑터 그룹 이름
     * @param	sNodeName			LU 그룹 노드 이름
     * @param    sGroupCode          LU 그룹 이름
     **/
    public WCASession getWCASession(String adapterGroupName, String nodeName, String lugrpName) throws WCAException {
    	// 어댑터 그룹에 해당하는 어댑터 오브젝트를 구함
        SNAAdapter snaAdapter = selectSnaAdapter(adapterGroupName);
        if (snaAdapter == null) {
        	adapter_logger.warn("SNAAdapterManager:getWCASession> There is No Adapter, sAdapterGrpName = [" + adapterGroupName + "]");        	
            throw new WCAException(WCAException.E_ADAPTERGROUP_NO_EXIST);
        }
        
        // LU 그룹 노드 정보와 LU 그룹명이 두가지 다 있거나, 두가지 다 없어나 해야 한다.
        if (nodeName.equals("") || lugrpName.equals("")) {
            return snaAdapter.getWCASessionInSessionPoolList();
        }
        else {
        	return snaAdapter.getWCASessionInSessionPoolList(nodeName, lugrpName);        	
        }  
    }    

    /** 
     * 1. 기능 :  BACKUP POOL 수동 전환 모드
     * 2. 처리 개요 : 
     * 3. 주의사항 
     *
     * @param    sAdapterGrpName     어댑터 그룹 이름
     * @param	sNodeName			LU 그룹 노드 이름
     * @param    sGroupCode          LU 그룹 이름
     * @param	flag     			백업 여부 (true : 백업, false : 정상)
     **/
    public void setManualBackupMode(String sAdapterGroupName, String sNodeName, String sGroupCode, boolean flag) throws WCAException {
    	adapter_logger.warn("SNAAdapterManager:setManualBackupMode> [" + sAdapterGroupName + "][" + sNodeName + "][" + sGroupCode + "][" + flag + "]");
        
        SNAAdapter sAdapter = (SNAAdapter)adapterMap.get(sAdapterGroupName);
        if (sAdapter == null) {
        	adapter_logger.warn("SNAAdapterManager:setManualBackupMode> There is No Adapter, sAdapterGrpName = [" + sAdapterGroupName + "]");        	
        	throw new WCAException(WCAException.E_SOFTLINK_NOT_FOUND_SESSION, "수동 백업/복구 모드 전환시 발생  [" +sAdapterGroupName+"]");
        }
        
        sAdapter.setManualBackupMode(sNodeName, sGroupCode, flag);
    }    
    
   
    /** 
     * 1. 기능 :  어댑터 그룹에 속한 LU 그룹과 현재 설정된 백업 모드 정보 반환
     * 2. 처리 개요 : 모니터링에서 사용하기 위한 함수임
     * 3. 주의사항 
     *
     * @param    sAdapterGrpName     어댑터 그룹 이름
     * 
     * @return   LU 그룹 및 백업 모드 정보 [
     *           Key : LU 그룹 이름, value : Boolean Object 백업 모드 정보 (true : 백업, false : 정상)
     **/
    public HashMap getLuGrpBackupModeMap(String adapterGroupName) throws WCAException {
        SNAAdapter snaAdapter = selectSnaAdapter(adapterGroupName);
        if (snaAdapter == null) {
        	adapter_logger.warn("SNAAdapterManager:getLuGrpBackupModeMap> There is No Adapter, sAdapterGrpName = [" + adapterGroupName + "]");        	
        	return new HashMap();
        }
        
        return snaAdapter.getLuGrpBackupModeMap();
    }    
      
        
    /** 
     * 1. 기능 :  모니터링으로부터 새로운 LU 그룹이 추가되었다는 Command를 처리
     * 2. 처리 개요 : 
     * 3. 주의사항 
     *
     * @param   data     		LU 그룹 정보 오브젝트
     **/        
    public void insertLuGroupInfoEx(SessionGroupDataEx lugrpInfo) throws WCAException {
    	SNAAdapter snaAdapter = selectSnaAdapter(lugrpInfo.getAdapterGroupName());
    	
        // adapter db에 정의되지 않았을 경우
        if (snaAdapter == null) {
            adapter_logger.warn("SNAAdapterManager:insertLuGroupInfoEx> " + lugrpInfo.getAdapterGroupName() +"이 구동되지 않았습니다.");
            return;
        }
        
        snaAdapter.insertLuGroupInfoEx(lugrpInfo);
    	
    	return;
    }    
    
    /** 
     * 1. 기능 :  모니터링으로부터 새로운 LU 그룹이 추가되었다는 Command를 처리
     * 2. 처리 개요 : 
     * 3. 주의사항 
     *
     * @param   data     		LU 그룹 정보 오브젝트
     **/        
    public void deleteLuGroupInfoEx(SessionGroupDataEx lugrpInfo) throws WCAException {
    	SNAAdapter snaAdapter = selectSnaAdapter(lugrpInfo.getAdapterGroupName());
    	
        // adapter db에 정의되지 않았을 경우
        if (snaAdapter == null) {
            adapter_logger.warn("SNAAdapterManager:deleteLuGroupInfoEx> " + lugrpInfo.getAdapterGroupName() +"이 구동되지 않았습니다.");
            return;
        }
        
        snaAdapter.deleteLuGroupInfoEx(lugrpInfo);
    	
    	return;
    }     
    
    /** 
     * 1. 기능 :  모니터링으로부터 LU 그룹 정보가 갱신되었다는 Command를 처리
     * 2. 처리 개요 : 
     * 3. 주의사항 
     *
     * @param   data     		LU 그룹 정보 오브젝트
     **/        
    public void updateLuGroupInfoEx(SessionGroupDataEx lugrpInfo) throws WCAException {
    	SNAAdapter snaAdapter = selectSnaAdapter(lugrpInfo.getAdapterGroupName());
    	
        // adapter db에 정의되지 않았을 경우
        if (snaAdapter == null) {
            adapter_logger.warn("SNAAdapterManager:updateLuGroupInfoEx> " + lugrpInfo.getAdapterGroupName() +"이 구동되지 않았습니다.");
            return;
        }
        
        snaAdapter.updateLuGroupInfoEx(lugrpInfo);
    	
    	return;
    }          
    
    /** 
     * 1. 기능 :  모니터링으로부터 WCA AppCode 정보가 갱신되었다는 Command를 처리 (updateWcaInfo 함수를 참조하여 개발)
     * 2. 처리 개요 : 
     * 3. 주의사항 
     *
     * @param   wcaInfo     		WcaInfoDataEx 오브젝트
     **/        
    public void updateWcaAppCodeEx(WcaInfoDataEx wcaInfo) throws WCAException {
        adapter_logger.warn("SNAAdapterManager:updateWcaAppCodeEx> sEaiNodeName = [" + wcaInfo.sEaiNodeName + "], sEaiInstanceName = [" + wcaInfo.sEaiInstanceName + "]");
        adapter_logger.warn("SNAAdapterManager:updateWcaAppCodeEx> sAdapterGroupName = [" + wcaInfo.sAdapterGroupName + "], sAdapterName = [" + wcaInfo.sAdapterName + "]");
        
    	SNAAdapter snaAdapter = selectSnaAdapter(wcaInfo.sAdapterGroupName);
    	
        // adapter가 db에 정의되지 않았을 경우
        if (snaAdapter == null) {
            adapter_logger.warn("SNAAdapterManager:updateWcaAppCodeEx> " + wcaInfo.sAdapterGroupName +"이 구동되지 않았습니다.");
            return;
        }
    	
        if (snaAdapter.adapterName.equals(wcaInfo.sAdapterName) == false) {
            adapter_logger.warn("SNAAdapterManager:updateWcaAppCodeEx> Adapter Name is not same, snaAdapter.adapterName = [" + snaAdapter.adapterName + "]");
            return;        	
        }
        
        try {
        	snaAdapter.updateWcaAppCodeEx(wcaInfo);
        }
        catch (Exception e) {
        	adapter_logger.warn("SNAAdapterManager:updateWcaAppCodeEx> [" + wcaInfo.sAdapterGroupName + "] Exception Msg = " + e.getMessage());        	
        }
        
    	return;
    }        
    
    /** 
     * 1. 기능 :  모니터링으로부터 WCA 정보가 갱신되었다는 Command를 처리
     * 2. 처리 개요 : 
     * 3. 주의사항 
     *
     * @param   data     		WCA 정보 오브젝트
     **/      
    public void updateWcaInfo(WcaInfoDataEx wcaInfo) {
    	SNAAdapter snaAdapter = selectSnaAdapter(wcaInfo.sAdapterGroupName);
    	
        // adapter db에 정의되지 않았을 경우
        if (snaAdapter == null) {
            adapter_logger.warn("SNAAdapterManager:updateWcaInfo> " + wcaInfo.sAdapterGroupName +"이 구동되지 않았습니다.");
            return;
        }
        
    	if (wcaInfo.sAdapterName.equals(snaAdapter.adapterName) == false) {
    		adapter_logger.warn("SNAAdapterManager:updateWcaAppCodeEx> " + wcaInfo.sAdapterGroupName +"이 구동되지 않았습니다.");
    		return;
    	}
    	
        try {
        	snaAdapter.updateWcaInfo();
        }
        catch (Exception e) {
        	adapter_logger.warn("SNAAdapterManager:updateWcaInfo> [" + wcaInfo.sAdapterGroupName + "] Exception Msg = " + e.getMessage());        	
        }
    	
    	return;    	
    }
    
    /** 
     * 1. 기능 :  어댑터 그룹에 속한 전체 LU 그룹 갯수를 구함.
     * 2. 처리 개요 : 어댑터로 데이터를 송신할때, WCA 세션을 찾을때 사용함
     * 3. 주의사항 
     *
     * @param   adapterGroupName   어댑터 그룹 이름
     * 
     * @return	어댑터 그룹에 속한 전체 LU 그룹 갯수
     **/     
    public int getLuGroupMapCount(String adapterGroupName) { 	
    	SNAAdapter	snaAdapter = selectSnaAdapter(adapterGroupName);
    	
        // adapter db에 정의되지 않았을 경우
        if (snaAdapter == null) {
            adapter_logger.warn("SNAAdapterManager:getLuGroupMapCount> " + adapterGroupName +"이 구동되지 않았습니다.");
            return 0;
        }
        
    	return snaAdapter.getLuGroupMapCount();
    }
}
