package com.eactive.eai.adapter.socket.service;

import java.io.Serializable;

import com.eactive.eai.adapter.socket.common.CommonLib;
import com.eactive.eai.adapter.socket.config.ConfigurationContext;
import com.eactive.eai.batch.doc.BatchDoc;
import com.eactive.eai.common.util.Logger;

public class InboundControl implements Serializable {

    private static final long serialVersionUID = 1L;

    static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);

    private String    adapterGroupName;
    private String    adapterName;
    private boolean   ready;
    private String    responseType;
    private long      timeout;
    private Throwable lastError;
    private BatchDoc  batchMsgDoc;

    public InboundControl(String adapterGroupName, String adapterName) {
        this.adapterGroupName = adapterGroupName;
        this.adapterName      = adapterName;
        this.lastError        = null;
        this.ready            = false;
    }

    public InboundControl(String adapterGroupName, String adapterName, long timeout) {
        this.adapterGroupName = adapterGroupName;
        this.adapterName      = adapterName;
        this.lastError        = null;
        this.ready            = false;
        this.timeout          = timeout;
    }

    public BatchDoc getBatchMsgDoc() {
        return batchMsgDoc;
    }
    public void setBatchMsgDoc(BatchDoc batchMsgDoc) {
        this.batchMsgDoc = batchMsgDoc;
    }
    public void initBatchMsgDocStage() {
        batchMsgDoc.getBatchMsg().getHeader().setRenamedFileName("");
        batchMsgDoc.getBatchMsg().getBody().setSubLayerCode("");
        batchMsgDoc.getBatchMsg().getBody().setPhaseType("");
        batchMsgDoc.getBatchMsg().getBody().setSndMsgCode("");
        batchMsgDoc.getBatchMsg().getBody().setRcvMsgCode("");
        batchMsgDoc.getBatchMsg().getBody().setPhaseStartTime("");
        batchMsgDoc.getBatchMsg().getBody().setPhaseEndTime("");
    }

    /**
     * @return Returns the code.
     */
    public String getAdapterGroupName() {
        return adapterGroupName;
    }
    /**
     * @param code The code to set.
     */
    public void setAdapterGroupName(String code) {
        this.adapterGroupName = code;
    }

    /**
     * @return Returns the responseType.
     */
    public String getResponseType() {
        return responseType;
    }
    /**
     * @param responseType The responseType to set.
     */
    public void setResponseType(String responseType) {
        this.responseType = responseType;
    }

    public boolean isSyncMode() {
        return this.responseType.equals( ConfigurationContext.SYNC_MODE );
    }

    /**
     * @return Returns the adapterName.
     */
    public String getAdapterName() {
        return adapterName;
    }
    /**
     * @param adapterName The adapterName to set.
     */
    public void setAdapterName(String adapterName) {
        this.adapterName = adapterName;
    }
    /**
     * @return Returns the request.
     */
    public byte[] getRequest() {
        return new byte[2];
    }

    /**
     * @param request The request to set.
     */
    public void setRequest(byte[] request) throws Exception {

    }
    /**
     * @return Returns the response.
     */
    public byte[] getResponse() {
        return new byte[2];
    }

    /**
    * @param response The response to set.
    */
    public void setResponse(byte[] response) {

    }

    public byte[] request() throws Exception {
        logger.debug("[ELINK]################ InboundControl.request() 호출됨.");
        long srtTime = 0;
        srtTime = System.currentTimeMillis();

        // Session pool에서 사용할 session을 얻어온다.
        // SessionManager는 SocketAdapterManager 에서 생성하여 사용함.
        SessionManager  mgr     = SessionManager.getInstance();
        SessionService  service  = null;

        long start    = System.currentTimeMillis();
        long waitTime = 0;

        while ( true ) {
            service = mgr.getSession( this.adapterGroupName );
            if ( service != null ) break;

            waitTime = System.currentTimeMillis() - start;
            if ( waitTime >= timeout ) 
            	break;
            try {
                Thread.sleep( 20L );
            } catch( InterruptedException e ) {}
        }

        if ( service == null )
            throw new Exception( CommonLib.getMessage("BECEAIASI004", new String[]{ adapterGroupName  } ));


        service.setControl( this );
        service.notifyMessage();    //wait 중인 SessionService 객체에 request 처리 호출

        //Request 처리가 완료 될 때까지 대기...처리가 완료되면 SessionServer에서 이 클래의 wakeup() 메소드 호출함.
        waitReply();

        if ( isSyncMode() && this.getResponse() == null || this.getResponse().equals("")) {
            throw new Exception( CommonLib.getMessage("BECEAIASI010") );
        }

         logger.debug("[ELINK]################ InboundControl.request() 종료. (수행 시간: "+ ((System.currentTimeMillis() - srtTime)/1000.0) +" Sec)");

        return this.getResponse();
    }

    protected synchronized void waitReply() {
        try {
            while ( !ready ) {
                this.wait();
            }
        } catch ( InterruptedException ie ) {}
    }

    public synchronized void wakeup() {
        this.ready  = true;
        try {
            this.notify();
        } catch( Throwable e ) {}
    }

    /**
     * @return Returns the lastError.
     */
    public Throwable getLastError() {
        return lastError;
    }
    /**
     * @param lastError The lastError to set.
     */
    public void setLastError(Throwable lastError) {
        this.lastError = lastError;
    }
}
