package gov.va.med.esr.messaging.parser;

import gov.va.med.esr.common.builder.entity.IncomeTestMetaData;
import gov.va.med.esr.common.builder.entity.metaData.IncomeTestMetaDataFromZMT;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.messaging.constants.HL7Constants;
import gov.va.med.esr.messaging.service.MessageProcessServiceUtil;
import gov.va.med.esr.messaging.util.AbstractMessagingTest;
import gov.va.med.esr.messaging.xml.XmlFormatter;
import gov.va.med.esr.service.PersonService;
import gov.va.med.fw.hl7.BatchMessage;
import gov.va.med.fw.hl7.Message;
import gov.va.med.fw.hl7.constants.SegmentConstants;
import gov.va.med.fw.hl7.segment.MSH;
import gov.va.med.fw.hl7.segment.PID;
import gov.va.med.fw.hl7.segment.ZIC;
import gov.va.med.fw.hl7.segment.ZPD;
import gov.va.med.fw.util.StopWatchLogger;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

/**
 * 
 * @author Rajiv Patnaik Created on Jul 27, 2005
 * @version 1.0
 * 
 * Copyright © 2005 VHA. All rights reserved
 */
public class Z07ParserTest extends AbstractMessagingTest
{

   public Z07ParserTest(String name)
    {
        super(name);
    }

   public void testRelationNameChanges() throws Exception
   {
       //Create a BatchMessage object
       BatchMessage batchMessage = (BatchMessage) super.createORUZ07Message();

       //Parses the message into segments
       batchMessage.getSegments();

       //Parses the message into different messages each containing its
       // respective segments
       List messages = batchMessage.getMessages();

       Z07Parser parser = (Z07Parser) applicationContext
               .getBean("inbound.z07Parser");
       
       //Build a simple Person in memory
       //Person person = buildSimplePerson();

       //Save the person so that it gets a database identifier.Without this
       //the parser returns null.
       PersonService personService = (PersonService) applicationContext.getBean("personService");
       //73293
       //5352
       Person person = personService.getPerson(CommonEntityKeyFactory
               .createPersonIdEntityKey("5352"));
       Person incoming = (Person)person.clone();
       Person built = null;
       
       //Right now there is only one message in the BatchMessage object
       for (Iterator iter = messages.iterator(); iter.hasNext();)
       {
           Message message = (Message) iter.next();
           //Parse the message and overlay the info on top of the retrieved
           // Person from database
           built = parser.build(incoming, message);
           assertNotNull("Person from parser is null", built);
       }

       assertNotNull("Person from parser is null", built);

   }
   
   
   public void testBuild() throws Exception
   {
       //Create a BatchMessage object
       BatchMessage batchMessage = (BatchMessage) super.createORUZ07Message();

       //Parses the message into segments
       batchMessage.getSegments();

       //Parses the message into different messages each containing its
       // respective segments
       List messages = batchMessage.getMessages();

       //Get a formatter to parse the Message and convert it to a XMLstring
       XmlFormatter messageFormatter = (XmlFormatter) applicationContext.getBean("inbound.oruz07.xmlFormatter");

       Z07Parser parser = (Z07Parser) applicationContext
               .getBean("inbound.z07Parser");
       
       //Build a simple Person in memory
       //Person person = buildSimplePerson();

       //Save the person so that it gets a database identifier.Without this
       //the parser returns null.
       PersonService personService = (PersonService) applicationContext.getBean("personService");
       //73293
       //5352
       Person person = personService.getPerson(CommonEntityKeyFactory
               .createPersonIdEntityKey("5352")); 
       //Right now there is only one message in the BatchMessage object
       for (Iterator iter = messages.iterator(); iter.hasNext();)
       {
           Message message = (Message) iter.next();
           //Parse the message and overlay the info on top of the retrieved
           // Person from database
           person = parser.build(person, message);
           assertNotNull("Person from parser is null", person);

           //Call the XMLFormatter to convert the raw message into XML
           String messageAsXML = MessageProcessServiceUtil
                   .getFormattedMessageBody(messageFormatter.build(message
                           .getMessageData()));

           //Build a DOM tree out of the XML doc
           DocumentBuilder builder = DocumentBuilderFactory.newInstance()
                   .newDocumentBuilder();
           Document document = builder.parse(new InputSource(new StringReader(
                   messageAsXML)));

           String sendingFacilityStationNumber = BaseSegmentsTestDataValidator
                   .getSendingFacilityStationNumber(document);
           VAFacility vaFacility = getLookupService().getVaFacilityByCode(
                   sendingFacilityStationNumber);

           //Now start validating the Person object to see that each segment
           // has been built corrrectly
           new PIDTestDataValidator().validatePID(document, person);
           new ZPDTestDataValidator().validateZPD(document, person);
           new ZTATestDataValidator().validateZTA(document, person);
           new ZIETestDataValidator().validateZIE(document, person);
           new ZELTestDataValidator().validateZEL(document, person,
                   getPersonHelperService());
           new ZENTestDataValidator().validateZEN(document, person);
           new ZCDTestDataValidator().validateZCD(document, person, getPersonHelperService());
           new ZMHTestDataValidator().validateZMH(document, person);
           new ZRDTestDataValidator().validateZRD(document, person);
           new ZCTTestDataValidator().validateZCT(document, person);
           new ZEMTestDataValidator().validateZEM(document, person);
           //ZGD
           new ZICTestDataValidator().validateZIC(document, person);
           //ZIR
           //ZDP
           new ZIOTestDataValidator()
                   .validateZIO(document, person, vaFacility);
           //NTE
           //new ZMTTestDataValidator().validateZMT(document, person, getPersonHelperService());
           new ZBTTestDataValidator().validateZBT(document, person, getPersonHelperService(), vaFacility);
           //ZFE
           new ZSPTestDataValidator()
                   .validateZSP(document, person, vaFacility);

       }

   }

   
   
