package cdac.medinfo.sdk.hl7282.tool.server;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;

import cdac.medinfo.sdk.hl7282.baselibs.MSG;
import cdac.medinfo.sdk.hl7282.baselibs.messagedictionary.MessageMapReader;
import cdac.medinfo.sdk.hl7282.baselibs.messages.ACK;
import cdac.medinfo.sdk.hl7282.baselibs.messages.IMessageRecepient;
import cdac.medinfo.sdk.hl7282.baselibs.messages.IMessageSource;
import cdac.medinfo.sdk.hl7282.baselibs.messages.Message;
import cdac.medinfo.sdk.hl7282.baselibs.messages.MessageFactory;
import cdac.medinfo.sdk.hl7282.baselibs.parserserializer.HL7Serializer;
import cdac.medinfo.sdk.hl7282.baselibs.segments.BHS;
import cdac.medinfo.sdk.hl7282.baselibs.segments.BTS;
import cdac.medinfo.sdk.hl7282.baselibs.segments.MSA;
import cdac.medinfo.sdk.hl7282.baselibs.segments.MSH;
import cdac.medinfo.sdk.hl7282.commoninterface.IDelimiter;
import cdac.medinfo.sdk.hl7282.commoninterface.ISegment;
import cdac.medinfo.sdk.hl7282.commoninterface.ISegmentSet;
import cdac.medinfo.sdk.hl7282.commoninterface.ISingleCollection;
import cdac.medinfo.sdk.hl7282.hl7model.messages.applicationmanagement.AppMgtSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.clinicallaboratoryautomation.ClinicalLabAutoSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.financialmanagement.FinancialSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.masterfiles.MasterFileSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.medicalrecords.MediRecSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.observationreporting.ObsvRepSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.orderentry.OrderEntrySource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.patientadministration.ADTRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.patientadministration.ADTSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.patientcare.PatientCareSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.patientreferral.PatientRefSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.personnelmanagement.PersonalMgmtSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.scheduling.SchedulingSource;
import cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.batch.BatchAgent;
import cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.batch.HL7Batch;
import cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.batch.HL7BatchFile;
import cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.fragment.FragmentAgent;
import cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.transactionhandler.TransactionHandler;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IBatchProcessor;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IFragmentProcessor;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IHL7Batch;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IHL7BatchFile;
import cdac.medinfo.sdk.hl7282.hl7net.commons.ITransactionHandler;
import cdac.medinfo.sdk.hl7282.hl7net.upperlayer.ClientSession;
import cdac.medinfo.sdk.hl7282.hl7net.upperlayer.IProcessHandler;
import cdac.medinfo.sdk.hl7282.hl7net.upperlayer.ServerSession;
import cdac.medinfo.sdk.hl7282.hl7streams.HL7BufferStream;
import cdac.medinfo.sdk.hl7282.utils.EnumMessageCode;
import cdac.medinfo.sdk.hl7282.utils.EnumMessageStructure;
import cdac.medinfo.sdk.hl7282.utils.HL7Config;
import cdac.medinfo.sdk.hl7282.utils.HL7Logger;
import cdac.medinfo.sdk.hl7282.utils.IMap;
import cdac.medinfo.sdk.hl7282.utils.IMessageMapReader;
import cdac.medinfo.sdk.hl7282.utils.SingleCollection;
import cdac.medinfo.sdk.hl7282.utils.StandardMethods;

/**
 * This class acts as main class for Server Utility tool of HL7.
 * It initializes the Sever Class for required parameters.
 */
public class HL7Server 
{
	static int lengthOfOption = 18;
	static int lengthOfDetails = 80 - lengthOfOption;
	
