package com.eactive.eai.adapter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;


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 com.eactive.eai.common.util.Logger;

/**
* 1. 기능 : 어댑터 정보를 DB로 부터 로딩해 메모리에 관리하는 Manager 클래스
* 2. 처리 개요 : 어댑터 정보에 저장된 정보를 메모리에 로딩 관리한다.
* 3. 주의사항
*
* @author  :
* @version : v 1.0.0
* @see : Lifecycle
* @since   :
*/
public class AdapterManager  implements Lifecycle
{
    /**
     * Default Logger
     */
    static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);

    /**
     * AdapterManager Single Instance
     */
    private static AdapterManager instance = new AdapterManager();
    /**
     * 기동 여부
     */
    private boolean started;
    /**
     * 어댑터 정보를 저장하는 collection
     */
    private HashMap<String, AdapterGroupVO> adapterGroups = new HashMap<String, AdapterGroupVO>();
    /**
     * LifeccyleSupport object
     */
    private LifecycleSupport lifecycle = new LifecycleSupport(this);

    /**
    * 1. 기능 :  Default Constructor
    * 2. 처리 개요 :
    * 3. 주의사항
    *
    **/
    private AdapterManager() {
    }

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

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

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

        this.adapterGroups.clear();

        ArrayList<AdapterGroupVO> groups = null;
        AdapterDAO dao = null;
        try {
            dao = (AdapterDAO)DAOFactory.newInstance().create(AdapterDAO.class);
            groups = dao.getAllAdapterGroups();

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

        AdapterGroupVO gvo = null;
        //AdapterVO avo = null;
        for(int i=0;i<groups.size();i++) {
            gvo = (AdapterGroupVO)groups.get(i);
            ArrayList<AdapterVO> all = null;
            try {
                all = dao.getAllAdapters(gvo.getName());
                for(int j=0;j<all.size();j++) {
                    AdapterVO vo = all.get(j);
                    gvo.addAdapterVO(vo);
                }
            } catch(DAOException e) {
                throw new LifecycleException(ExceptionUtil.getErrorCode(e, "BECEAIMAD017"));
            }

            String[] msgArgs = new String[1];
            msgArgs[0] = gvo.toString();
            if (logger.isDebugEnabled()) logger.debug(ExceptionUtil.make("BDCEAIMAD018", msgArgs));
            addAdapterGroupVO(gvo);



            if(gvo instanceof Lifecycle) {
                try {
                    LifecycleListener listeners[] = this.lifecycle.findLifecycleListeners();
                    if(listeners!=null) {
                        for(int j=0;j<listeners.length;j++) {
                            gvo.addLifecycleListener(listeners[j]);
                        }
                    }

                    if(!gvo.isUsedFlag()) {
                        if (logger.isDebugEnabled()) logger.debug("Not Used Adapter>> "+gvo);
                        continue;
                    }
                    gvo.start();
                } catch(Exception e) {
                    throw new LifecycleException(ExceptionUtil.getErrorCode(e, "BECEAIMAD019"));
                }
            }
        }
        started = true;
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(STARTED_EVENT, this);
    }

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

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

        for(Iterator<AdapterGroupVO> it = this.adapterGroups.values().iterator();it.hasNext();) {
            AdapterGroupVO vo = it.next();
            try {
                if(!vo.isStarted()) continue;
                if(vo instanceof Lifecycle) {
                    vo.stop();
                }
            } catch(LifecycleException e) {
                String msgArgs[] = new String[1];
                msgArgs[0] = vo.toString();
                String errText = ExceptionUtil.make("BECEAIMAD021", msgArgs);
                if (logger.isError()) logger.error(errText);
                throw new LifecycleException(ExceptionUtil.getErrorCode(e, errText));
            }
        }

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

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

    /**
    * 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. 기능 :  어댑터 정보를 찾아 반환하는 메서드
    * 2. 처리 개요 : 어댑터 정보를 찾아 반환한다.
    * 3. 주의사항
    *
    * @param    adapterGroupName    어댑터그룹명
    * @param    adapterName    어댑터명
    * @return   어댑터 정보 VO 객체
    **/
    public AdapterVO getAdapterVO(String adapterGroupName, String adapterName) {
        AdapterGroupVO gvo = (AdapterGroupVO)adapterGroups.get(adapterGroupName);
        if(gvo==null) return null;

        return (AdapterVO)gvo.getAdapterVO(adapterName);
    }

    /**
    * 1. 기능 :  어댑터 그룹 정보를 찾아 반환하는 메서드
    * 2. 처리 개요 : 어댑터 그룹 정보를 찾아 반환한다.
    * 3. 주의사항
    *
    * @param    adapterGroupName    어댑터그룹명
    * @return   어댑터 그룹 정보 VO 객체
    **/
    public AdapterGroupVO getAdapterGroupVO(String adapterGroupName) {
        return (AdapterGroupVO)adapterGroups.get(adapterGroupName);
    }

    public AdapterGroupVO getAdapterGroupInDB(String adapterGroupName) {
        try {
        	AdapterDAO dao = (AdapterDAO)DAOFactory.newInstance().create(AdapterDAO.class);
        	AdapterGroupVO vo = dao.getAdapterGroup(adapterGroupName);
            ArrayList<AdapterVO> all = null;

            all = dao.getAllAdapters(adapterGroupName);
            for(int j=0;j<all.size();j++) {
                AdapterVO avo = all.get(j);
                vo.addAdapterVO(avo);
            }

        	return vo;

        } catch(DAOException e) {
            logger.error( e.getMessage(), e);
            return null;
        }

    }
    
    /**
    * 1. 기능 :  어댑터 그룹 정보를 추가하는 메서드
    * 2. 처리 개요 : 어댑터 그룹 정보를 추가한다.
    * 3. 주의사항
    *
    * @param    vo    어댑터그룹 VO
    **/
    public void addAdapterGroupVO(AdapterGroupVO vo) {
        if(vo!=null)
            adapterGroups.put(vo.getName(),vo);
    }

    /**
    * 1. 기능 :  모든 어댑터 그룹 정보를 찾아 반환하는 메서드
    * 2. 처리 개요 : 모든 어댑터 그룹 정보를 찾아 HashMap 객체로반환한다.
    * 3. 주의사항
    *
    * @return   어댑터 그룹 정보 VO 객체 Collection
    **/
    public HashMap<String, AdapterGroupVO> getAllAdapterGroupVO() {
        return adapterGroups;
    }

    /**
    * 1. 기능 :  모든 어댑터 그룹명을 찾아 반환하는 메서드
    * 2. 처리 개요 : 모든 어댑터 그룹명을 찾아 List 객체로 반환한다.
    * 3. 주의사항
    *
    * @return   어댑터 그룹명 리스트
    **/
    public List<String> getAllAdapterGroupNames() {
        ArrayList<String> al = new ArrayList<String>();
        Iterator<String> it = this.adapterGroups.keySet().iterator();
        while(it.hasNext()) {
            al.add(it.next());
        }
        Collections.sort(al);
        return al;
    }

    /**
    * 1. 기능 :  어댑터 그룹정보를 갱신하는 메서드
    * 2. 처리 개요 : 어댑터 그룹정보를 갱신한다.
    * 3. 주의사항
    *
    * @param   vo   어댑터 그룹 VO 객체
    **/
    //db update code 필요!!
    public void updateAdapterGroupVO(AdapterGroupVO vo) {
        if(vo!=null)
            adapterGroups.put(vo.getName(),vo);
    //db update code 넣을것..
	}

    /**
    * 1. 기능 :  어댑터 그룹정보를 삭제하는 메서드
    * 2. 처리 개요 : 어댑터 그룹정보를 삭제한다.
    * 3. 주의사항
    *
    * @param   vo   어댑터 그룹명
    **/
    public void removeAdapterGroupVO(String name){
        adapterGroups.remove(name);
    }

    /**
    * 1. 기능 :  debug String을 리턴하는 메서드
    * 2. 처리 개요 :
    * 3. 주의사항
    *
    **/
    public void print() {
        if (logger.isDebugEnabled()) logger.debug("AdapterManager] All Adapter List>> "+this.adapterGroups);
    }
}
