package com.eactive.eai.batch.osd;
import com.eactive.eai.common.dao.DAOException;
import com.eactive.eai.common.dao.DAOFactory;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.lifecycle.Lifecycle;
import com.eactive.eai.common.lifecycle.LifecycleException;
import com.eactive.eai.common.lifecycle.LifecycleListener;
import com.eactive.eai.common.lifecycle.LifecycleSupport;

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

public class OutsideManager implements Lifecycle
{
   /**
     * TelegramInfoManager Single Instance
     */
    private static OutsideManager instance = new OutsideManager();

    /**
     * LifeccyleSupport object
     */
    private LifecycleSupport lifecycle = new LifecycleSupport(this);

    /**
     * 기동 여부
     */
    private boolean started;

    /**
     * 전문 정보를 저장하는 collection
     */
    private HashMap<String, ArrayList<OutsideVO>> osdInfos;
    private HashMap<String, ArrayList<OutsideLinkVO>> osdLnkInfos;

    /**
    * 1. 기능 :  Default Constructor
    * 2. 처리 개요 : 전문(Telegram) 정보를 저장하기 위한 HashMap을 초기화한다.
    * 3. 주의사항
    *
    **/
    private OutsideManager() {
    	osdInfos = new HashMap<String, ArrayList<OutsideVO>>();
    	osdLnkInfos = new HashMap<String, ArrayList<OutsideLinkVO>>();
    }

    /**
    * 1. 기능 :  TelegramManager Singleton Object를 반환하는 getter method
    * 2. 처리 개요 : TelegramManager Singleton Object를 반환한다.
    * 3. 주의사항
    *
    * @return   TelegramManager Singleton object
    **/
    public static OutsideManager getInstance() {

        return instance;
    }


    /* ****************************************************************** */
    /*                  Web Agent 호출을 위한  메소드 정의                */
    /* ****************************************************************** */

    /**
     * 1.기능: 전문 Key에 해당하는 전문 객체를 삭제한다.
     * 구현 : by kscheon at 20080506
     */
    public void removeOutsideInfo(String bCode, String outCode)  throws Exception
    {
        
    	ArrayList<OutsideVO> oinfo = osdInfos.get(bCode);
    	
    	if (oinfo == null){
    		throw new RuntimeException("OutsideManager ] removeOutsideInfo - 삭제 OutsideVO가 존재하지 않습니다. - "+bCode +" , "+outCode);
    		
    	} else {
    		OutsideVO ovo = null;
    		for (int i=0;oinfo.size()>0 && i < oinfo.size(); i++){
    			ovo = (OutsideVO)oinfo.get(i);
    			if(outCode.equals(ovo.getOsdCode())){
    				oinfo.remove(i--);
    			}
    		}
    	}
    	
    	osdInfos.put(bCode, oinfo);
    }

    /**
     * 1.기능: 전문 Key에 해당하는 전문 객체를 다시 읽어온다.
     * 구현 : by kscheon at 20080506
     */
    /*
    public void updateOutsideInfo(OutsideVO vo)  throws Exception
    {
    	String bCode = vo.getBatchCode();
    	String outCode = vo.getOsdCode();
    	
    	ArrayList<OutsideVO> oinfo = osdInfos.get(bCode.trim());
    	
    	if (oinfo == null){
    		throw new RuntimeException("OutsideManager ] updateOutsideInfo - 수정될 OutsideVO가 존재하지 않습니다. - "+bCode);
    		
    	} else {
    		OutsideVO ovo = null;
    		for (int i=0; i < oinfo.size(); i++){
    			ovo = (OutsideVO)oinfo.get(i);
    			if(outCode.equals(ovo.getOsdCode())){
    				oinfo.remove(i);
    				oinfo.add(i, vo);
    			}
    		}
    	}
    	
    	osdInfos.put(bCode, oinfo);
    }
    */