	public static void main(String args[])
	{
		String strLoggingPath = null;
		int iPort = 0;
		String strIP = null;
		String strDestinationPath = null;
		int iTimeOutPeriod = -1;

		HL7Server objServerTool = new HL7Server();

		String strIniFile = null;
		String strKey = null;
		
		
		
		/*
		 * If no parameters are provided then help need to be displayed.
		 */
		if(args == null || args.length ==0)
		{
			objServerTool.displayHelp();
			System.exit(0);
		}
		/*
		 * Checks the command line arguments and its repeatabilty 
		 * Repeatabilty of same command gives warning message and exits. 
		 */
		for(int i=0; i<args.length;i=i+2)
		{
			for(int j=i+2;j<args.length;j=j+2)
			{
				if(args[i].equalsIgnoreCase(args[j]))
				{		
					System.out.println("Not a valid Mulitple Occurences: "+args[j]);
					System.exit(0);
				}
			}
		}
		/*
		 * Initializing required parameters provided through cmd line arguments.
		 */
		for(int i=0; i<args.length; i++)
		{
			if(args[i].equalsIgnoreCase("-d") && args.length > i+1)
			{
				//Reading logging path information
				strLoggingPath = args[i+1];
				i++;
			}
			else if(args[i].equalsIgnoreCase("-p") && args.length > i+1)
			{
				//reading port information
				String strPort = args[i+1];
				iPort = Integer.parseInt(strPort);
				if(iPort == 0)
				{
					System.out.println("Not a valid command");
					System.exit(0);
				}
				i++;
			}
			else if(args[i].equalsIgnoreCase("-i") && args.length > i+1)
			{
				//reading IP address information
				strIP = args[i+1];
				i++;
			}
			else if(args[i].equalsIgnoreCase("-s") && args.length > i+1)
			{
				//reading destination dir path where received requests will be dumped
				strDestinationPath = args[i+1] ;
				i++;
			}
			else if(args[i].equalsIgnoreCase("-t") && args.length > i+1)
			{
				//reading value of No. of attempts for which resending will be done
				String strTimeOutPeriod = args[i+1];
				int iTimeOut = Integer.parseInt(strTimeOutPeriod);
				if(iTimeOut != 0)
				{
					iTimeOutPeriod = iTimeOut;
				}
				i++;
			}
			else
			{
				System.out.println("Not a valid command");
				objServerTool.displayHelp();
				System.exit(0);
			}
		}

		//IP and Port information are minimum required parameters to start the server
		if(iPort ==0)
		{
			System.out.println("Not a valid command");
			objServerTool.displayHelp();
			System.exit(0);
		}

		HISServer objHISServer = new HISServer();
		objHISServer.setINIFile(strIniFile);
		objHISServer.setKey(strKey);
		objHISServer.initiate(strLoggingPath,strIP, iPort,strDestinationPath,iTimeOutPeriod);
	}

	/*
	 * This function displays the help.
	 */
	private void displayHelp()
	{
		//Discription of command
		System.out.println("\nHL7SERVER :: Process message, batch and batchfiles supported by HL7.");

		//Signature
		System.out.println("\n" + "HL7SERVER [-i IP] -p Port [-d LogDir]  " +
				"[-s StorageDir] \n [-t TimeOut] " + "\n");

		//IP Address
		printToConsole("-i", "IP Address, default IP address is localhost.");

		//Port
		printToConsole("-p", "Port");

		//Log directory
		printToConsole("-d", "Log directory");
		printToConsole("", "User's temp directory is taken as default.");

		//Storage directory
		printToConsole("-s","Destination folder to store the received ACK and Batch files");
		printToConsole("", "User's temp directory is taken as default.");

		//Session time out
		printToConsole("-t","Session time out in milliseconds");
		
        
        System.out.println("\nExample :");

		//Example
		System.out.println("\n1. HL7SERVER -p 9999" +
		"\nStarts HL7 server at localhost listening on port 9999 for receiving HL7 message events. Message Events can be received in HL7Batch or HL7Batch File.\n");
	
	}

