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

import com.eactive.eai.adapter.socket.common.CommonLib;
import com.eactive.eai.adapter.socket.config.SocketAdapterManager;
import com.eactive.eai.common.util.Logger;

import java.io.Serializable;

public class OutboundControl implements Serializable {

	private static final long serialVersionUID = 1L;
	private String          adapterGroupName;
	private byte[]          response;
	private byte[]          request;
	private Throwable       lastError;
	private Logger          logger;
    private static Logger   errLogger = SocketLogManager.getInstance().getErrLogger();
    private boolean         ready;
	private long            respTimeout;
    /**
	 * @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 request.
	 */
	public byte[] getRequest() {
		return request;
	}
	/**
	 * @param request The request to set.
	 */
	public void setRequest(byte[] request) {
		this.request = request;
	}
	/**
	 * @return Returns the resposne.
	 */
	public byte[] getResponse() {
		return response;
	}
	/**
	 * @param resposne The resposne to set.
	 */
	public synchronized void setResponse(byte[] response) {
		this.response = response;
	}

    public OutboundControl() {
        logger = SocketLogManager.getInstance().getLogger();
        ready  = false;
        respTimeout = 0;
	}

    public OutboundControl(String adapterGroupName) {
        this.adapterGroupName   = adapterGroupName;
        logger  = SocketLogManager.getInstance().getLogger( adapterGroupName );
    }

    public byte[] callService(String adapterGroupName, byte[] message) throws Exception {

        // Connection을 얻어온다...
        OutboundChannelManager mgr  = OutboundChannelManager.getInstance();

        SocketService service       = null;

        long start      = System.currentTimeMillis();
        long waitTime   = 0;
        long timeout    = SocketAdapterManager.getInstance().getTimeout( adapterGroupName );

        while ( true ) {
            service = mgr.getConnection(adapterGroupName);
            if ( service != null ) {
            	//break;
                try {
	            	//if ( service.getCurrentState() == CommonLib.PROCESSING_PROTOCOL && service.isConnected() ) {
	            	if ( service.isActive() && service.getCurrentState() == CommonLib.PROCESSING_PROTOCOL ) {
	            		break;
	            	} else if ( service.isActive() ) {
	            		mgr.addConnection( adapterGroupName, service);
	            	}
            	} catch( Throwable e ) {
            		continue;
            	}
            }

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

		if ( service == null ) {
            String errMsg = CommonLib.getMessage("BECEAIASO008", new String[]{ this.adapterGroupName } );

            logger.error( errMsg );
            logger.error( CommonLib.getDumpMessage( message ) );

            if ( logger != errLogger ) {
                errLogger.error( errMsg );
                errLogger.error( CommonLib.getDumpMessage( message ) );
            }
            throw new Exception( errMsg );
		}

		this.setRequest( message );

//bmchae - 이거 버그있음 - lock에 걸림
//System.out.println("//bmchae - 이거 버그있음 - lock에 걸림");
//Thread.dumpStack();

        try {
            service.setControl(this);
            service.notifyMessage();
            // 응답전문을 기다림...
            waitReply();
        } catch( Throwable e ) {
//bmchae
//e.printStackTrace();
            String errMsg = CommonLib.getMessage("BECEAIASO008", new String[]{ this.adapterGroupName } );
            lastError =  new Exception( errMsg );
        }

        if ( lastError != null ) {
            String errMsg = CommonLib.getMessage("BECEAIASO009", new String[]{ lastError.getMessage() });

            logger.error( errMsg, lastError );

            if ( logger != errLogger ) {
                errLogger.error( errMsg );
                errLogger.error( CommonLib.getDumpMessage( message ) );
            }
            throw new Exception( errMsg );
        }

		return this.response;
	}

    protected synchronized void waitReply() {
        //synchronized(request) {
            long  start = System.currentTimeMillis();
            if ( respTimeout == 0 )
                respTimeout = 60000L;
        	try {
        		while ( !ready ) {
                    this.wait( respTimeout );
                    break;
                }
        	} catch ( InterruptedException ie ) {}

            if ( respTimeout > 0 &&  ( System.currentTimeMillis() - start ) >= respTimeout ) {
                String errMsg = CommonLib.getMessage("BECEAIASO008", new String[]{ this.adapterGroupName } );
                lastError =  new Exception( errMsg );
            }
        //}
    }

    public void setRespTimeout(long timeout) {
        this.respTimeout = timeout;
    }

    public synchronized void wakeup() {
        //synchronized(request) {
            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 synchronized void setLastError(Throwable lastError) {
        this.lastError = lastError;
	}
}