    public void testCreateUnmigratedICNFile() throws Exception
    {
    	 StopWatchLogger watch = new StopWatchLogger("testCreateUnmigratedICNFile()");
    	 watch.start();
    	//FileWriter outFile =  new FileWriter("D:\\bea\\dev\\data\\ORUZ07_BIG_1.out");
    	//PrintWriter out = new PrintWriter(outFile);
//    	File file = new File("C:\\tmp\\ORUZ07_BIG_1.out");
//    	DataOutputStream out = new DataOutputStream(new FileOutputStream(file)); 
    	
    	FileWriter fstream = new FileWriter("C:\\tmp\\ORUZ07_BIG_1.out");
    	BufferedWriter out = new BufferedWriter(fstream);
    	
    	FileWriter fstream2 = new FileWriter("C:\\tmp\\Report.out");
    	BufferedWriter out2 = new BufferedWriter(fstream2);
    	  
		BufferedReader in = null;
		try {
			//System.out.println(Runtime.getRuntime().freeMemory() +"/" +Runtime.getRuntime().totalMemory() );
			InputStreamReader input = new InputStreamReader(
					new BufferedInputStream(new FileInputStream("C:\\tmp\\ORUZ07_BIG.txt")));
			
			
			//System.out.println("read the file" );
			//System.out.println(Runtime.getRuntime().freeMemory() +"/" +Runtime.getRuntime().maxMemory() );
			in = new BufferedReader(input);
			
		} catch (Throwable e) {
			e.printStackTrace();
		}
		//return content.toString();
//		System.gc();
//		Thread.sleep(10000);
//		
//		
//		System.gc();
//		Thread.sleep(10000);
		String data = null;
		int lineNum = 0;
		int messageNum = 0;
		int successNum = 0;
		int exceptionNum = 0;
		int duplicateNum = 0;
		
		StringBuffer singleMessage = new StringBuffer();
		Map map = new HashMap();
		String aRecord = null;
		if (in != null) {
			while ((data = in.readLine()) != null) {
				lineNum++;
				
				if ( lineNum > 1 && data != null && data.startsWith("MSH^~|")) {
					// This is a new message. 
					
					//process siggle message in a batch 
					messageNum++;
					/**
					if (messageNum == 25001 ) {
				    	outFile =  new FileWriter("D:\\bea\\dev\\data\\ORUZ07_BIG_2.out");
				    	out = new PrintWriter(outFile);
						
					}**/
					//System.out.println("Message#" + messageNum);
					try{
	//					out.writeChars(processSignleMessage(singleMessage.toString(), out));
						aRecord = processSignleMessage(singleMessage.toString(), out);
						if (map.get(aRecord) == null)
						{
							out.write(aRecord);
							successNum++;
							map.put(aRecord, "");
						} else
						{
							//duplicate
							duplicateNum++;
						}
		
					}catch(Exception e) {
	//					out.writeChars("Exception on " + singleMessage.toString());
	//					out.write("Exception on " + singleMessage.toString());
						out2.write("Exception on: " + singleMessage.toString() + " with Exception= " + ExceptionUtils.getFullStackTrace(e) + "\n");
						exceptionNum++;
					}
					
					singleMessage = new StringBuffer();
	
				} 
				singleMessage.append(data).append("\n");
				
				//System.out.println("lineNum#" + lineNum);
				//System.out.println(Runtime.getRuntime().freeMemory() +"/" +Runtime.getRuntime().totalMemory() +"/" +Runtime.getRuntime().maxMemory());
			}
		}
//		out.writeChars(processSignleMessage(singleMessage.toString(), out));
		try {
			messageNum++;
			aRecord = processSignleMessage(singleMessage.toString(), out);
			if (map.get(aRecord) == null)
			{
				out.write(aRecord);
				successNum++;
				map.put(aRecord, "");	

			} else {
				//duplicate
				duplicateNum++;
			}
		}catch(Exception e) {
			out2.write("Exception on: " + singleMessage.toString() + " with Exception= " + ExceptionUtils.getFullStackTrace(e) + "\n");
			exceptionNum++;
		}
		
		out.close();
		
		watch.stop();
		out2.write("testCreateUnmigratedICNFile() total seconds = " + watch.getTotalTimeSeconds());
		out2.write("\nTotal # of messages: " + messageNum + "\nTotal # of exceptions: " + exceptionNum + "\nTotal # written successfully: " +successNum + "\nTotal # of duplicate: " + duplicateNum);
		
		out2.close();
    }

    
//    private String processSignleMessage(String messageString, DataOutputStream out) throws Exception{
    private String processSignleMessage(String messageString, BufferedWriter out) throws Exception{
        //Create a BatchMessage object
    	
    	String batchHeader = "BHS^~|\\&^VAMC 442^442^ESR^200ESR31^20040810^^~T~ORU|Z07~2.3.1~AL~AL^^54364365^\n";
    	String batchTrailer = "BTS^1\n";
    	messageString = batchHeader+messageString+batchTrailer;
        BatchMessage batchMessage = new BatchMessage(messageString,HL7Constants.ORUZ07);
        //Parses the message into segments
        batchMessage.getSegments();

        //Parses the message into different messages each containing its
        // respective segments
        List messages = batchMessage.getMessages();

        //Get a formatter to parse the Message and convert it to a XMLstring
        XmlFormatter messageFormatter = (XmlFormatter) applicationContext.getBean("inbound.oruz07.xmlFormatter");

        Z07Parser parser = (Z07Parser) applicationContext
                .getBean("inbound.z07Parser");
        
        //Build a simple Person in memory
        //Person person = buildSimplePerson();

        //Save the person so that it gets a database identifier.Without this
        //the parser returns null.
        PersonService personService = (PersonService) applicationContext.getBean("personService");
        //73293
        //5352
        //Person person = personService.getPerson(CommonEntityKeyFactory
        //        .createPersonIdEntityKey("5352")); 
        //Right now there is only one message in the BatchMessage object
        for (Iterator iter = messages.iterator(); iter.hasNext();)
        {
            Message message = (Message) iter.next();
            //Parse the message and overlay the info on top of the retrieved
            // Person from database
            
            
            MSH msh = (MSH)message.getSegment("msh");
            //String sendingFacility = msh.getSendingFacility();
            String sendingFacility = message.getSendingFacility();
            //System.out.println("Sending Facility :" + sendingFacility);

            List zmts = message.getSegments(SegmentConstants.ZMT);
            String incomeYear = "MISSING";
            try {
				IncomeTestMetaData incomeTestMetadata = new IncomeTestMetaDataFromZMT(
						(ZPD) message.getSegment(SegmentConstants.ZPD), zmts,
						message.getSegments(SegmentConstants.NTE),
						(ZIC) message.getSegment(SegmentConstants.ZIC), message
								.getSendingFacility());
				String incomeYearStr = incomeTestMetadata.getIncomeYear();
				
				if (incomeYearStr != null)
					incomeYear = incomeTestMetadata.getIncomeYear().substring(
							0, 4);

			} catch (Exception e) {

			}
            
            // System.out.println("Income Year :" +
			// incomeTestMetadata.getIncomeYear());
            PID pid = (PID)message.getSegment("PID");

            String dob = pid.getDOB();
            String idList = pid.getPatientIdentifierList();
            String dfn = null;
            
            List subelements = convertTokensToList(idList, "|");
            for ( int i=0; i<subelements.size();i++) {
            	String subele = (String)subelements.get(i);
            	List eles = convertTokensToList(subele, "~");
            	if ( eles != null && eles.size() > 3 ) {
            		String typeName = (String)eles.get(6);
            		if ("PI".equals(typeName)) {
            			dfn = (String) (String)eles.get(0);
            			break;
            		}
            	}
            }

            //System.out.println("dfn:" + dfn);
            //System.out.println("dob:" + dob);
            return "SSN^LASTNAME^FIRSTNAME^GENDER^"+dob+"^"+ dfn+"^"+sendingFacility+"^"+incomeYear+"\n";

        }
        return "";
    }
    
    

    
	private List convertTokensToList(String subele, String delim ){
		List strs = new ArrayList();
		
		StringTokenizer st = new StringTokenizer(subele,delim ,true);
		while ( st.hasMoreTokens()) {
			strs.add(st.nextToken());
		}
		return strs;
	}
}