	/**
	 * Display Help of command on console in proper manner.
	 * @param strOption Option for command.
	 * @param strDetails Description of option.
	 */
	public static void printToConsole(String strOption, String strDetails)
	{
		String strBuffer = "";
		if (strOption != null)
			strBuffer = strBuffer + strOption ;
		while (lengthOfOption > strBuffer.length())
		{
			strBuffer = strBuffer + " ";
		}
		if (strDetails != null)
		{
			if (strDetails.length() < lengthOfDetails || strDetails.length() == lengthOfDetails)
			{
				strBuffer = strBuffer + strDetails;
				strDetails = null;
			}
			else
			{
				strBuffer = strBuffer + strDetails.substring(0, lengthOfDetails);
				strDetails = strDetails.substring(lengthOfDetails, (strDetails.length() ));
			}
		}

		System.out.println(strBuffer);
		if (strDetails == null)
			return;
		else
			printToConsole(null, strDetails);
	}

	/**
	 * Display Help of command on console in proper manner.
	 * @param strAttribute Attribute for option.
	 * @param strDesc Description of attributes.
	 */
	public static void printToConsole(String strAttribute, String[] strDesc)
	{
		if (strDesc.length > 1)
			printToConsole(strAttribute, strDesc[0]);
		for(int i = 1;i<strDesc.length;i++)
			printToConsole(null, strDesc[i]);
	}
}

/**
 * This sample code demonstrates implementation of Server for different HL7 Systems.
 * HIS Server can process event request for different systems.
 * It can also process requests in Batch or BatchFile.
 */
class HISServer implements IProcessHandler
{	
	ServerSession objServerSession=null;
	IBatchProcessor objIBatchProcessor = null;
	MessageFactory objMessageFactory = null;
	int messageControlId = 0;
	int i = 1;
	String strDestinationPath = null;
	ITransactionHandler objTransactionHandler = null;
	String strMessageControlID=null;
	int iMessageControlId =0; 

	
	private String strIniFile;
	private String strKey;

	public void setINIFile(String strIniFile)
	{
		this.strIniFile = strIniFile;
	}
	public void setKey(String strKey)
	{
		this.strKey = strKey;
	}

	public String getINIFile()
	{
		return this.strIniFile;
	}
	public String getKey()
	{
		return this.strKey;
	}
	