    /**
     * 1.기능: 전문 Key에 해당하는 전문 객체를 다시 읽어온다.
     * 구현 : by dhjeong at 20091124
     */
    public void updateOutsideInfo(String bCode, String outCode)  throws Exception
    {
    	
    	ArrayList<OutsideVO> oinfo = osdInfos.get(bCode);
    	
    	if (oinfo == null){
    		oinfo = new ArrayList<OutsideVO>();
    	}
		OutsideVO ovo = null;
		for (int i=0; i < oinfo.size(); i++){
			ovo = (OutsideVO)oinfo.get(i);
			if(outCode.equals(ovo.getOsdCode())){
				oinfo.remove(i);
			}
		}

		DAOFactory daoFactory = DAOFactory.newInstance();
        OutsideDAO dao = (OutsideDAO)daoFactory.create(OutsideDAO.class);
    	OutsideVO vo = dao.getOutsideInfoByKey(bCode, outCode);
		oinfo.add(vo);

    	
    	osdInfos.put(bCode, oinfo);
    }

    
/**
     * 1.기능: 전문 Key에 해당하는 전문 객체를 삭제한다.
     * 구현 : by kscheon at 20080506
     */
    public void removeOutsideLinkInfo(String bCode, String outCode)  throws Exception
    {

    	ArrayList<OutsideLinkVO> linfo = osdLnkInfos.get(outCode);
    	
    	if (linfo == null){
    		throw new RuntimeException("[ OutsideManager ] removeOutsideLinkInfo - 삭제 OutsideLinkvoVO가 존재하지 않습니다. - "+bCode +" , "+outCode);
    		
    	} else {
    		OutsideLinkVO lvo = null;
    		for (int i=0; linfo.size() > 0 && i < linfo.size(); i++){
    			lvo = (OutsideLinkVO)linfo.get(i);
    			if(bCode.equals(lvo.getBatchCode())){
    				linfo.remove(i--);
    			}
    		}
    	}
    	
    	osdLnkInfos.put(outCode, linfo);
    }

    /**
     * 1.기능: 전문 Key에 해당하는 전문 객체를 다시 읽어온다.
     * 구현 : by kscheon at 20080506
     */
    public void updateOutsideLinkInfo(OutsideLinkVO vo)  throws Exception
    {
    	String outCode = vo.getOsdCode();
    	String linkCode = vo.getSyslinkCode().trim();
    	
    	ArrayList<OutsideLinkVO> linfo = osdLnkInfos.get(outCode.trim());
    	
    	if (linfo == null){
    		throw new RuntimeException("[ OutsideManager ] updateOutsideLinkInfo - 수정될 OutsideLinkVO가 존재하지 않습니다. - "+linkCode);
    		
    	} else {
    		OutsideLinkVO lvo = null;
    		for (int i=0; i < linfo.size(); i++){
    			lvo = (OutsideLinkVO)linfo.get(i);
    			if(linkCode.equals(lvo.getSyslinkCode().trim())){
    				linfo.remove(i);
    				linfo.add(i, vo);
    			}
    		}
    	}
    	osdLnkInfos.put(outCode, linfo);
    }

    /**
     * 1.기능: 전문 Key에 해당하는 전문 객체를 다시 읽어온다.
     * 구현 : by dhjeong at 20091124
     */
    public void updateOutsideLinkInfo(String bCode, String outCode )  throws Exception
    {
    	
    	ArrayList<OutsideLinkVO> linfo = osdLnkInfos.get(outCode.trim());
    	
    	if (linfo == null){
    		linfo = new ArrayList<OutsideLinkVO>(); 
    	}
		OutsideLinkVO lvo = null;
		for (int i=0; i < linfo.size(); i++){
			lvo = (OutsideLinkVO)linfo.get(i);
			if(bCode.equals(lvo.getBatchCode())){
				linfo.remove(i);
			}
		}
    	DAOFactory daoFactory = DAOFactory.newInstance();
        OutsideDAO dao = (OutsideDAO)daoFactory.create(OutsideDAO.class);
        ArrayList<OutsideLinkVO> voList = dao.getOutsideLinkInfoByOsdCode(bCode, outCode);

        for ( int inx= 0; inx < voList.size(); inx++){
        	OutsideLinkVO vo = voList.get(inx);
    		linfo.add(linfo.size(), vo);
        }
    	osdLnkInfos.put(outCode, linfo);
    }

