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




import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ConnectException;
import java.net.SocketException;

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.HL7Parser;
import cdac.medinfo.sdk.hl7282.baselibs.parserserializer.HL7Serializer;
import cdac.medinfo.sdk.hl7282.baselibs.segments.MSA;
import cdac.medinfo.sdk.hl7282.baselibs.segments.MSH;
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.exceptions.InvalidMessageException;
import cdac.medinfo.sdk.hl7282.hl7model.messages.observationreporting.ObsvRepRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.observationreporting.ObsvRepSource;
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.query.QSB_Q16;
import cdac.medinfo.sdk.hl7282.hl7model.messages.query.QSX_J02;
import cdac.medinfo.sdk.hl7282.hl7model.messages.query.QryRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.query.QrySource;
import cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.batch.BatchAgent;
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.ITransactionHandler;
import cdac.medinfo.sdk.hl7282.hl7net.localextension.Populate_Test;
import cdac.medinfo.sdk.hl7282.hl7net.upperlayer.ClientSession;
import cdac.medinfo.sdk.hl7282.hl7net.upperlayer.IExceptionListener;
import cdac.medinfo.sdk.hl7282.hl7net.upperlayer.IProcessHandler;
import cdac.medinfo.sdk.hl7282.hl7net.upperlayer.ServerSession;
import cdac.medinfo.sdk.hl7282.hl7net.upperlayer.UserSession;
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.EnumTriggerEvent;
import cdac.medinfo.sdk.hl7282.utils.HL7Config;
import cdac.medinfo.sdk.hl7282.utils.IMap;
import cdac.medinfo.sdk.hl7282.utils.IMessageMapReader;
import cdac.medinfo.sdk.hl7282.utils.StandardMethods;

/**
 * This class acts as subscriber by sending message and receives 
 * particular type of message for which it is subscriber for. 
 */
public class HL7System_Subscriber implements IProcessHandler 
{

	/*Instance of MessageFacotry for creation and population of messages.*/
	MessageFactory objMessageFactory =null;

	/*Flag for status for subscription message send or not.*/
	boolean isSubscriptionSend = false;

	//Handler which does verification of messages.
	ITransactionHandler objServerTransactionHandler =null;

	String strMessageControlID=null,strQueryId =null;
	int iMessageControlId =0;
	Populate_Test objPopulate_Test = null;

	/**
	 * @param args
	 */
	public static void main(String[] args) 
	{
		try
		{
			//Reading IP address for HL7System_Subscriber
			System.out.print("Enter IP Adderess of HL7System_Subscriber : ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strIP = reader.readLine();

			//Reading port for HL7System_Subscriber
			System.out.print("Enter Port on which HL7System_Subscriber is listening : ");
			String strPort = reader.readLine();
			int port = Integer.parseInt(strPort);

			HL7System_Subscriber objHL7System_Subscriber = new HL7System_Subscriber();
			objHL7System_Subscriber.initiate(strIP,port);	
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}


	public void initiate(String strIP,int port)
	{
		try 
		{

			/*
			 * 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. 
			 */
			HL7Config.createInstance().enableLogging("E:\\PubSubLogs");

			
			objPopulate_Test = new  Populate_Test();

			//Creating ServerSession Session for HL7System_Subscriber.
			ServerSession objServerSession = new ServerSession();

			//Create MessageFactory to provide support for creation and population of messages.
			MessageFactory objMessageFactory = MessageFactory.createInstance();


			/*   Patient Administration System */
			/*
			 * Instantiating Message Recipient for HL7System
			 * User can provide his own implementation of Message Recipient by implementing IMessageReceipient interface. 
			 */
			IMessageRecepient objADTRecepient = new ADTRecepient();

			/*
			 * Adding Patient Admin Recipient on Message Factory.
			 * By setting this recipient client becomes capable to create messages and send Events of Patient Admin System
			 * Similarly user can set recipients for different systems.
			 * sdk for HL7 provides sources for all systems specified by HL7.
			 */ 
			objMessageFactory.addMessageRecepient(objADTRecepient);

			/*
			 * Instantiating Message Source for HL7System
			 * User can provide his own implementation of Message Source by implementing IMessageSource interface. 
			 */
			IMessageSource objADTSource  = new ADTSource();

			/*
			 * Adding Patient Admin Source and Recipient on on Message Factory.
			 * By setting this source client becomes capable to create messages and receive responses of Patient Admin System
			 * Similarly user can set sources for different systems.
			 * sdk for HL7 provides sources for all systems specified by HL7.
			 */ 
			objMessageFactory.addMessageSource(objADTSource);


			/* Observation Reporting System*/ 
			//Initiating Message Recipient for Observation Reporting System.
			IMessageRecepient objObsvRepRecepient = new ObsvRepRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objObsvRepRecepient);

			//Initiating Message Source for Observation Reporting System.
			IMessageSource objObsvRepSource  = new ObsvRepSource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objObsvRepSource);


			/*   Query System */
			//Initiating Message Recipient for Query System.
			IMessageRecepient objQryRecepient = new QryRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objQryRecepient);

			//Initiating Message Source for Query System.
			IMessageSource objQrySource  = new QrySource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objQrySource);

