package com.eactive.eai.adapter;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;

import org.slf4j.LoggerFactory;

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. 기능 : 어댑터 그룹 정보를 표현하는 Java Value Object 클래스.
* 2. 처리 개요 : 어댑터 그룹 정보를 정의한다.
* 3. 주의사항
*
* @author  :
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since   :
*/
public class AdapterGroupVO implements Serializable, Lifecycle
{
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
     * Default Logger
     */
    static Logger logger = (Logger) Logger.getLogger(Logger.LOGGER_ADAPTER);

    private String  name;                 //어뎁터업무그룹명[TSEAIAD01.AdptrBzwkGroupName]
    private String  type;                 //어댑터코드[TSEAIAD01.AdptrCd]
    private boolean usedFlag;             //어댑터사용여부[TSEAIAD01.AdptrUseYn]
    private String  description;          //어댑터업무그룹설명[TSEAIAD01.AdptrBzwkGroupDesc]
    private String  batchProcessCode;     //BATCH작업업무구분코드[TSEAIBJ06.BjobBzwkDstcd]
    private String  batchInstitutionCode; //BATCH작업업무구분코드[TSEAIBJ06.OsidInstiDstCd]

    /**
     * 어댑터 collection
     */
    private HashMap<String,AdapterVO> adapters;

    private Vector<AdapterVO> actives;
//    private Vector<AdapterVO> disables;

    /**
     * 어댑터 이름 리스트
     */
    private ArrayList<String> adapterNames;

    /**
     * index
     */
    private int idx;

    /**
     * 기동 여부
     */
    private boolean started;
    /**
     * LifecycleSupport instance
     */
    private LifecycleSupport lifecycle = new LifecycleSupport(this);

    /**
     * current transaction
     */
    private int currentTx;

    /**
    * 1. 기능 :  Defualt Constructor
    * 2. 처리 개요 :
    *     -
    * 3. 주의사항
    *
    **/
    public AdapterGroupVO() {
        this("");
    }