    private void updateOutsideLinkIdPassword(OutsideLinkVO vo)  throws Exception
    {
        DAOFactory daoFactory = DAOFactory.newInstance();
        OutsideDAO dao = (OutsideDAO)daoFactory.create(OutsideDAO.class);
        dao.updateOutsideLinkInfo(vo);
        updateOutsideLinkInfo(vo);
    }

    /**
     * 1.기능: 전문 Key에 해당하는 전문 객체를 전체 HashMap에 추가한다.
     */
    /*
    public void addOutsideLinkInfo(OutsideLinkVO vo)  throws Exception
    {
    	
    	String oCode = vo.getOsdCode();
    
    	ArrayList<OutsideLinkVO> linfo = osdLnkInfos.get(oCode);
    	
    	if (linfo == null){  		
    		linfo = new ArrayList<OutsideLinkVO>();    		
    		linfo.add(linfo.size(), vo);
    		
    	} else {     		
    		linfo.add(linfo.size(), vo);
    	}
    	
    	osdLnkInfos.put(oCode, linfo);
    }
    */
    
    /**
     * 1.기능: 전문 Key에 해당하는 전문 객체를 전체 HashMap에 추가한다.
     */
    public void addOutsideLinkInfo(String bCode, String outCode)  throws Exception
    {
    	
    
    	ArrayList<OutsideLinkVO> linfo = osdLnkInfos.get(outCode);
    	
    	if (linfo == null){  		
    		linfo = new ArrayList<OutsideLinkVO>();    		
    	}
    	
    	DAOFactory daoFactory = DAOFactory.newInstance();
        OutsideDAO dao = (OutsideDAO)daoFactory.create(OutsideDAO.class);
        ArrayList<OutsideLinkVO> voList = dao.getOutsideLinkInfoByOsdCode(bCode, outCode);

        for ( int inx= 0; inx < voList.size(); inx++){
        	OutsideLinkVO vo = voList.get(inx);
    		linfo.add(linfo.size(), vo);
        }
    	
    	osdLnkInfos.put(outCode, linfo);
    }

    /**
     * Telegram Mapping 정보 조회 : --> 텔레그램 클래스, 메시지 메타코드
     */
    public Object[] getBatchCodeArray() {
        return this.osdInfos.keySet().toArray();
    }

    public ArrayList<OutsideVO> getOutsideInfo(String strBatchCode)
    {
        if (this.osdInfos == null || this.osdInfos.size() == 0) return null;
        return this.osdInfos.get(strBatchCode);
    }

    public OutsideVO getOutsideInfo(String processCode, String organCode)
    {
        ArrayList<OutsideVO> alist = this.getOutsideInfo(processCode);
        if (alist == null || alist.size() == 0) return null;
        
        for (int i=0; i<alist.size(); i++) {
            OutsideVO info = alist.get(i);
            if (organCode.equals(info.getOsdCode())) return info;
        }
        return null;
    }

    public ArrayList<OutsideLinkVO> getOutsideLinkInfo(String strOsdCode)
    {
        return this.osdLnkInfos.get(strOsdCode);
    }

    private ArrayList<OutsideLinkVO> getOutsideLinkInfo(String strProcCode, String strOsdCode)
    {
        ArrayList<OutsideLinkVO> all = getOutsideLinkInfo(strOsdCode);
        ArrayList<OutsideLinkVO> newall = new ArrayList<OutsideLinkVO>();
        for ( int inx = 0; inx < all.size(); inx++){
        	OutsideLinkVO vo = (OutsideLinkVO)all.get( inx );
        	if ( vo.getBatchCode().equals(strProcCode)){
        		newall.add(vo);
        	}
        }
    	return newall;
    }
    