			/* 
			 * As per the given systems requirement Un-Comment required source and 
			 * Recipient for sending and receiving for supported messages.  

		    Application management System 
			//Initiating Message Recipient for Application management System.
			IMessageRecepient objAppMgtRecepient = new AppMgtRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objAppMgtRecepient);

			//Initiating Message Source for Application management System.
			IMessageSource objAppMgtSource  = new AppMgtSource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objAppMgtSource);


			   Clinical Laboratory Automation System 
			//Initiating Message Recipient for Clinical Laboratory Automation System.
			IMessageRecepient objClinicalLabAutoRecepient = new ClinicalLabAutoRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objClinicalLabAutoRecepient);

			//Initiating Message Source for Clinical Laboratory Automation System.
			IMessageSource objClinicalLabAutoSource  = new ClinicalLabAutoSource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objClinicalLabAutoSource);


			   Financial Management System 
			//Initiating Message Recipient for Financial Management System.
			IMessageRecepient objFinancialRecepient = new FinancialRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objFinancialRecepient);

			//Initiating Message Source for Financial Management System.
			IMessageSource objFinancialSource  = new FinancialSource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objFinancialSource);


			   Master Files System 
			//Initiating Message Recipient for Master Files System.
			IMessageRecepient objMasterFileRecepient = new MasterFileRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objMasterFileRecepient);

			//Initiating Message Source for Master Files System.
			IMessageSource objMasterFileSource  = new MasterFileSource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objMasterFileSource);


			   Medical Records System 
			//Initiating Message Recipient for Medical Records System.
			IMessageRecepient objMediRecRecepient = new MediRecRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objMediRecRecepient);

			//Initiating Message Source for Medical Records System.
			IMessageSource objMediRecSource  = new MediRecSource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objMediRecSource);


			  Order Entry System 
			//Initiating Message Recipient for Order Entry System.
			IMessageRecepient objOrderEntryRecepient = new OrderEntryRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objOrderEntryRecepient);

			//Initiating Message Source for Order Entry System.
			IMessageSource objOrderEntrySource  = new OrderEntrySource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objOrderEntrySource);


			  Patient Care System 
			//Initiating Message Recipient for Patient Care System.
			IMessageRecepient objPatientCareRecepient = new PatientCareRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objPatientCareRecepient);

			//Initiating Message Source for Patient Care System.
			IMessageSource objPatientCareSource  = new PatientCareSource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objPatientCareSource);


			  Patient Referral System 
			//Initiating Message Recipient for Patient Referral System.
			IMessageRecepient objPatientRefRecepient = new PatientRefRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objPatientRefRecepient);

			//Initiating Message Source for Patient Referral System.
			IMessageSource objPatientRefSource  = new PatientRefSource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objPatientRefSource);


			  Personnel Management System 
			//Initiating Message Recipient for Personnel Management System.
			IMessageRecepient objPersonalMgmtRecepient = new PersonalMgmtRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objPersonalMgmtRecepient);

			//Initiating Message Source for Personnel Management System.
			IMessageSource objPersonalMgmtSource  = new PersonalMgmtSource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objPersonalMgmtSource);


			  Scheduling System 
			//Initiating Message Recipient for Scheduling System.
			IMessageRecepient objSchedulingRecepient = new SchedulingRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objSchedulingRecepient);

			//Initiating Message Source for Scheduling System.
			IMessageSource objSchedulingSource  = new SchedulingSource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objSchedulingSource);*/