    /**
    * 1. 기능 :  어댑터 그룹명을 초기화하는 생성자 함수
    * 2. 처리 개요 : 어댑터 그룹명을 초기화한다.
    * 3. 주의사항
    *
    * @param name   어댑터 그룹명
    **/
    public AdapterGroupVO(String name) {
        this.name = name;
        this.adapters   = new HashMap<String,AdapterVO>();
        this.actives    = new Vector<AdapterVO>();
//        this.disables   = new Vector<AdapterVO>();
        this.adapterNames = new ArrayList<String>();
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getType() {
        return this.type;
    }

    public void setUsedFlag(boolean usedFlag) {
        this.usedFlag = usedFlag;
    }

    public boolean isUsedFlag() {
        return this.usedFlag;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getDescription() {
        return this.description;
    }


    /**
    * 1. 기능 : 어댑터 정보를 추가하는 메서드
    * 2. 처리 개요 : 어댑터 정보를 추가 한다.
    * 3. 주의사항
    *
    * @param    avo AdapterVO 객체
    *
    **/
    public void addAdapterVO(AdapterVO avo) {
        this.adapters.put(avo.getName(),avo);
        this.adapterNames.add(avo.getName());
    }

    /**
    * 1. 기능 : 어댑터 정보를 반환하는 메서드
    * 2. 처리 개요 : 어댑터 정보를 반환 한다.
    * 3. 주의사항
    *
    * @return    AdapterVO AdapterVO 객체
    *
    **/
    public AdapterVO getAdapterVO(String adapterName) {
        return (AdapterVO)adapters.get(adapterName);
    }

    /**
    * 1. 기능 : currentTx를 증가시키는 메서드
    * 2. 처리 개요 : currentTx를 증가시킨다.
    * 3. 주의사항
    *
    **/
    public synchronized void increase() {
        ++currentTx;
    }

    /**
    * 1. 기능 : currentTx를 감소시키는 메서드
    * 2. 처리 개요 : currentTx를 감소 시킨다.
    * 3. 주의사항
    *
    **/
    public synchronized void decrease() {
        --currentTx;
    }

    /**
    * 1. 기능 : currentTx getter 메서드
    * 2. 처리 개요 :
    * 3. 주의사항
    *
    * @return   int currentTx
    **/
    public int currentTx() {
        return this.currentTx;
    }

    /**
    * 1. 기능 :  Lifecycle의 start 메서드로 AdapterGroupVO 초기화하는 메서드
    * 2. 처리 개요 : AdapterVO를 초기화한다.
    * 3. 주의사항
    *
    * @exception    LifecycleException  이미 시작되었거나, AdapterVO를 통해 Rule 정보를 가져오다 DAOExcepiton이 발생될 경우
    *
    **/
    public void start() throws LifecycleException {

        if (started)
            throw new LifecycleException("BECEAIMAD030");

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

        if(!this.usedFlag){
            String code = "BECEAIMAD040";
            String[] msgArgs = new String[1];
            msgArgs[0] = name;
            String errText = ExceptionUtil.make(code, msgArgs);
            if (logger.isError()) logger.error(errText);
            throw new LifecycleException(errText);
        }

        AdapterVO avo = null;
        Iterator<AdapterVO> it = adapters.values().iterator();
        while(it.hasNext()) {
            avo = it.next();
            if(avo instanceof Lifecycle) {
                try {
                    LifecycleListener []listeners = this.lifecycle.findLifecycleListeners();
                    if(listeners != null) {
                        for(int j=0;j<listeners.length;j++) {
                            avo.addLifecycleListener(listeners[j]);
                        }
                    }
                    avo.setAdapterGroupVO(this);
                    avo.start();
                    active(avo);
                } catch(Exception e) {
                    disable(avo);
                    throw new LifecycleException(ExceptionUtil.getErrorCode(e, "BECEAIMAD031"));                }
            }
        }


        started = true;
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(STARTED_EVENT, this);

    }

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

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


        AdapterVO avo = null;
        Iterator<AdapterVO> it = adapters.values().iterator();
        while(it.hasNext()) {
            avo = it.next();
            if(!avo.isStarted()) continue;
            if(avo instanceof Lifecycle) {
                try {
                    avo.stop();
                } catch(Exception e) {
                    throw new LifecycleException(ExceptionUtil.getErrorCode(e, "BECEAIMAD033"));
                }
            }
        }
        started = false;
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(STOPPED_EVENT, this);
    }

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

    /**
     * 1. 기능 : 해당 어댑터를 active 그룹으로 변경한다.
     * 2. 처리 개요 : 해당 어댑터를 disble 그룹에서 삭제하고, active 그룹에 추가한다.
     * 3. 주의사항
     *
     * @param   vo  상태변경할 어댑터
     */
    public void active(AdapterVO vo) {
//        this.disables.remove(vo);
    	if (!actives.contains(vo) && vo.isStatus()) {
    		this.actives.add(vo);
    	}
    }

    /**
     * 1. 기능 : 해당 어댑터를 disble 그룹으로 변경한다.
     * 2. 처리 개요 : 해당 어댑터를 active 그룹에서 삭제하고, disble 그룹에 추가한다.
     * 3. 주의사항
     *
     * @param   vo  상태변경할 어댑터
     */
    public void disable(AdapterVO vo) {
        this.actives.remove(vo);
//        this.disables.add(vo);
    }

    /**
     * 1. 기능 : 어댑터 그룹에 속한 가용한 어댑터가 있는지 여부를 반환하는 메서드
     * 2. 처리 개요 : Active 그룹에 속한 어댑터가 있으면 true, 그렇지 않으면 false를 반환한다.
     * 3. 주의사항
     *
     * @return  어댑터 그룹에 속한 가용한 어댑터가 있는지 여부
     */
    public boolean isAlive() {
        if(this.actives.size()>0) return true;
        else return false;
    }


    /**
    * 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. 기능 :  어댑터 정보 Iteration 객체를 반환
    * 2. 처리 개요 : 어댑터 정보 Iteration 객체를 반환 한다.
    * 3. 주의사항
    *
    * @return    Iterator    어댑터 정보 Iteration 객체
    **/
    public Iterator<AdapterVO> getAdapters() {
        return this.adapters.values().iterator();
    }

	public HashMap<String,AdapterVO> getAllAdapters() {
		return this.adapters;
	}

    /**
    * 1. 기능 :  어댑터명 array를 반환
    * 2. 처리 개요 : 어댑터명 array를 반환한다.
    * 3. 주의사항
    *
    * @return    String[]    어댑터명 array
    **/
    public String[] getAdapterNames() {
        String[] names = new String[this.adapterNames.size()];
        for(int i=0;i<names.length;i++) {
            names[i] = (String)this.adapterNames.get(i);
        }
        return names;
    }

    /**
    * 1. 기능 :  다음 인덱스의 어댑터 정보를 반환
    * 2. 처리 개요 : 다음 인덱스의 어댑터 정보를 반환한다.
    * 3. 주의사항
    *
    * @return    AdapterVO    어댑터 정보
    **/
    public synchronized AdapterVO nextAdapterVO() {
        if(this.actives.size()==0) return null;
        try {
            if(idx>=this.actives.size()) idx=0;
            AdapterVO vo = this.actives.get(idx++);
            return   vo;
        } catch(Exception e) {
            if(this.actives.size()==0) return null;
            idx = 0;
            return this.actives.get(idx++);
        }
    }

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

    /**
    * 1. 기능 :  어댑터 정보를 String 형태로 반환하는 메서드
    * 2. 처리 개요 : String 형태로 어댑터 정보를 반환한다.
    * 3. 주의사항
    *
    * @return    String    어댑터 정보
    **/
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("\nAdapterGroupVO [ name=").append(name);
        sb.append(", type=").append(type);
        sb.append(", usedFlag=").append(usedFlag);
        sb.append(", description=").append(description);
        sb.append(", batchProcessCode=").append(batchProcessCode);
        sb.append(", batchInstitutionCode=").append(batchInstitutionCode);
        sb.append(", AdapterList=").append(adapters);
        sb.append(" ]");

        return sb.toString();
    }

    public void setBatchProcessCode(String batchProcessCode) {
        this.batchProcessCode = batchProcessCode;
    }

    public String getBatchProcessCode() {
        return this.batchProcessCode;
    }

    public void setBatchInstitutionCode(String batchInstitutionCode) {
        this.batchInstitutionCode = batchInstitutionCode;
    }

    public String getBatchInstitutionCode() {
        return this.batchInstitutionCode;
    }

}
