package cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.batch;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Locale;

import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.StartDocument;
import javax.xml.stream.events.XMLEvent;

import cdac.medinfo.sdk.hl7282.baselibs.segments.FHS;
import cdac.medinfo.sdk.hl7282.baselibs.segments.FTS;
import cdac.medinfo.sdk.hl7282.baselibs.segments.Segment;
import cdac.medinfo.sdk.hl7282.commoninterface.ISingleCollection;
import cdac.medinfo.sdk.hl7282.exceptions.BatchException;
import cdac.medinfo.sdk.hl7282.exceptions.InvalidMessageException;
import cdac.medinfo.sdk.hl7282.exceptions.InvalidSegmentException;
import cdac.medinfo.sdk.hl7282.exceptions.SegmentMissingException;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IHL7Batch;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IHL7BatchFile;
import cdac.medinfo.sdk.hl7282.utils.EnumSegments;
import cdac.medinfo.sdk.hl7282.utils.HL7Config;
import cdac.medinfo.sdk.hl7282.utils.HL7Constants;
import cdac.medinfo.sdk.hl7282.utils.ResourceBundleWrapper;

/**
 * HL7BatchFile consist of BatchFile header, trailer, and
 * Collection of batches .
 */
public class HL7BatchFile implements IHL7BatchFile 
{
	

	/** The batch file header. */
	private FHS objBatchFileHeader;

	/** The batch file trailer. */
	private FTS objBatchFileTrailer;

	/** The HL7Batch collection. */
	private ISingleCollection<IHL7Batch> objHL7BatchCollection;


	/**
	 * Instantiates HL7BatchFile
	 */
	public HL7BatchFile()
	{

	}


	/**
	 * Instantiates HL7Batch batch with header and trailer segment provided.
	 * @param objFHS Specified batch file header segment  
	 * @param objFTS Specified batch file trailer segment
	 * @param objHL7BatchCollection Message Batch to be inserted in Batch file. 
	 */
	public HL7BatchFile(FHS objFHS,FTS objFTS,ISingleCollection<IHL7Batch> objHL7BatchCollection)
	{
		this.objBatchFileHeader = objFHS;
		this.objBatchFileTrailer = objFTS;
		this.objHL7BatchCollection = objHL7BatchCollection;
	}


	/**
	 * Gets the batch file header.
	 * @return FHS -the batch file header
	 */
	public FHS getBatchFileHeader() 
	{
		return objBatchFileHeader;
	}

	/**
	 * Sets the batch file header.
	 * @param objBatchFileHeader the new batch file header
	 */
	public void setBatchFileHeader(FHS objBatchFileHeader) 
	{
		this.objBatchFileHeader = objBatchFileHeader;
	}

	/**
	 * Gets the batch file trailer.
	 * @return FTS - the batch file trailer
	 */
	public FTS getBatchFileTrailer() 
	{
		return objBatchFileTrailer;
	}

	/**
	 * Sets the batch file trailer.
	 * @param objBatchFileTrailer the new batch file trailer
	 */
	public void setBatchFileTrailer(FTS objBatchFileTrailer) 
	{
		this.objBatchFileTrailer = objBatchFileTrailer;
	}

	/**
	 * Gets the HL7Batch collection.
	 * @return ISingleCollection<IHL7Batch> - the HL7Batch collection
	 */
	public ISingleCollection<IHL7Batch> getHL7BatchCollection() 
	{
		return objHL7BatchCollection;
	}

	/**
	 * Sets the HL7Batch collection.
	 * @param objHL7BatchCollection the new HL7Batch collection
	 */
	public void setHL7BatchCollection(ISingleCollection<IHL7Batch> objHL7BatchCollection) 
	{
		this.objHL7BatchCollection = objHL7BatchCollection;
	}
	