			/*
			 * 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 implementation 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 implementation for BatchProcessor by implementing IBatchProcessor interface.
			 */
			IBatchProcessor objIBatchProcessor = new BatchAgent();

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

			/*
			 * Setting this class as ProcessHandler for PatientAdminServer.
			 * 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);

			//Sets the wait period for which each ClientSession should wait till it 
			//receives ACK/response for triggered event/Query.
			//if user not sets then by default set to 20 sec.

			//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. 
			objServerSession.setTimeOut(0);

			//This will create Separate User Session on different port for Sending Subscription Message. 
			//Message objMessage = getSubscriptionMessage("C:\\mnt\\D_DRIVE\\QSB_Q16_1.hl7");
			System.out.println("Enter the file contain Subscription message :");
			
			InputStreamReader input1 = new InputStreamReader(System.in);
			BufferedReader reader1 = new BufferedReader(input1);
			String strSubMessage = reader1.readLine();//"/home/sayali/dump/Testing/QSB_Q16_New.hl7"
			
			Message objMessage = getSubscriptionMessage(strSubMessage);
			
			System.out.println("Do u want to Send subscription message to PatientAdminPublisher [y or Y]:");

			//Reading IP address for Client
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			char ch = (char)reader.read();
			if(ch=='y' || ch=='Y')
			{
				isSubscriptionSend = true;
				//Sending Subscription message by creating separate UserSession.
				System.out.println("Sending Subscription message by creating separate UserSession");

				HL7System_SubscriberUserSesion objHL7System_SubscriberUserSesion = new HL7System_SubscriberUserSesion();
				objHL7System_SubscriberUserSesion.setMessage(objMessage);
				objHL7System_SubscriberUserSesion.start();
			}

			//ServerSession for this system is started on port 9002.
			objServerSession.start(port);
		}
		catch (Exception e)
		{
			System.out.println("Error Ocured (Ending Client..)== > "+e.getMessage());
			e.printStackTrace();
		}		
	}
	/**
	 * 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) {}
	/**
	 * This method is invoked when deferred response received is in Batch.
	 */
	public void OnBatchReceive(ClientSession objClientSession) {}
	/**
	 * 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.
		 * if user wants verification for each message within transaction then user has to set it else not.
		 */
		objServerTransactionHandler = new TransactionHandler();

