

package gov.va.med.cds.client.proxy;


import gov.va.med.cds.exception.ErrorCodeEnum;
import gov.va.med.cds.exception.SocketClientException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.transport.socket.SocketConnector;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;


/**
 * Concrete connection factory class used to create a
 * new blocking connection each time the getConnection
 * interface is called 
 * 
 * @author susarlan
 *
 */
public class BlockingConnectionFactory
    implements
        IBlockingConnectionFactory
{
    private static Log logger = LogFactory.getLog( BlockingConnectionFactory.class );

    private int connectionTimeoutMillis;
    private int readTimeoutMillis;
    private int idleTimeoutMillis;

    SocketConnector socketConnector = null;


    public void setSocketConnector( SocketConnector socketConnector )
    {
        this.socketConnector = socketConnector;
    }


    /***
     * Returns a new blocking connection to the the specified host and port.
     *  
     * TODO Modify signature to throw app friendly exception
     * 
     * @param : String host - host name of the server to which to connect to
     * @param : int port - port number on the host server to which to connect to
     * @throws : ConnectionException
     * @return : IBlockingConnection - a new blocking connection to the specified host and port
     */
    public SocketChannel getConnection( String host, int port )
    {

        SocketChannel socketChannel = null;

        InetAddress inetAddress = null;

        InetSocketAddress inetSocketAddress = null;

        try
        {
            inetAddress = InetAddress.getByName( host.trim() );

            inetSocketAddress = new InetSocketAddress( inetAddress, port );

            // The JDK supports timeout configuration only if the Socket is read/write using a channel 
            socketChannel = SocketChannel.open();

            socketChannel.socket().setSoTimeout( readTimeoutMillis );

            socketChannel.socket().setSoLinger( false, idleTimeoutMillis );

            socketChannel.socket().setTcpNoDelay( false );

            socketChannel.connect( inetSocketAddress );

        }
        catch ( UnknownHostException e1 )
        {
            logger.error( "Unknown host specified", e1 );
            throw new SocketClientException( ErrorCodeEnum.SOCKET_CLIENT_UNKNOWN_HOST_EXCEPTION, e1 );
        }
        catch ( Exception e )
        {
            logger.error( "Socket timeout exception occurred", e );
            throw new SocketClientException( ErrorCodeEnum.SOCKET_CLIENT_IO_EXCEPTION, e );
        }

        return socketChannel;
    }


    public void setConnectionTimeoutMillis( int connectionTimeoutMillis )
    {
        this.connectionTimeoutMillis = connectionTimeoutMillis;
    }


    public void setReadTimeoutMillis( int readTimeoutMillis )
    {
        this.readTimeoutMillis = readTimeoutMillis;
    }


    public void setIdleTimeoutMillis( int idleTimeoutMillis )
    {
        this.idleTimeoutMillis = idleTimeoutMillis;
    }

}
