package cdac.medinfo.sdk.hl7282.HL7Dump;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

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.MSH;
import cdac.medinfo.sdk.hl7282.commoninterface.ISegment;
import cdac.medinfo.sdk.hl7282.commoninterface.ISegmentSet;
import cdac.medinfo.sdk.hl7282.hl7model.messages.applicationmanagement.AppMgtRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.applicationmanagement.AppMgtSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.claimsandreimbursement.ClaimsAndReimbursementRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.claimsandreimbursement.ClaimsAndReimbursementSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.clinicallaboratoryautomation.ClinicalLabAutoRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.clinicallaboratoryautomation.ClinicalLabAutoSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.financialmanagement.FinancialRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.financialmanagement.FinancialSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.masterfiles.MasterFileRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.masterfiles.MasterFileSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.materialsmanagement.MaterialsMgtRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.materialsmanagement.MaterialsMgtSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.medicalrecords.MediRecRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.medicalrecords.MediRecSource;
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.orderentry.OrderEntryRecepient;
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.PatientCareRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.patientcare.PatientCareSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.patientreferral.PatientRefRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.patientreferral.PatientRefSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.personnelmanagement.PersonalMgmtRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.personnelmanagement.PersonalMgmtSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.query.QryRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.query.QrySource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.scheduling.SchedulingRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.scheduling.SchedulingSource;
import cdac.medinfo.sdk.hl7282.utils.EnumSegments;
import cdac.medinfo.sdk.hl7282.utils.HL7Config;

/**
 * This test code will dump information of message like its segments, groups and its attribute values to XML Sheet.
 */
public class HL7XMLDump 
{

	public static void main(String[] args) 
	{
		InputStreamReader input = new InputStreamReader(System.in);
		BufferedReader reader = new BufferedReader(input);
		HL7XMLDump objHL7Dump = new HL7XMLDump();
		
		try
		{
			int choice = objHL7Dump.menu(reader);
		if(choice==1 || choice==2){	
			//User define HL7 file
			System.out.println("Enter HL7 file to dump:   ");
		    String strHL7File = reader.readLine();
			
			//User can define its own destination folder
			//where user can dump HL7 file			
			System.out.println("Enter destination file (.xml file) where to dump HL7 file:   ");
			String strDestFolder = reader.readLine();
			
			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(null);

			if(strHL7File != null)
			{
				if(strDestFolder == null || strDestFolder.equalsIgnoreCase(""))
					objHL7Dump.dumpHL7Message(choice, strHL7File, System.getProperty("java.io.tmpdir")+"/CDAC-SDK/HL7-J/HL7XMLDump/");
				else
					objHL7Dump.dumpHL7Message(choice, strHL7File, strDestFolder);
			}
			else
			{			
				System.out.println("Not a valid command, Source HL7 file for dump is not specified.");
			}
		}
		else{
			System.out.println("Invalid choice");
		}
		}
		catch(FileNotFoundException exception)
		{
			System.out.println("Operation failed :" + exception.getMessage());
			exception.printStackTrace();
		}
		catch(Exception exception)
		{
			System.out.println("Operation failed :" + exception.getMessage());
			exception.printStackTrace();
		}
	}