		objClientSession.setServerSideTransactionHandler(objServerTransactionHandler);
		objClientSession.setMessageFactory(objMessageFactory);
		objClientSession.acceptConnection(true);
	}
	/**
	 * 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) {}

	/**
	 * 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) 
	{

		System.out.println("OnMessageReceive of HL7System_Subscriber");
		System.out.println("Published Message Received by Listener1..... from : " + objClientSession.getClientAddress().toString());
		Message objMessage = objClientSession.getMessage();
		try {
			String strFilepath = "F:\\SubInbox\\Listener1receivedmsg.hl7";

			HL7Serializer objHL7Serializer = new HL7Serializer();
			objHL7Serializer.serialize(objMessage.getSegmentSet(),strFilepath); 

			System.out.println("Message received is serialized successfully at location  " + strFilepath);

			System.out.println("Sending ACK for " + objMessage.getMessageStructure());

			//This will generate ACK for Received Message.
			ACK ackMessage = generateAcknowledgement(objMessage);

			//Send Acknowledgment for deferred response
			objClientSession.sendMessage(ackMessage);

			//If subscription is send already then send Cancellation of Subscription message for it.
			if(isSubscriptionSend)
			{
				System.out.println("Do u want to Send subscription Cancellation message to PatientAdminPublisher : [y or Y]");

				//Reading IP address for Client
				InputStreamReader input = new InputStreamReader(System.in);
				BufferedReader reader = new BufferedReader(input);
				char ch = (char)reader.read();
				if(ch=='y' || ch=='Y')
				{
					//This will create HL7System_SubscriberUserSesion session for Creating Cancellation request for 
					HL7System_SubscriberUserSesion objHL7System_SubscriberUserSesion = new HL7System_SubscriberUserSesion();
					System.out.println("Enter file for Subscription Cancellation :");
					InputStreamReader input1 = new InputStreamReader(System.in);
					BufferedReader reader1 = new BufferedReader(input1);
					String strSubCancellationMessage = reader1.readLine();
					objMessage = getSubscriptionCancellationMessage(strSubCancellationMessage);//"/home/sayali/dump/Testing/QSX_J02.hl7"
					objHL7System_SubscriberUserSesion.setMessage(objMessage);
					objHL7System_SubscriberUserSesion.start();
				}
			}

			//Creating QrySource for sending and receving capabiltiy for Query System.
			//e.g Send Queries like QSX_J02.
			IMessageSource objQrySource = new QrySource();

			//Adding MessageSource of Query to MessageFactory.
			objMessageFactory.addMessageSource(objQrySource);


		} catch (FileNotFoundException e) 
		{			
			e.printStackTrace();
		}	
		catch (IOException e) 
		{				
			e.printStackTrace();
		}	
	}
	/**
	 * This method simulates user action to generate Acknowledgement from message received.
	 * This method is demonstrated for test purpose only.
	 * In the actual scenerion,it is the responsibility of user to generates acknowledgement & sends it on remote end. 
	 * @param objReceivedMessage specified Message object
	 * @return ACK message object
	 */
	public ACK generateAcknowledgement(Message objReceivedMessage)
	{
		strMessageControlID = "MSPO65456" + iMessageControlId++;
		
		IMessageMapReader objMessageMapReader = MessageMapReader.createInstance();
		IMap objMessageMap = objMessageMapReader.getMessageMap(EnumMessageCode.ACK, null);

		ACK ackMessage = new ACK(StandardMethods.getEnumTriggerEvent(objReceivedMessage.getTriggerEvent()), objMessageMap);
		MSH objMSH = objPopulate_Test.populateMSH();
		objMSH.setMessageType(EnumMessageCode.ACK.getValue(), objReceivedMessage.getTriggerEvent(),EnumMessageStructure.ACK.getValue());
		objMSH.setMessageControlID(strMessageControlID);
		ackMessage.setHeader(objMSH);
		
		//MSA Segment
		MSA objMSA = new MSA();
		objMSA.setAcknowledgmentCode("AA");
		objMSA.setMessageControlID(objReceivedMessage.getHeader().getMessageControlID().getValue().toString());
		objMSA.setExpectedSequenceNumber("1234567");
		ackMessage.setMessageAcknowledgmentSegment(objMSA);
		return ackMessage;
	}
	
	/**
	 * 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("In On Exception Receiced : Printing Stacktrace...");
		System.out.println(ex.getMessage());
		System.out.println("End of Stacktrace....");
		try
		{
			System.out.println("Byte Buffer is : ");
			ByteArrayOutputStream objByteArrayOutputStream = new ByteArrayOutputStream();
			objByteArrayOutputStream.write(buffer);

			objByteArrayOutputStream.writeTo(System.out);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	//This will give Subscription message from specified path of for QSB_Q16.
	private Message getSubscriptionMessage(String strFilePath)
	{
		QSB_Q16 objQSB_Q16 = null;
		try 
		{
			QrySource objQrySource = new QrySource();
			objQSB_Q16 = (QSB_Q16)objQrySource.createMessage(EnumMessageCode.QSB, EnumTriggerEvent.Q16);
			FileInputStream fis;

			fis = new FileInputStream(new File(strFilePath));

			byte buff[] = new byte[fis.available()];
			fis.read(buff);
			ByteArrayInputStream bis = new ByteArrayInputStream(buff);
			HL7BufferStream objHL7BufferStream = new HL7BufferStream();
			objHL7BufferStream.setInputStream(bis);
			HL7Parser objHL7Parser = new HL7Parser();
			ISegmentSet objSegmentSet = objHL7Parser.parse(objHL7BufferStream);
			objQSB_Q16.populate(objSegmentSet);

		} catch (FileNotFoundException e)
		{
			e.printStackTrace();
		} catch (IOException e) 
		{
			e.printStackTrace();
		}
		return objQSB_Q16;
	}
	//This will give Subscription cancellation message from specified path of for QSX_J02. 
	private Message getSubscriptionCancellationMessage(String strFilePath)
	{
		QSX_J02 objQSX_J02 = null;
		try 
		{
			QrySource objQrySource = new QrySource();
			objQSX_J02 = (QSX_J02)objQrySource.createMessage(EnumMessageCode.QSX, EnumTriggerEvent.J02);
			FileInputStream fis;

			fis = new FileInputStream(new File(strFilePath));

			byte buff[] = new byte[fis.available()];
			fis.read(buff);
			ByteArrayInputStream bis = new ByteArrayInputStream(buff);
			HL7BufferStream objHL7BufferStream = new HL7BufferStream();
			objHL7BufferStream.setInputStream(bis);
			HL7Parser objHL7Parser = new HL7Parser();
			ISegmentSet objSegmentSet = objHL7Parser.parse(objHL7BufferStream);
			objQSX_J02.populate(objSegmentSet);

		} catch (FileNotFoundException e)
		{
			e.printStackTrace();
		} catch (IOException e) 
		{
			e.printStackTrace();
		}
		return objQSX_J02;
	}
	/**
	 * Creating new User Session which will be decided during 
	 * negotiation and as per the conformance statement stated it is listening 
	 * on specific ip and port.This will received all messages for which Subscriber is subscribed for.
	 */
	public class HL7System_SubscriberUserSesion extends Thread implements IExceptionListener
	{
		Message objMessage;
		int i=0;
		UserSession objUserSession = null;
		public void run() 
		{
			initiateUserSession();
		}
		public void setMessage(Message objMessage)
		{
			this.objMessage = objMessage;
		}
		/**
		 * This method create new User session. 
		 */
		public void initiateUserSession()
		{
			try 
			{			
				/*
				 * 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. 
				 */
				HL7Config.createInstance().enableLogging("C:\\HL7Client_Logs");

				
				//Creating User Session for HL7System_Subscriber.
				objUserSession  = new UserSession();

				//Create MessageFactory to provide support for creation and population of messages.
				MessageFactory objMessageFactory = MessageFactory.createInstance();


				/*   Patient Administration System */
				/*
				 * Instantiating Message Recipient for HL7System
				 * User can provide his own implementation of Message Recipient by implementing IMessageReceipient interface. 
				 */
				IMessageRecepient objADTRecepient = new ADTRecepient();

				/*
				 * Adding Patient Admin Recipient on Message Factory.
				 * By setting this recipient client becomes capable to create messages and send Events of Patient Admin System
				 * Similarly user can set recipients for different systems.
				 * sdk for HL7 provides sources for all systems specified by HL7.
				 */ 
				objMessageFactory.addMessageRecepient(objADTRecepient);

				/*
				 * Instantiating Message Source for HL7System
				 * User can provide his own implementation of Message Source by implementing IMessageSource interface. 
				 */
				IMessageSource objADTSource  = new ADTSource();

				/*
				 * Adding Patient Admin Source and Recipient on on Message Factory.
				 * By setting this source client becomes capable to create messages and receive responses of Patient Admin System
				 * Similarly user can set sources for different systems.
				 * sdk for HL7 provides sources for all systems specified by HL7.
				 */ 
				objMessageFactory.addMessageSource(objADTSource);


				/*   Query System */
				//Initiating Message Recipient for Query System.
				IMessageRecepient objQryRecepient = new QryRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objQryRecepient);

				//Initiating Message Source for Query System.
				IMessageSource objQrySource  = new QrySource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objQrySource);

				/* 
				 * As per the given systems requirement Un-Comment required source and 
				 * Recipient for sending and receiving for supported messages.  

			    Application management System 
				//Initiating Message Recipient for Application management System.
				IMessageRecepient objAppMgtRecepient = new AppMgtRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objAppMgtRecepient);

				//Initiating Message Source for Application management System.
				IMessageSource objAppMgtSource  = new AppMgtSource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objAppMgtSource);


				   Clinical Laboratory Automation System 
				//Initiating Message Recipient for Clinical Laboratory Automation System.
				IMessageRecepient objClinicalLabAutoRecepient = new ClinicalLabAutoRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objClinicalLabAutoRecepient);

				//Initiating Message Source for Clinical Laboratory Automation System.
				IMessageSource objClinicalLabAutoSource  = new ClinicalLabAutoSource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objClinicalLabAutoSource);


				   Financial Management System 
				//Initiating Message Recipient for Financial Management System.
				IMessageRecepient objFinancialRecepient = new FinancialRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objFinancialRecepient);

				//Initiating Message Source for Financial Management System.
				IMessageSource objFinancialSource  = new FinancialSource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objFinancialSource);


				   Master Files System 
				//Initiating Message Recipient for Master Files System.
				IMessageRecepient objMasterFileRecepient = new MasterFileRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objMasterFileRecepient);

				//Initiating Message Source for Master Files System.
				IMessageSource objMasterFileSource  = new MasterFileSource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objMasterFileSource);


				   Medical Records System 
				//Initiating Message Recipient for Medical Records System.
				IMessageRecepient objMediRecRecepient = new MediRecRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objMediRecRecepient);

				//Initiating Message Source for Medical Records System.
				IMessageSource objMediRecSource  = new MediRecSource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objMediRecSource);


				  Observation Reporting System 
				//Initiating Message Recipient for Observation Reporting System.
				IMessageRecepient objObsvRepRecepient = new ObsvRepRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objObsvRepRecepient);

				//Initiating Message Source for Observation Reporting System.
				IMessageSource objObsvRepSource  = new ObsvRepSource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objObsvRepSource);


				  Order Entry System 
				//Initiating Message Recipient for Order Entry System.
				IMessageRecepient objOrderEntryRecepient = new OrderEntryRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objOrderEntryRecepient);

				//Initiating Message Source for Order Entry System.
				IMessageSource objOrderEntrySource  = new OrderEntrySource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objOrderEntrySource);


				  Patient Care System 
				//Initiating Message Recipient for Patient Care System.
				IMessageRecepient objPatientCareRecepient = new PatientCareRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objPatientCareRecepient);

				//Initiating Message Source for Patient Care System.
				IMessageSource objPatientCareSource  = new PatientCareSource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objPatientCareSource);


				  Patient Referral System 
				//Initiating Message Recipient for Patient Referral System.
				IMessageRecepient objPatientRefRecepient = new PatientRefRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objPatientRefRecepient);

				//Initiating Message Source for Patient Referral System.
				IMessageSource objPatientRefSource  = new PatientRefSource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objPatientRefSource);


				  Personnel Management System 
				//Initiating Message Recipient for Personnel Management System.
				IMessageRecepient objPersonalMgmtRecepient = new PersonalMgmtRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objPersonalMgmtRecepient);

				//Initiating Message Source for Personnel Management System.
				IMessageSource objPersonalMgmtSource  = new PersonalMgmtSource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objPersonalMgmtSource);


				  Scheduling System 
				//Initiating Message Recipient for Scheduling System.
				IMessageRecepient objSchedulingRecepient = new SchedulingRecepient();

				//Add the Message Recipient in MessageFactory.
				objMessageFactory.addMessageRecepient(objSchedulingRecepient);

				//Initiating Message Source for Scheduling System.
				IMessageSource objSchedulingSource  = new SchedulingSource();

				//Add MessageRecipient to MessageFactory.
				objMessageFactory.addMessageSource(objSchedulingSource);*/


				/*
				 * 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 implementation for FragmentProcessor by implementing IFragmentProcessor interface.
				 */ 
				IFragmentProcessor objIFragmentProcessor = new FragmentAgent();

				//Setting Fragment processor on user session.
				objUserSession.setFragmentProcessor(objIFragmentProcessor);

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

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

				/*
				 * 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 ClientSideTransactionHandler by implementing ITransactionHandler interface.
				 * if user wants verification for each message within transaction then user has to set it else not.
				 */
				ITransactionHandler objClientSideTransactionHandler = new TransactionHandler();

				//Setting this transaction handler on User session.
				objUserSession.setClientSideTransactionHandler(objClientSideTransactionHandler);


				/*
				 * Setting the class implementing behavior of HL7System as listener in asynchronous mode,
				 * to process deffered queries.
				 * User can provide his own implementation by implementing interface IAsynReceiver
				 */
				objUserSession.addExceptionListener((IExceptionListener)this);

				//Connecting User Session to specified Ip and port. 
				//Reading IP address for Client
				System.out.print("Enter IP Adderess of HL7System_Publisher Server: ");
				InputStreamReader input = new InputStreamReader(System.in);
				BufferedReader reader = new BufferedReader(input);
				String strIP = reader.readLine();

				//Reading port for HL7System_Publisher
				System.out.print("Enter Port on which HL7System_Publisher Server is Listening for Subscription messsage: ");
				String strPort = reader.readLine();
				int port = Integer.parseInt(strPort);
				objUserSession.connect(strIP,port);

				// Subscribe for patient id 1
				objUserSession.sendMessage(objMessage);

				//Waiting for time period 
				Thread.sleep(2000);

				//Check that For Subscription send whether ACK is Received or not.
				//Specify the MessageControl Id for message to check the Acknowledgment.
				ISingleCollection<Message> objMessageCollection =null;
				if(objMessage.getMessageCode().equals(EnumMessageCode.QSB.getValue()))
					objMessageCollection = objUserSession.getRecievedMessagesCollection("MSG22Q01");
				else if(objMessage.getMessageCode().equals(EnumMessageCode.QSX.getValue()))
					objMessageCollection = objUserSession.getRecievedMessagesCollection("MSG235001");
				if(objMessageCollection!=null)
				{
					for(Message objMessage: objMessageCollection)
					{
						if(objMessage.getMessageStructure().equals(EnumMessageStructure.ACK.getValue()))
						{
							System.out.println("ACK recieved for "+objMessage.getTriggerEvent());
						}
					}
				}
				else
					System.out.println("ACK not recieved ");

				Thread.sleep(99999);

			}
			catch (InterruptedException e) 
			{
				e.printStackTrace();
			}
			catch(ConnectException ce)
			{
				System.out.println(ce.getMessage());
			}
			catch(SocketException se)
			{
				System.out.println(se.getMessage());
			}
			catch (IOException e) 
			{
				e.printStackTrace();
			}
		}
		/**
		 * This method is invoked when exception is fetched from remote end.
		 * @ex Exception fetched
		 * @buffer for which exception is received
		 */
		public void onException(Exception ex, byte[] buffer) 
		{
			System.out.println("In On Exception Receiced : Printing Stacktrace...");
			System.out.println(ex.getMessage());
			System.out.println("End of Stacktrace....");
			try
			{
				System.out.println("Byte Buffer is : ");
				ByteArrayOutputStream objByteArrayOutputStream = new ByteArrayOutputStream();
				objByteArrayOutputStream.write(buffer);

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

		}

		/**
		 * This method is invoked when exception is fetched from remote end.
		 * @ex Exception fetched
		 * @objISegmentSet for which Segment Set is Received.
		 */
		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
			{
				System.out.println("Segment Set is : ");
				ISingleCollection<ISegment> objISegmentSetCollection = objISegmentSet.getList();
				if(objISegmentSetCollection!=null)
				{
					System.out.println("Received Segment Set Contains following Segments:");
					for(ISegment objISegment : objISegmentSetCollection)
					{
						System.out.println(objISegment.getName());
					}
				}

			}
			catch (Exception e)
			{
				e.printStackTrace();
			}

		}
		/**
		 * This method is invoked when deferred response is received.
		 */
		public void onResponseReceive(Message deferredResponse) 
		{
			System.out.println("Deferred Response Received............ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");

			String strFilePath = null;
			try
			{
				strFilePath = "E:\\Server" + i++ + ".hl7"; //reader.readLine();

				HL7Serializer objHL7Serializer = new HL7Serializer();
				objHL7Serializer.serialize(deferredResponse.getSegmentSet(), strFilePath);

				System.out.print("Message serialized successfully\n");

				//After receiving deferredResponse user sends Acknowledgment in response to Deferred response.
				//generate Acknowledgment with respect to deferred response.
				ACK ackMessage = generateAcknowledgement(deferredResponse);

				//Send Acknowledgment for deferred response
				objUserSession.sendMessage(ackMessage);

				synchronized (this) 
				{
					notify();	
				}
			}catch(IOException ioe)
			{
				ioe.printStackTrace();
			}
			catch (InvalidMessageException e) 
			{
				e.printStackTrace();
			} 
		}
	}
	/**
	 * Closes the Connection.
	 * @param objClientSession object of Client Session.
	 */
	public void onClose(ClientSession objClientSession) 
	{
		System.out.println("On Close");
	}
	/**
	 * This method is invoked when exception is fetched from remote end.
	 * @ex Exception fetched
	 * @objISegmentSet for which Segment Set is Received.
	 */
	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
		{
			System.out.println("Segment Set is : ");
			ISingleCollection<ISegment> objISegmentSetCollection = objISegmentSet.getList();
			if(objISegmentSetCollection!=null)
			{
				System.out.println("Received Segment Set Contains following Segments:");
				for(ISegment objISegment : objISegmentSetCollection)
				{
					System.out.println(objISegment.getName());
				}
			}

		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

	}
}