	/**
	 * Serializes Batch File Information in the form of XML.
	 * @return String - Returns Batch File in XML format 
	 * @throws IOException
	 * @throws XMLStreamException
	 */
	public String writeBatchFileToXML_v2() throws IOException, XMLStreamException
	{
		
		// Create a XMLOutputFactory
		XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
		// Create XMLEventWriter
		Writer stringWriter=new StringWriter();
		XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(stringWriter);


		// Create a EventFactory
		XMLEventFactory eventFactory = XMLEventFactory.newInstance();
		// Create and write Start Tag
		StartDocument startDocument = eventFactory.createStartDocument();
		eventWriter.add(startDocument);		
		XMLEvent end = eventFactory.createDTD("\n");
		XMLEvent tab = eventFactory.createDTD("\t");
		
		eventWriter.add(end); 
		
		eventWriter.add(eventFactory.createStartElement("", "", "BATCH"));
		
		FHS objFHS = getBatchFileHeader();
		objFHS.writeToXML_v2(eventWriter);
		
		eventWriter.add(end); 
		
		for(IHL7Batch objHL7Batch : objHL7BatchCollection)
		{
			((HL7Batch) objHL7Batch).writeToXML(eventWriter);				
		}
		
		FTS objFTS = getBatchFileTrailer();
		objFTS.writeToXML_v2(eventWriter);		
		eventWriter.add(end);
		
		eventWriter.add(eventFactory.createEndElement("", "", "BATCH"));
		eventWriter.add(eventFactory.createEndDocument());
		eventWriter.close();
		return stringWriter.toString();	

	}

	/**
	 * Serializes Batch File Information in the form of XML.
	 * @param strFilePath Destination file path
	 * @throws IOException
	 * @throws XMLStreamException
	 */
	public void writeBatchFileToXML_v2(String strFilePath) throws IOException, XMLStreamException
	{
		
		// Create a XMLOutputFactory
		XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
		// Create XMLEventWriter
		XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(new FileOutputStream(strFilePath));


		// Create a EventFactory
		XMLEventFactory eventFactory = XMLEventFactory.newInstance();
		// Create and write Start Tag
		StartDocument startDocument = eventFactory.createStartDocument();
		eventWriter.add(startDocument);		
		XMLEvent end = eventFactory.createDTD("\n");
		XMLEvent tab = eventFactory.createDTD("\t");
		
		eventWriter.add(end); 
		
		eventWriter.add(eventFactory.createStartElement("", "", "BATCH"));
		
		FHS objFHS = getBatchFileHeader();
		objFHS.writeToXML_v2(eventWriter);
		
		eventWriter.add(end); 
		
		for(IHL7Batch objHL7Batch : objHL7BatchCollection)
		{
			((HL7Batch) objHL7Batch).writeToXML(eventWriter);				
		}
		
		FTS objFTS = getBatchFileTrailer();
		objFTS.writeToXML_v2(eventWriter);		
		eventWriter.add(end);
		
		eventWriter.add(eventFactory.createEndElement("", "", "BATCH"));
		eventWriter.add(eventFactory.createEndDocument());
		eventWriter.close();

	}

	/**
	 * Validates HL7 BatchFile objects.
	 * @return true - if successful
	 * 		   false - otherwise
	 * @throws BatchException the invalid HL7Batch exception
	 */
	public boolean validate()throws BatchException
	{
		try
		{
			// Step 1: Validate FHS and FTS Segments
			if(objBatchFileHeader == null && objBatchFileTrailer != null ) 
				throw new SegmentMissingException(EnumSegments.HL7_SEG_FHS.getValue());
			if(objBatchFileHeader != null && objBatchFileTrailer == null ) 
				throw new SegmentMissingException(EnumSegments.HL7_SEG_FTS.getValue());

			if(objBatchFileHeader != null && objBatchFileTrailer != null ) 
			{
				objBatchFileHeader.validate();
				objBatchFileTrailer.validate();
			}
			// Step 2: Call Validate on Batches contained in it.
			if(objHL7BatchCollection!=null)
			{
				for (IHL7Batch objHL7Batch : objHL7BatchCollection)
				{
					objHL7Batch.validate();
				}
			}
		}
		catch(InvalidSegmentException ex)
		{
			throw new BatchException(ResourceBundleWrapper.getValue("exceptions","InvalidSegment",new Locale(HL7Config.createInstance().getLocale())));
		}
		catch(SegmentMissingException ex)
		{
			throw new BatchException(ResourceBundleWrapper.getValue("exceptions","SegmentMissing",new Locale(HL7Config.createInstance().getLocale())));
		}
		catch(InvalidMessageException ex)
		{
			throw new BatchException(ResourceBundleWrapper.getValue("exceptions","InvalidMessage",new Locale(HL7Config.createInstance().getLocale())));
		}
		return true;
	}

}