	/**
	 * Starts HIS Server at IPadderess & port provided.
	 * @param strIP  IP Address specified
	 * @param port port specified 
	 */
	public void initiate(String strLoggingPath, String strIP,int port,String strDestPath,int iTimeoutPeriod)
	{

		try 
		{
			this.strDestinationPath = strDestPath;
			HL7Config objHL7Config = HL7Config.createInstance();

			//Specifying logging directory.
			//User can specify any directory where log files will be created.
			//If no path is specified then logs will be generated in user's temp directory.
			objHL7Config.enableLogging(strLoggingPath);

			//Creating Server Session
			objServerSession = new ServerSession();


			/*
			 * Initializing recepients for different systems and adding them on server session. 
			 * By setting recepient on server session, it becomes capable to process requests of specific System
			 */
			objMessageFactory = MessageFactory.createInstance();
			
			IMessageSource objADTSource = new ADTSource();
			objMessageFactory.addMessageSource(objADTSource);
			
			IMessageRecepient objADTRecepient  = new ADTRecepient();
			objMessageFactory.addMessageRecepient(objADTRecepient);

			IMessageSource objFinancialSource = new FinancialSource();
			objMessageFactory.addMessageSource(objFinancialSource);

			IMessageSource objPatientCareSource = new PatientCareSource();
			objMessageFactory.addMessageSource(objPatientCareSource);

			IMessageSource objPatientRefSource = new PatientRefSource();
			objMessageFactory.addMessageSource(objPatientRefSource);

			IMessageSource objClinicalLabAutoSource = new ClinicalLabAutoSource();
			objMessageFactory.addMessageSource(objClinicalLabAutoSource);

			IMessageSource objSchedulingSource = new SchedulingSource();
			objMessageFactory.addMessageSource(objSchedulingSource);

			IMessageSource objAppMgtSource = new AppMgtSource();
			objMessageFactory.addMessageSource(objAppMgtSource);

			IMessageSource objMasterFileSource = new MasterFileSource();
			objMessageFactory.addMessageSource(objMasterFileSource);

			IMessageSource objMediRecSource = new MediRecSource();
			objMessageFactory.addMessageSource(objMediRecSource);

			IMessageSource objObsvRepSource = new ObsvRepSource();
			objMessageFactory.addMessageSource(objObsvRepSource);

			IMessageSource objOrderEntrySource = new OrderEntrySource();
			objMessageFactory.addMessageSource(objOrderEntrySource);

			IMessageSource objPersonalMgmtSource = new PersonalMgmtSource();
			objMessageFactory.addMessageSource(objPersonalMgmtSource);
			
			/*
			 * Instantiating IFragmentProcessor which handles the fragmentaion and defragmention for larger messages.
			 * FragmentAgent is the default implementation provided by sdk for HL7.
			 * User can provide his own implementaion for FragmentProcessor by implementing IFragmentProcessor interface.
			 */ 
			IFragmentProcessor objIFragmentProcessor = new FragmentAgent();

			//Setting Fragment processor on server session.
			objServerSession.setFragmentProcessor(objIFragmentProcessor);

			/*
			 * Instantiating IBatchProcessor which handles HL7Batch and HL7BatchFiles.
			 * BatchAgent is the default implementation provided by sdk for HL7.
			 * User can provide his own implementaion for BatchProcessor by implementing IBatchProcessor interface.
			 */
			objIBatchProcessor = new BatchAgent();

			//Setting Batch Processor on user session
			objServerSession.setBatchProcessor(objIBatchProcessor);

			/*
			 * Setting this class as ProcessHandler for HISServer.
			 * IProcessHandler interface must be implemented ,so that server can receive messages from client side. 
			 */
			objServerSession.setIProcessHandler(this);	

			//Set the reading and writing max length for this client which will be used to decide whehther to fragment or not.
			objServerSession.setReadWriteLength(1024,1024);

			//Setting time period for which ClientSession will read on socket 
			//for given time period in milliseconds. 
			//The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout.
			if(iTimeoutPeriod>0)
				objServerSession.setTimeOut(iTimeoutPeriod);

			//If IP address is not given then by default it will be LocalHost
			if(strIP==null)
			{
				InetAddress ownIP = InetAddress.getLocalHost();
				strIP= ownIP.getHostAddress();
			}
			/*
			 * Starts the ServerSession for Server on given IP and port.
			 */
			objServerSession.start(strIP, port);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			if(HL7Config.createInstance().isLoggingOn())
			{
				HL7Logger objHLogger = HL7Logger.getLogger();
				objHLogger.log(e);
			}
			try {
				objServerSession.close();
			} catch (IOException e1) 

			{
				e1.printStackTrace();
				if(HL7Config.createInstance().isLoggingOn())
				{
					HL7Logger objHLogger = HL7Logger.getLogger();
					objHLogger.log(e1);
				}
			}
		}
	}

