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

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.baselibs.segments.Segment;
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.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.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;

public class HL7XMLDump
{
	static int lengthOfOption = 18;
	static int lengthOfDetails = 79 - lengthOfOption;

	public static void main(String[] args) 
	{
		String strLoggingPath = null;
		int choice=1;
		String strDestFolder = null;
		String strHL7File = null;
		HL7XMLDump objHL7XMLDump = new HL7XMLDump();

		/*
		 * If no parameters are provided then help need to be displayed.
		 */
		if(args == null || args.length ==0)
		{
			objHL7XMLDump.displayHelp();
			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("-s") && args.length > i+1)
			{
				//reading destination dir path where received requests will be dumped
				strDestFolder = args[i+1] ;
				i++;
			}
			else if(args[i].equalsIgnoreCase("-f") && args.length > i + 1)
			{
				strHL7File = args[i + 1];
				i++;
			}
			else if(args[i].equalsIgnoreCase("-c") && args.length > i + 1)
			{
				String ch = args[i + 1];
				choice=Integer.parseInt(ch);
				i++;
			}
			else
			{
				System.out.println("Not a valid command");
				objHL7XMLDump.displayHelp();
				System.exit(0);
			}
		}

		try
		{
			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);

			//HL7 message file is minimum parameter requirement
			if(strHL7File != null)
			{

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

	/**
	 * Displays the help.
	 */
	private void displayHelp()
	/*{
		System.out.println("\nHL7XMLDUMP :: Creates XML Document having infromation of all attributes of HL7 \nmessage.");
		System.out.println("\nHL7XMLDUMP [-d LogDir]  " +
		"-f HL7file [-s DestinationFolder]  \n");

		printToConsole("-d", "Log directory");
		printToConsole("", "User's temp directory is taken as default.");
		printToConsole("-f", "Source HL7 file for dump.");
		printToConsole("-s", "Destination folder path to store converted XML documet file.");
		printToConsole("", "User's temp directory is taken as default.");
        
        System.out.println("\nExample :");

		System.out.println("\n1. HL7XMLDUMP -f image.hl7 -s C:/HL7Content " +
		"\nDumps the information of HL7 message to XML document and stores same to folder \nC:/HL7Content.\n");

	}*/
	{
		System.out.println("\nHL7XMLDUMP ::\t Choice 1: Creates XML Document having infromation 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: <ADT_A01>	<MSH>	<MSH.1>|</MSH.1>... </MSH>...</ADT_A01>");
		System.out.println();
		System.out.println("\t\tChoice 2: Creates XML Document having infromation of all attributes of HL7.\n\t\tXML Format example: <Message Name=\"ADT_A01\">	<Segment Name=\"MSH\">\n\t\t<Field Name=\"Field Separator\" Type=\"ST\" Value=\"|\"></Field>...</Segment>...</Message>");
	
		System.out.println("\nHL7XMLDUMP [-d LogDir]  " +"[-c FormatChoice]  "+
		"-f HL7file [-s DestinationFolder]  \n");
		printToConsole("-c", "Choice of format\t 1.HL7 specified format\t 2.other format");
		printToConsole("", "(Note: Default choice is 1)");
		printToConsole("-d", "Log directory");
		printToConsole("", "User's temp directory is taken as default.");
		printToConsole("-f", "Source HL7 file for dump.");
		printToConsole("-s", "Destination folder path to store converted XML documet file.");
		printToConsole("", "User's temp directory is taken as default.");
        
        System.out.println("\nExample :");

		System.out.println("\n1. HL7XMLDUMP -c 1 -f image.hl7 -s C:/HL7Content/image.xml " +
		"\nDumps the information of HL7 message to XML document image.xml and stores same to folder \nC:/HL7Content.\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]);
	}


	/**
	 * Creates the XML document for HL7 file.
	 * @choice to decide the format of XML
	 * @param strHL7File HL7 File path.
	 * @param strDestinationPath  Destination folder to store created document.
	 */
	private void dumpHL7Message(int choice,String strHL7File,String strDestinationPath) throws Exception
	{
		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()))
		{
			String strMessageCode =null;
			String strTriggerEvent = null;
			Segment objTempSegment = (Segment)objSegmentSet.getSegment(0);
			if(objTempSegment.getName().equals(EnumSegments.HL7_SEG_MSH))
			{
				MSH objMSH = (MSH)objTempSegment;
				strMessageCode = (String)objMSH.getMessageType().getMessageCode().getValue();
				strTriggerEvent = (String)objMSH.getMessageType().getTriggerEvent().getValue();
			}
			Message objMessage = getMessage(strMessageCode, strTriggerEvent, objSegmentSet);
			
			//Call Dump
			if(objMessage != null)
			{
				if (choice == 1) {
					objMessage.writeMessageToXML_v2(strDestinationPath);

					System.out.println("\nDump of HL7 message as per HL7 specified format is stored at " + strDestinationPath);

					ISegmentSet objSegmentSetRead = objParser.readXML(strDestinationPath);
					String strDest = strDestinationPath.split("\\.")[0];
					String destination = strDest + "_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("Message 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("Invalid format choice");
					displayHelp();
					System.exit(0);
				}
			}
		}
		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());

		return objMessageFactory;
	}
}
