package cdac.medinfo.sdk.hl7282.hl7net.upperlayer;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Locale;

import cdac.medinfo.sdk.hl7282.hl7net.commons.IBatchProcessor;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IFragmentProcessor;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IMLLP;
import cdac.medinfo.sdk.hl7282.commoninterface.ISingleCollection;
import cdac.medinfo.sdk.hl7282.utils.HL7Config;
import cdac.medinfo.sdk.hl7282.utils.HL7Logger;
import cdac.medinfo.sdk.hl7282.utils.ResourceBundleWrapper;

/**
 * The Class SCPSession.
 */
public class ServerSession   
{
	

	/** The controller. */
	private Controller controller = null;

	/** The  objIprocess handler. */
	private IProcessHandler objIProcessHandler = null;

	/**The Fragment Processor */
	private IFragmentProcessor objFragmentProcessor = null;

	/** The MLLP Processor **/
	private IMLLP objIMLLP = null;

	private int iReadMaxLength,iWriteMaxLength;

	/**The Batch Processor */
	private IBatchProcessor objBatchProcessor = null;

	private int itimeout = 0;

	
	/**
	 * Constructs ServerSession
	 */
	public ServerSession() throws IOException
	{
		controller = new Controller();
	}

	/**
	 * Sets the Fragment Processor
	 * @param objIFragmentProcessor the objIFragmentProcessor to set
	 */
	public void setFragmentProcessor(IFragmentProcessor objIFragmentProcessor) 
	{
		this.objFragmentProcessor = objIFragmentProcessor;
	}

	/**
	 * Sets the MLLP Processor.
	 * @param objIMLLP the MLLP processor to set.
	 */
	public void setMLLPProcessor(IMLLP objIMLLP)
	{
		this.objIMLLP = objIMLLP;
	}

	/**
	 * Sets the Batch Processor
	 * @param objIBatchProcessor the BatchProcessor to set
	 */
	public void setBatchProcessor(IBatchProcessor objIBatchProcessor) 
	{
		this.objBatchProcessor = objIBatchProcessor;
	} 	


	/**
	 * Gets the IProcessHandler.
	 * @return IProcessHandler - the IProcessHandler
	 */
	public IProcessHandler getIProcessHandler() 
	{
		return objIProcessHandler;
	}

	/**
	 * Sets the IProcessHandler.
	 * @param objIProcessHandler new IIProcessHandler
	 */
	public void setIProcessHandler(IProcessHandler objIProcessHandler)
	{
		this.objIProcessHandler = objIProcessHandler;
	}

	/**
	 * Sets max length limit of reading and writing. 
	 * @param iReadLength value of Reading max length
	 * @param iWriteLength value of Writing max length
	 */
	public void setReadWriteLength(int iReadLength,int iWriteLength)
	{
		if(iReadLength>0 && iWriteLength>0)
		{
			iReadMaxLength = iReadLength;
			iWriteMaxLength = iWriteLength;	
		}
		else
		{
			if(iReadLength>=0)
			{
				iReadMaxLength = iReadLength;
			}
			if(iWriteLength>=0)
			{
				iWriteMaxLength = iWriteLength;	
			}
			if(HL7Config.createInstance().isLoggingOn())
			{
				HL7Logger objHL7Logger = HL7Logger.getLogger();
				String strLogMessage = ResourceBundleWrapper.getValue("warnings","Fragment_InvalidReadersWritersLength",new Locale(HL7Config.createInstance().getLocale()));
				objHL7Logger.log(strLogMessage);
			}
		}
	}

	/**
	 * Start.
	 * 
	 * @param strIP the ip address of server
	 * @param iPort the port on which server should listen
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public void start(String strIP, int iPort) throws IOException
	{
		start(new InetSocketAddress(strIP,iPort));
	}

	/**
	 * 
	 * @param iPort int value of port.
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public void start(int iPort)throws IOException
	{
		start(new InetSocketAddress(InetAddress.getLocalHost(),iPort));
	}

	/**
	 * 
	 * @param ip instance of INet Address.
	 * @param iPort int value of port.
	 * @throws IOException  Signals that an I/O exception has occurred.
	 */
	public void start(InetAddress ip, int iPort)throws IOException
	{
		start(new InetSocketAddress(ip,iPort));
	}


	private void initController()throws IOException
	{

		//		controller.setWaitPeriod(waitPeriod);
		controller.setIProcessHandler(objIProcessHandler);

		if(objFragmentProcessor != null)
			objFragmentProcessor.setMaxLength(iWriteMaxLength);
		controller.setFragmentProcessor(objFragmentProcessor);
		controller.setMLLPProcessor(objIMLLP);

		controller.setBatchProcessor(objBatchProcessor);
		controller.setReadWriteLength(iReadMaxLength,iWriteMaxLength);
	}

	/**
	 * Starts UserSession on Socket Address
	 * @param addr specified address
	 * @throws IOException 
	 */
	public void start(InetSocketAddress addr) throws IOException
	{
		initController();
		controller.accept(addr,itimeout);
	}

	/**
	 * Starts ClientSession on Socket
	 * @param objSocket Specifies object of Socket on Client Session.
	 */
	public void start(Socket socket)throws IOException
	{
		initController();
		controller.initClientSession(socket, itimeout);
	}

	/**
	 * Retrieves number of clients currently connected to Service Provider.    
	 * @return int - no. of Clients connected
	 */
	public int noOfClientsConnected()
	{
		return controller.noOfClientsConnected();
	}

	/**
	 * Shows current status of client,whether it is active or not, for given Inet Socket Address
	 * @param objAddress InetSocketAddress of client 
	 * @return boolean - shows status as true or false.
	 */
	public boolean isClientConnected(InetSocketAddress objAddress)
	{
		return controller.isClientConnected(objAddress);
	}

	/**
	 * Retrieves list of connection info for all currently active clients
	 * @return ISingleCollection<InetSocketAddress> - list of InetSocketAddress for all active clients
	 */
	public ISingleCollection<InetSocketAddress> getClientsConnectionInfo()
	{
		return controller.getClientsConnectionInfo();
	}

	/**
	 * Closes the Server Session.
	 */
	public void close() throws IOException
	{
		if(HL7Config.createInstance().isLoggingOn())
		{
			HL7Logger objHL7Logger = HL7Logger.getLogger();
			objHL7Logger.log(ResourceBundleWrapper.getValue("status", "SCPSessionClosed",new Locale(HL7Config.createInstance().getLocale())));
		}
		if(controller != null)
			controller.close();
		controller = null;

		objFragmentProcessor = null;
		objIMLLP = null;
		objBatchProcessor = null;
		objIProcessHandler = null;
	}



	/**
	 * Returns setting for Socket read timeout of this session, 
	 *  0 returns implies that the option is disabled (i.e., timeout of infinity).
	 * @return int - the setting for socket read timeout.
	 */
	public int getTimeOut() 
	{
		return itimeout;
	}

	/**
	 *  sets  Socket read timeout of this session, in
	 *  milliseconds.  With this option set to a non-zero timeout,
	 *  a read() call on the InputStream associated with this Socket
	 *  will block for only this amount of time.If the timeout expires,
	 *  a session is closed,The timeout must be > 0. A timeout of zero
	 *  is interpreted as an infinite timeout. 
	 * @param timeout the specified timeout, in milliseconds.
	 */
	public void setTimeOut(int itimeout)
	{
		this.itimeout = itimeout;
	}


}