	private int menu(BufferedReader reader){
		try {
		System.out.println("Choice 1: Creates XML Document having information of all attributes of HL7 \n\t\tmessage using HL7 specified format and parses the XML to form HL7 message.\n\t\tXML format example:\n\t\t <ADT_A01> <MSH> <MSH.1>|</MSH.1>... </MSH>...</ADT_A01>\n");
		System.out.println("Choice 2: Creates XML Document having information of all attributes of HL7.\n\t\tXML Format example:\n\t\t <Message Name=\"ADT_A01\"> <Segment Name=\"MSH\">\n\t\t<Field Name=\"Field Separator\" Type=\"ST\" Value=\"|\"></Field>...</Segment>...</Message>\n");
		System.out.println("Enter your choice(1/2)");
		int choice=Integer.parseInt(reader.readLine());
		return choice;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return 0;
	}
	
	/**
	 * Creates the MS document for HL7 file.
	 * @param choice to know the xml format required
	 * @param strHL7File HL7 File path.
	 * @param strDestinationPath  Destination folder to store created document.
	 */
	private void dumpHL7Message(int choice, String strHL7File,String strDestinationPath) throws Exception
	{
		/* 
		 * The HL7Parser parses the HL7Message and provides a SegmentSet.
		 * SegmentSet contains all segments of a HL7 Message in the same order as they appeared.
		 */
		HL7Parser objParser = new HL7Parser();
		ISegmentSet objSegmentSet = objParser.parse(strHL7File);

		ISegment objSegment = objSegmentSet.getSegment(0);
		String strSegment = objSegment.getName().getValue();
		strSegment = strSegment.trim();

		if(strSegment.equals(EnumSegments.HL7_SEG_MSH.getValue()))
		{
			
			//Retrieve TriggerEvent and MessageCode
			MSH objMSH = (MSH)objSegment; 
			String strTriggerEvent = (String)objMSH.getMessageType().getTriggerEvent().getValue();
			String strMessageCode = (String)objMSH.getMessageType().getMessageCode().getValue();

			Message objMessage = getMessage(strMessageCode, strTriggerEvent, objSegmentSet);

			//Call Dump
			if(objMessage != null)
			{
				if(choice==1){
					objMessage.writeToXML_v2(strDestinationPath);

					System.out.println("\nDump of HL7 message as per HL7 specified format is stored at " + strDestinationPath);
				ISegmentSet objSegmentSetRead = objParser.readXML(strDestinationPath);
				String dest=strDestinationPath.split("\\.")[0];
				String destination=dest+"_Parsed.hl7";
				
				Message objMessageRead = getMessage(strMessageCode, strTriggerEvent, objSegmentSetRead);
				if(objMessageRead!=null){
					if(objMessage.validate())
					{
						HL7Serializer objHL7Serializer = null;
						objHL7Serializer = new HL7Serializer();
						objHL7Serializer.serialize(objSegmentSetRead,destination);
						System.out.println("\nMessage serialized successfully");
						System.out.println("Serialized HL7 message is stored at " + destination);
					}
				}
				}
				else if(choice==2){
					objMessage.writeToXML(strDestinationPath);

					System.out.println("\nDump of HL7 message is stored at " + strDestinationPath);
				}
			}
		}
		else
		{
			System.out.println("\nOperation supported for HL7 messages only. ");
		}
	}

	/*
	 * Populates message through provided SegmentSet,MessageCode and TriggerEvent
	 */
	private Message getMessage(String strMessageCode,String strTriggerEvent,ISegmentSet objSegmentSet)
	{
		Message objMessage = null;

		MessageFactory objMessageFactory = getMessageFactory();

		objMessage = objMessageFactory.populateReceiveSupportedMessage(strMessageCode, strTriggerEvent, objSegmentSet);

		if(objMessage != null)
		{
			objMessage = objMessageFactory.createSendSupportedMessage(strMessageCode, strTriggerEvent);
			if(objMessage != null)
				objMessage.populate(objSegmentSet);
		}

		return objMessage;
	}

	/*
	 * Populates Message Factory
	 */
	private MessageFactory getMessageFactory()
	{
		MessageFactory objMessageFactory = MessageFactory.createInstance();

		objMessageFactory.addMessageSource(new ObsvRepSource());
		objMessageFactory.addMessageRecepient(new ObsvRepRecepient());
		objMessageFactory.addMessageSource(new AppMgtSource());
		objMessageFactory.addMessageRecepient(new AppMgtRecepient());
		objMessageFactory.addMessageSource(new ClinicalLabAutoSource());
		objMessageFactory.addMessageRecepient(new ClinicalLabAutoRecepient());
		objMessageFactory.addMessageSource(new FinancialSource());
		objMessageFactory.addMessageRecepient(new FinancialRecepient());
		objMessageFactory.addMessageSource(new MasterFileSource());
		objMessageFactory.addMessageRecepient(new MasterFileRecepient());
		objMessageFactory.addMessageSource(new MediRecSource());
		objMessageFactory.addMessageRecepient(new MediRecRecepient());
		objMessageFactory.addMessageSource(new OrderEntrySource());
		objMessageFactory.addMessageRecepient(new OrderEntryRecepient());
		objMessageFactory.addMessageSource(new ADTSource());
		objMessageFactory.addMessageRecepient(new ADTRecepient());
		objMessageFactory.addMessageSource(new PatientCareSource());
		objMessageFactory.addMessageRecepient(new PatientCareRecepient());
		objMessageFactory.addMessageSource(new PatientRefSource());
		objMessageFactory.addMessageRecepient(new PatientRefRecepient());
		objMessageFactory.addMessageSource(new PersonalMgmtSource());
		objMessageFactory.addMessageRecepient(new PersonalMgmtRecepient());
		objMessageFactory.addMessageSource(new QrySource());
		objMessageFactory.addMessageRecepient(new QryRecepient());
		objMessageFactory.addMessageSource(new SchedulingSource());
		objMessageFactory.addMessageRecepient(new SchedulingRecepient());
		objMessageFactory.addMessageSource(new ClaimsAndReimbursementSource());
		objMessageFactory.addMessageRecepient(new ClaimsAndReimbursementRecepient());
		objMessageFactory.addMessageSource(new MaterialsMgtSource());
		objMessageFactory.addMessageRecepient(new MaterialsMgtRecepient());

		return objMessageFactory;
	}



}