    public void updateOsdIdPassword( String strProcCode, String strOsdCode, String userId, String userPassword )
    {
    	try {
    		ArrayList<OutsideLinkVO> alLink = getOutsideLinkInfo(strProcCode, strOsdCode);
    		for ( int inx = 0; inx < alLink.size(); inx++){
    			OutsideLinkVO vo = alLink.get(inx);
    			vo.setUserID(userId);
    			vo.setPwd(userPassword);
    			updateOutsideLinkIdPassword(vo);
    		}
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

    /* ****************************************************************** */
    /*                  Lifecycle 인터페이스에 정의된 메소드              */
    /* ****************************************************************** */

    /**
    * 1. 기능 :  Lifecycle의 start 메서드로 TelegramManager를 초기화하는 메서드
    * 2. 처리 개요 : TelegramDAO를 이용해 추출 전문 정보 모두를 가져와 초기화한다.
    * 3. 주의사항
    *
    * @exception    LifecycleException  이미 시작되었거나,
    *               EAIServerDAO를 통해 Rule 정보를 가져온다.
    *               DAOExcepiton이 발생될 경우
    **/
    public void start() throws LifecycleException
    {
        if (started)
            throw new LifecycleException("BECEAIMOS003");

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(STARTING_EVENT, this);

        DAOFactory daoFactory = DAOFactory.newInstance();
        OutsideDAO dao = null;
        try {
            dao = (OutsideDAO)daoFactory.create(OutsideDAO.class);
            this.osdInfos       = dao.getAllOutsideInfo();
            this.osdLnkInfos    = dao.getAllOutsideLinkInfo();
            //Object[] keys = this.osdInfos.keySet().toArray() ;

        } catch(DAOException e) {
            throw new LifecycleException(ExceptionUtil.getErrorCode(e,"BECEAIMOS004"));
        }

        started = true;

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(STARTED_EVENT, this);
    }

    /**
    * 1. 기능 :  Lifecycle의 stop 메서드로 EAIServerManager를 종료하는 메서드
    * 2. 처리 개요 : 멤버에 캐싱항 EAIServer Rule 정보를 clear한다.
    * 3. 주의사항
    *
    * @exception    LifecycleException  이미 종료된 경우 발생
    **/
    public void stop() throws LifecycleException {
        // Validate and update our current component state
        if (!started)
            throw new LifecycleException("BECEAIMOS005");

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(STOPING_EVENT, this);

        this.osdInfos.clear();
        this.osdLnkInfos.clear();

        started = false;
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(STOPPED_EVENT, this);
    }

    /**
    * 1. 기능 :  LifecycleListener를 등록하는 메서드
    * 2. 처리 개요 : LifecycleListener를 등록한다.
    * 3. 주의사항
    *
    * @param    listener    LifecycleEvent를 수신한 LifecycleListener
    **/
    public void addLifecycleListener(LifecycleListener listener)
    {
        lifecycle.addLifecycleListener(listener);
    }

    /**
    * 1. 기능 :  등록된 LifecycleListener 리스트를 반환하는 메서드
    * 2. 처리 개요 : 등록된 LifecycleListener 리스트를 반환하다.
    * 3. 주의사항
    *
    * @return   등록된 LifecycleListener 리스트
    **/
    public LifecycleListener[] findLifecycleListeners()
    {
        return lifecycle.findLifecycleListeners();
    }

    /**
    * 1. 기능 :  등록된 LifecycleListener를 삭제하는 메서드
    * 2. 처리 개요 : 파라미터의 LifecycleListener를 삭제한다.
    * 3. 주의사항
    *
    * @param    listener    삭제할 LifecycleListener
    **/
    public void removeLifecycleListener(LifecycleListener listener)
    {
        lifecycle.removeLifecycleListener(listener);
    }

    /**
    * 1. 기능 :  FlowRuleManager의 초기화 여부를 반환하는 getter 메서드
    * 2. 처리 개요 : FlowRuleManager의 초기화 여부를 반환한다.
    * 3. 주의사항
    *
    * @return   초기화 여부
    **/
    public boolean isStarted() {
        return this.started;
    }

}