	/**
	 * This method is automatically invoked when Message is received from remote system.
	 * User provides the implementation of this method.
	 * Simulation of user code is demonstrated below.
	 * @param objClientSession instance of Client Session
	 */
	public void OnMessageReceive(ClientSession objClientSession)
	{
		Message receivedMessage = objClientSession.getMessage();

		System.out.println("Message received :: " + receivedMessage.getMessageStructure());
		dumpMessage(receivedMessage);
		//User code goes over here
		try
		{
			/*
			 * Server can receive following types of messages.
			 * 1)Any Event triggered by other Health Information System available in HL7 network.
			 * 2)Query message specific to  system.
			 * 3)Acknowledgement for the Deferred response sent.  
			 */

			ACK acknowledgement = null;


			/* 
			 * When user send Deferred response,ACK message is received from remote client end.
			 * ACK is fetched only when Deferred response is dispatched.
			 * Following code block handles Acknowledgement received for deferred response sent.
			 */
			if (receivedMessage.getMessageStructure().equals(EnumMessageStructure.ACK.getValue()) || receivedMessage.isQuery() || receivedMessage.isResponse())  
			{
				//Simply Dump the Message
				System.out.println("Unexpected Message Received :: " + receivedMessage.getMessageStructure());
			}
			//Send Acknowledgement when event is received from other system.
			else
			{
				System.out.println("Generating Acknoledgement");
				acknowledgement = generateAcknowledgement(receivedMessage);
//				if(objMessageHandler.isACKWaitingRequired(receivedMessage))
//				{
					objClientSession.sendMessage(acknowledgement);
//				}
				System.out.println("Acknoledgement Sent :: " + acknowledgement.getMessageStructure() + "\n");
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * This method simulates user action to generate Acknowledgement for message received.
	 * This method is demonstrated for test purpose only.
	 * In the actual scenerion, it is User's responsibility to generates acknowledgement & sends it on client Session. 
	 * @param objReceivedMessage specified Message object
	 * @return ACK instance of acknowledgement
	 */
	public ACK generateAcknowledgement(Message objReceivedMessage)
	{
		strMessageControlID = "MSQ3456" + iMessageControlId++; 
		
		IMessageMapReader objMessageMapReader = MessageMapReader.createInstance();
		IMap objMessageMap = objMessageMapReader.getMessageMap(EnumMessageCode.ACK, null);
		
		HL7BufferStream objBufferStream = new HL7BufferStream();
		ByteArrayOutputStream objByteArrayOutputStream = new ByteArrayOutputStream();
		objBufferStream.setOutputStream(objByteArrayOutputStream);

		String strTriggerEvent = objReceivedMessage.getTriggerEvent();
		ACK ackMessage = new ACK(strTriggerEvent, objMessageMap);
		MSH objMSH = objReceivedMessage.getHeader();
		String strReceivedID = (String)objMSH.getMessageControlID().getValue();
		IDelimiter objIDelimiter = objMSH.getDelimiter();
		try
		{
			objMSH.serialize(objBufferStream, objIDelimiter);
			ByteArrayInputStream objByteArrayInputStream = new ByteArrayInputStream(objBufferStream.toByteArray());
			objBufferStream.setInputStream(objByteArrayInputStream);
			MSH AckMsh = new MSH();
			StringBuffer strBuffValue = new StringBuffer(3);
			objBufferStream.readString(strBuffValue, 3);
			String strTemp="";
			char creadChar;
			do
			{
				creadChar=objBufferStream.readChar();
				strTemp=strTemp+creadChar;
			}while(creadChar!='\r');
			AckMsh.parse(strTemp, objIDelimiter);
			MSG objAckMsg = AckMsh.getMessageType();			
			objAckMsg.setMessageCode(EnumMessageCode.ACK.getValue());
			objAckMsg.setTriggerEvent(objReceivedMessage.getTriggerEvent());
			objAckMsg.setMessageStructure(EnumMessageStructure.ACK.getValue());
			AckMsh.setMessageControlID(strMessageControlID);
			ackMessage.setHeader(AckMsh);

			// MSA Segment
			MSA objMSA = new MSA();
			objMSA.setAcknowledgmentCode("AA");
			objMSA.setMessageControlID(strReceivedID);
//			objMSA.setTextMessage("This is "+ objReceivedMessage.getMessageStructure() +" event.");
			//			objMSA.setExpectedSequenceNumber("1234567");
			ackMessage.setMessageAcknowledgmentSegment(objMSA);
			return ackMessage;
		}
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * This method is implementation of IProcesshandler interface.
	 * This method is invoked when any user establishes connection with Server. 
	 * @param objClientSession session of remote end
	 */
	public void OnConnect(ClientSession objClientSession) 
	{
		/*
		 * Instantiating TransactionHandler which keeps track for the sending and receiving message 
		 * and does verification of each message during transaction.
		 * User can provide his own implementation for ServerSideTransactionHandler by implementing ITransactionHandler interface.
		 */
		objTransactionHandler = new TransactionHandler();
		objClientSession.setServerSideTransactionHandler(objTransactionHandler);
		objClientSession.acceptConnection(true);
		objClientSession.setMessageFactory(objMessageFactory);
	}

	/**
	 * This method is implementation of IProcesshandler interface.
	 * This method is invoked when SDK is not able to parse received message.
	 * @param objClientSession 
	 */
	public void OnErrorReceive(ClientSession objClientSession)
	{
		//user code to generate error ACK to send 
		System.out.println("Error Occured"+objClientSession.getErrorCode());
	}

	/**
	 * This method is implementation of IProcesshandler interface.
	 * This method is invoked when SDK receives file containing batch of HL7 messages from remote system.
	 * @param objClientSession session of remote end
	 */

	public void OnBatchFileReceive(ClientSession objClientSession)
	{
		try
		{
			IHL7BatchFile objACKBatchFile = null;
			ISingleCollection<IHL7Batch> objAckBatches = null;

			IHL7BatchFile objHL7BatchFile = objClientSession.getBatchFile();

			System.out.println("Batch File Received ");
			System.out.println("No of Batch in HL7 Batch-File :: " + objHL7BatchFile.getHL7BatchCollection().size());
			dumpMessage(objHL7BatchFile);
			System.out.println("Process Batches available in Batch File");
			for(IHL7Batch objHL7Batch : objHL7BatchFile.getHL7BatchCollection())
			{
				System.out.println("Processing Batch with ID :: " + objHL7Batch.getBatchControlID());
				ISingleCollection<Message> objMessageCollection = objHL7Batch.getMessageCollection();
				ISingleCollection<Message> objAckCollection = new SingleCollection<Message>(); // set on batch and sent.

				if(objMessageCollection.size() == 0)
				{
					BHS objBHS = new BHS();
					objBHS.setBatchControlID(objHL7Batch.getBatchControlID());
					objBHS.setBatchFieldSeparator('|');
					objBHS.setBatchEncodingChars('^','&','~','\\','#');

					BTS objBTS = new BTS();
					objBTS.setBatchMessageCount(""+objAckCollection.size());
					IHL7Batch objACKBatch = new HL7Batch(objBHS,objBTS,objAckCollection);

					objACKBatchFile = new HL7BatchFile();
					objAckBatches = new SingleCollection<IHL7Batch>();
					objAckBatches.add(objACKBatch);

					objACKBatchFile.setHL7BatchCollection(objAckBatches);

					objClientSession.sendBatch(objACKBatchFile);
				}

				System.out.println("Processing Batch Messages");
				for(Message objMessage : objMessageCollection)
				{
					ACK acknowledgement = null;
					//ACK is fetched only when Deferred response is dispatched
					if(objMessage.getMessageStructure().equals(EnumMessageStructure.ACK.getValue()) || objMessage.isQuery() || objMessage.isResponse())  
					{
						System.out.println("Unexpected Message in Batch :: " + objMessage.getMessageStructure());
					}
					//Code block of ACK
					else
					{
						System.out.println("Generating Acknoledgement for Batch Message :: " + objMessage.getMessageStructure());
						acknowledgement = generateAcknowledgement(objMessage);
//						if(objMessageHandler.isACKWaitingRequired(objMessage))
							objAckCollection.add(acknowledgement);
					}
				}

				BHS objBHS = new BHS();
				objBHS.setBatchControlID(objHL7Batch.getBatchControlID());
				objBHS.setBatchFieldSeparator('|');
				objBHS.setBatchEncodingChars('^','&','~','\\','#');

				BTS objBTS = new BTS();
				objBTS.setBatchMessageCount(""+objAckCollection.size());
				IHL7Batch objACKBatch = new HL7Batch(objBHS,objBTS,objAckCollection);

				objACKBatchFile = new HL7BatchFile();
				objAckBatches = new SingleCollection<IHL7Batch>();
				objAckBatches.add(objACKBatch);
				objACKBatchFile.setHL7BatchCollection(objAckBatches);

				objClientSession.sendBatch(objACKBatchFile);
				System.out.println("Batch Processed with Batch ID :: " + objACKBatch.getBatchControlID() + "\n");
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		} 
	}

	/**
	 * This method is implementation of IProcesshandler interface.
	 * This method is invoked when SDK receives erroneous binary data.
	 * @param buffer Binary data for which exception is generated
	 * @param ex Type of Exception raised
	 */
	public void onException(Exception ex,byte[] buffer) 
	{
		System.out.println("Exception Occured While Processing");
		System.out.println(ex.getMessage());
		try
		{
			System.out.println("Errorneous Buffer :: ");
			ByteArrayOutputStream objByteArrayOutputStream = new ByteArrayOutputStream();
			objByteArrayOutputStream.write(buffer);

			objByteArrayOutputStream.writeTo(System.out);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	private boolean dumpMessage(Message objMessage)
	{
		try
		{
			String strDestFilePath = null;

			if(strDestinationPath != null)
			{
				if(!strDestinationPath.endsWith(File.separator))
					strDestinationPath = strDestinationPath + File.separator;

				File objFile = new File(strDestinationPath);
				objFile.mkdirs();
				strDestFilePath = strDestinationPath + StandardMethods.generateUUID() + ".HL7";
			}
			else
			{
				String strLogLocation = StandardMethods.getTempDirectoryStorage() + "CDAC-SDK/HL7-J/Dump";
				File objFile = new File(strLogLocation);
				if(!objFile.exists())
					objFile.mkdirs();
				strDestFilePath = objFile.getPath() + File.separator + StandardMethods.generateUUID() + ".HL7";
			}

			HL7Serializer objHL7Serializer = new HL7Serializer();
			objHL7Serializer.serialize(objMessage.getSegmentSet(),strDestFilePath);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return false;
		}
		return true;
	}

	private boolean dumpMessage(IHL7BatchFile objIHL7BatchFile)
	{
		try
		{
			String strDestFilePath = null;

			if(strDestinationPath != null)
			{
				if(!strDestinationPath.endsWith(File.separator))
					strDestinationPath = strDestinationPath + File.separator;

				File objFile = new File(strDestinationPath);
				objFile.mkdirs();
				strDestFilePath = strDestinationPath + StandardMethods.generateUUID() + ".HL7";
			}
			else
			{
				String strLogLocation = StandardMethods.getTempDirectoryStorage() + "CDAC-SDK/HL7-J/Dump";
				File objFile = new File(strLogLocation);
				if(!objFile.exists())
					objFile.mkdirs();
				strDestFilePath = objFile.getPath() + File.separator + StandardMethods.generateUUID() + ".HL7";
			}

			ISegmentSet objSegmentSet = objIBatchProcessor.getSegmentSet(objIHL7BatchFile);
			HL7Serializer objHL7Serializer = new HL7Serializer();
			objHL7Serializer.serialize(objSegmentSet, strDestFilePath);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * This method is implementation of IProcesshandler interface.
	 * This method is invoked when SDK receives erroneous binary data.
	 * @param ex Type of Exception raised.
	 * @param objISegmentSet Generated Segment Set.
	 */
	public void onException(Exception ex,ISegmentSet objISegmentSet)
	{
		System.out.println("In On Exception Receiced : Printing Stacktrace...");
		System.out.println(ex.getMessage());
		System.out.println("End of Stacktrace....");
		try
		{
			ISingleCollection<ISegment>  objCollection = objISegmentSet.getList();
			for(ISegment objISegment : objCollection)
			{
				System.out.println(objISegment.getName());
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	@Override
	public void onClose(ClientSession arg0) {
		// TODO Auto-generated method stub
		
	}
}
