/*******************************************************************************
 *  Copyright 2017 Centre for Development of Advanced Computing(C-DAC), Pune
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *    http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *******************************************************************************/
package cdac.medinfo.sdk.hl7282.baselibs.segments;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Locale;

import cdac.medinfo.sdk.hl7282.baselibs.CWE;
import cdac.medinfo.sdk.hl7282.baselibs.DTM;
import cdac.medinfo.sdk.hl7282.baselibs.ID;
import cdac.medinfo.sdk.hl7282.baselibs.ST;
import cdac.medinfo.sdk.hl7282.baselibs.segmentfactory.DataElementFactory;
import cdac.medinfo.sdk.hl7282.commoninterface.IDataType;
import cdac.medinfo.sdk.hl7282.commoninterface.IDelimiter;
import cdac.medinfo.sdk.hl7282.commoninterface.ISingleCollection;
import cdac.medinfo.sdk.hl7282.exceptions.FieldMissingException;
import cdac.medinfo.sdk.hl7282.exceptions.InvalidDataTypeException;
import cdac.medinfo.sdk.hl7282.exceptions.InvalidDelimiterException;
import cdac.medinfo.sdk.hl7282.exceptions.InvalidFieldException;
import cdac.medinfo.sdk.hl7282.exceptions.InvalidSegmentException;
import cdac.medinfo.sdk.hl7282.hl7streams.HL7BufferStream;
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;
import cdac.medinfo.sdk.hl7282.utils.SingleCollection;

/**
 * MFA - Master File Acknowledgment Segment. <p>
 * The Technical Steward for the MFE segment is CQ.
 * <p>Represents an HL7 MFA message segment. 
 * This segment has the following fields:</p><p>
 * MFA-1: Record-Level Event Code (ID)<b>Required</b><br> 
 * MFA-2: MFN Control ID (ST)<b>Conditional</b><br> 
 * MFA-3: Event Completion Date/Time (DTM)<b>Optional</b><br> 
 * MFA-4: MFN Record Level Error Return (CWE)<b>Required</b><br> 
 * MFA-5: Primary Key Value - MFA (Varies)<b>Required</b><br> 
 * MFA-6: Primary Key Value Type - MFA (ID)<b>Required</b><br><p>
 * This class provides mechanism to validate message against HL7 v 2.8.2 standard.
 * The class provides accessors & mutators for the elements mentioned above.
 * The class has validate method which validates Message against HL7 v 2.8.2 standard.
 *
 * <p>User can also create Segment through {@link SegmentFactory}
 */
 public class MFA extends Segment   
{
	
	/**
	 * Constructs the MFA segment.
	 */
	public MFA()
	{super(EnumSegments.HL7_SEG_MFA);
	}
	//Integer values used in getter/setter is unique item id defined 
	//for each attribute.

	/**
	 * Retrieves the Event Completion Date Time.
	 * This field may be require or optional depending on the site specifications
	 *  for the given master file, master file event, and receiving facility.
	 * @return DTM - eventCompletionDate_Time
	 */
	public DTM getEventCompletionDate_Time() 
	{
		ISingleCollection<IDataType> objDataCollection =getDataType(668);
		if(objDataCollection != null && objDataCollection.size() != 0) 
			return (DTM)objDataCollection.elementAt(0);
		else
			return null;
	}

	/**
	 * Retrieves the MFN Control ID.
	 * This field contains a number or other identifier that uniquely
	 *  identifies this change to this record from the point of view of the originating system.  
	 * @return ST - mFNControlID
	 */
	public ST getMFNControlID() 
	{
		ISingleCollection<IDataType> objDataCollection =getDataType(665);
		if(objDataCollection != null && objDataCollection.size() != 0) 
			return (ST)objDataCollection.elementAt(0);
		else
			return null;
	}

	/**
	 * Retrieves the MFN Record Level Error Return.
	 * This field contains the status of the requested update. Site-defined table, 
	 * specific to each master file being updated via this transaction.
	 * @return CWE - mFNRecordLevelErrorReturn
	 */
	public CWE getMFNRecordLevelErrorReturn() 
	{
		ISingleCollection<IDataType> objDataCollection =getDataType(669);
		if(objDataCollection != null && objDataCollection.size() != 0) 
			return (CWE)objDataCollection.elementAt(0);
		else
			return null;
	}

	/**
	 * Retrieves the Primary Key Value MFA.
	 * This field uniquely identifies the record of the master file. 
	 * @return ISingleCollection<IDataType> - primaryKeyValueMFA
	 */
	public ISingleCollection<IDataType> getPrimaryKeyValueMFA() 
	{
		ISingleCollection<IDataType> objDataCollection =getDataType(1308);
		ISingleCollection<IDataType> objDataList = new SingleCollection<IDataType>(); 
		if(objDataCollection != null && objDataCollection.size() != 0)
		{
			for(IDataType objDataType : objDataCollection)
			{
				objDataList.add(objDataType);
			}
		}
		return objDataList;
	}

	/**
	 * Retrieves the Primary Key Value Type MFA.
	 * This field contains the HL7 data type of MFA-5 - Primary Key Value - MFA.  
	 * @return ISingleCollection<ID> - primaryKeyValueTypeMFA
	 */
	public ISingleCollection<ID> getPrimaryKeyValueTypeMFA() 
	{
		ISingleCollection<IDataType> objDataCollection =getDataType(1320);
		ISingleCollection<ID> objDataList = new SingleCollection<ID>(); 
		if(objDataCollection != null && objDataCollection.size() != 0)
		{
			for(IDataType objDataType : objDataCollection)
			{
				ID objID = (ID)objDataType;
				objDataList.add(objID);
			}
		}
		return objDataList;
	}

	/**
	 * Retrieves the Record Level Event Code.
	 * This field defines record-level event for the master file record 
	 * identified by the MFI segment and the primary key in this segment.  
	 * @return ID - recordLevelEventCode
	 */
	public ID getRecordLevelEventCode() 
	{
		ISingleCollection<IDataType> objDataCollection =getDataType(664);
		if(objDataCollection != null && objDataCollection.size() != 0) 
			return (ID)objDataCollection.elementAt(0);
		else
			return null;
	}

	/**
	 * Set the Record Level Event Code.
	 * This field defines record-level event for the master file record 
	 * identified by the MFI segment and the primary key in this segment.
	 * @param strRecordLevelEventCode String value of code. 
	 */ 
	public void setRecordLevelEventCode (String strRecordLevelEventCode) 
	{
		ID recordLevelEventCode  = (ID)getDataElement(664);
		recordLevelEventCode.setValue(strRecordLevelEventCode); 
		setRecordLevelEventCode(recordLevelEventCode);


	} 

	/** Set the Record Level Event Code.
	 * This field defines record-level event for the master file record 
	 * identified by the MFI segment and the primary key in this segment.
	 * @param objrecordLevelEventCode object of Record Level Event Code. 
	 */ 
	public void setRecordLevelEventCode(ID objrecordLevelEventCode)
	{
		setDataType(664,objrecordLevelEventCode);


	}
	/**
	 * Set the MFN Control ID.
	 * This field contains a number or other identifier that uniquely
	 *  identifies this change to this record from the point of view of the originating system.
	 * @param strMFNControlID Used as MFNControlID.
	 */ 
	public void setMFNControlID (String strMFNControlID) 
	{
		ST mFNControlID  = (ST)getDataElement(665);
		mFNControlID.setValue(strMFNControlID); 
		setMFNControlID(mFNControlID);


	} 

	/** Set the MFN Control ID.
	 * This field contains a number or other identifier that uniquely
	 *  identifies this change to this record from the point of view of the originating system.
	 * @param objmFNControlID object of MFN Control ID.
	 */ 
	public void setMFNControlID(ST objmFNControlID)
	{
		setDataType(665,objmFNControlID);


	}
	/**
	 * SetEventCompletionDate_Time
	 * @param strTime Specifies a point in time using a 24-hour clock notation. 
	 */ 
	public void setEventCompletionDate_Time (String strTime) 
	{
		DTM eventCompletionDate_Time  = (DTM)getDataElement(668);
		eventCompletionDate_Time.setValue(strTime);
		setEventCompletionDate_Time(eventCompletionDate_Time);
	} 

	/** SetEventCompletionDate_Time
	 * @param objeventCompletionDate_Time object of Event Completion Date_Time.
	 */ 
	public void setEventCompletionDate_Time(DTM objeventCompletionDate_Time)
	{
		setDataType(668,objeventCompletionDate_Time);


	}
	/**
	 * Set the MFN Record Level Error Return.
	 * This field contains the status of the requested update. Site-defined table, 
	 * specific to each master file being updated via this transaction.
	 * @param strIdentifier Specifies of characters (the code) that uniquely identifies the item being referenced. 
	 * @param strText Specifies The descriptive or textual name of the identifier, e.g., myocardial infarction. 
	 * @param strNameOfCodingSystem Identifies the coding scheme being used in the identifier component.
	 * @param strAlternateIdentifier Specifies an alternate sequence of characters (the code) that uniquely identifies the item being referenced.
	 * @param strAlternateText Specifies the descriptive or textual name of the alternate identifier. See usage note in section introduction.
	 * @param strNameOfAlternateCodingSystem Identifies the coding scheme being used in the alternate identifier component. 
	 * @param strCodingSystemVersionID A sequence of characters that uniquely identifies a second alternate code.
	 * @param strAlternateCodingSystemVersionId This component carries the version for the coding system identified by components 4-6.
	 * @param strOriginalText The text as seen and/or selected by the user who entered the data.
	 * @param strSecondAlternateIdentifier A sequence of characters that uniquely identifies a second alternate code.
	 * @param strSecondAlternateText The descriptive or textual name of the alternate identifier.
	 * @param strNameofSecondAlternateCodingSystem Identifies the coding scheme being used in the alternate identifier component.
	 * @param strSecondAlternateCodingSystemVersionID This component carries the version for the coding system identified by components 10-12.
	 * @param strCodingSystemOID This component contains the ISO Object Identifier (OID) for the coding system or value set named in CWE.3.
	 * @param strValueSetOID This component contains the ISO Object Identifier (OID) to allow identification of the value set from which the value in CWE.1 is obtained.
	 * @param strValueSetVersionID This component carries the version for the value set identified by CWE.15. The version is a date. The date is the date/time that the value set being used was published.
	 * @param strAlternateCodingSystemOID This component contains the ISO Object Identifier (OID) for the coding system or value set named in CWE.6.
	 * @param strAlternateValueSetOID This component contains the ISO Object Identifier (OID) to allow identification of the value set from which the value in CWE.4 is obtained.
	 * @param strAlternateValueSetVersionID This component carries the version for the value set identified by CWE.18. The version is a date.
	 * @param strSecondAlternateCodingSystemOID This component contains the ISO Object Identifier (OID) for the coding system or value set named in CWE.12.
	 * @param strSecondAlternateValueSetOID This component contains the ISO Object Identifier (OID) to allow identification of the value set from which the value in CWE.10 is obtained.
	 * @param strSecondAlternateValueSetVersionID This component carries the version for the value set identified by CWE.21. The version is a date.
	 */
	public void setMFNRecordLevelErrorReturn  (String strIdentifier,String strText,String strNameOfCodingSystem,
			String strAlternateIdentifier,String strAlternateText,String strNameOfAlternateCodingSystem, String strCodingSystemVersionID, String 				strAlternateCodingSystemVersionId,
			String strOriginalText, String  strSecondAlternateIdentifier, String strSecondAlternateText, 
			String strNameofSecondAlternateCodingSystem, String strSecondAlternateCodingSystemVersionID, String strCodingSystemOID, String strValueSetOID,
			String strValueSetVersionID, String strAlternateCodingSystemOID, String strAlternateValueSetOID, String strAlternateValueSetVersionID,
			String  strSecondAlternateCodingSystemOID, String strSecondAlternateValueSetOID, String strSecondAlternateValueSetVersionID)
	{
		CWE cwe  = (CWE)getDataElement(669);
		cwe.setIdentifier(strIdentifier);
		cwe.setText(strText);
		cwe.setNameOfCodingSystem(strNameOfCodingSystem);
		cwe.setAlternateIdentifier(strAlternateIdentifier);
		cwe.setAlternateText(strAlternateText);
		cwe.setNameOfAlternateCodingSystem(strNameOfAlternateCodingSystem); 
		cwe.setCodingSystemVersionID(strCodingSystemVersionID);
		cwe.setAlternateCodingSystemVersionId(strAlternateCodingSystemVersionId);
		cwe.setOriginalText(strOriginalText);
		cwe.setSecondAlternateIdentifier(strSecondAlternateIdentifier);
		cwe.setSecondAlternateText(strSecondAlternateText);
		cwe.setNameofSecondAlternateCodingSystem(strNameofSecondAlternateCodingSystem);
		cwe.setSecondAlternateCodingSystemVersionID(strSecondAlternateCodingSystemVersionID);
		cwe.setCodingSystemOID(strCodingSystemOID);
		cwe.setValueSetOID(strValueSetOID);
		cwe.setValueSetVersionID(strValueSetVersionID);
		cwe.setAlternateCodingSystemOID(strAlternateCodingSystemOID);
		cwe.setAlternateValueSetOID(strAlternateValueSetOID);
		cwe.setAlternateValueSetVersionID(strAlternateValueSetVersionID);
		cwe.setSecondAlternateCodingSystemOID(strSecondAlternateCodingSystemOID);
		cwe.setSecondAlternateValueSetOID(strSecondAlternateValueSetOID);
		cwe.setSecondAlternateValueSetVersionID(strSecondAlternateValueSetVersionID); 
		setMFNRecordLevelErrorReturn(cwe);


	} 

	/** Set the MFN Record Level Error Return.
	 * This field contains the status of the requested update. Site-defined table, 
	 * specific to each master file being updated via this transaction.
	 * @param objmFNRecordLevelErrorReturn object of MFN Record Level Error Return.
	 */ 
	public void setMFNRecordLevelErrorReturn(CWE objmFNRecordLevelErrorReturn)
	{
		setDataType(669,objmFNRecordLevelErrorReturn);


	}

	/**
	 * Add the Primary Key Value MFA.
	 * This field uniquely identifies the record of the master file. 
	 * @param objprimaryKeyValueMFA Used as primaryKeyValueMFA.
	 */
	public void addprimaryKeyValueMFA(IDataType objprimaryKeyValueMFA)
	{
		addDataType(1308,objprimaryKeyValueMFA);
	}

	/**
	 * Set the Primary Key Value MFA.
	 * This field uniquely identifies the record of the master file. 
	 * @param objprimaryKeyValueMFAList List of Primary Key Value MFA.
	 */
	@SuppressWarnings("unchecked")
	public void setprimaryKeyValueMFA(ISingleCollection<IDataType> objprimaryKeyValueMFAList)
	{
		ISingleCollection<IDataType> objCollection = null;
		ISingleCollection<?> objUnknownCollection = (ISingleCollection<?>)objprimaryKeyValueMFAList;
		objCollection = (ISingleCollection<IDataType>)objUnknownCollection;
		setDataType(1308,objCollection);
	}

	/**
	 * Add the Primary Key Value Type MFA.
	 * This field contains the HL7 data type of MFA-5 - Primary Key Value - MFA.
	 * @param strCharacterSet Used as CharacterSet.
	 */ 
	public void addPrimaryKeyValueType (String strCharacterSet) 
	{
		ID tempPrimaryKeyValueTypeMFA  = (ID)getDataElement(1320);
		tempPrimaryKeyValueTypeMFA.setValue(strCharacterSet); 
		addPrimaryKeyValueType(tempPrimaryKeyValueTypeMFA);

	} 

	/** Add the Primary Key Value Type MFA.
	 * This field contains the HL7 data type of MFA-5 - Primary Key Value - MFA.
	 * @param objtempPrimaryKeyValueTypeMFA object of Primary Key Value Type MFA.
	 */ 
	public void addPrimaryKeyValueType(ID objtempPrimaryKeyValueTypeMFA)
	{
		addDataType(1320,objtempPrimaryKeyValueTypeMFA);

	} 

	/** Set the Primary Key Value Type MFA.
	 * This field contains the HL7 data type of MFA-5 - Primary Key Value - MFA.
	 * @param objtempPrimaryKeyValueTypeMFAList List of Primary Key Value Type MFA.
	 */ 
	@SuppressWarnings("unchecked")
	public void setPrimaryKeyValueType(ISingleCollection<ID> objtempPrimaryKeyValueTypeMFAList)
	{
		ISingleCollection<IDataType> objCollection = null;
		ISingleCollection<?> objUnknownCollection = (ISingleCollection<?>)objtempPrimaryKeyValueTypeMFAList;
		objCollection = (ISingleCollection<IDataType>)objUnknownCollection;
		setDataType(1320,objCollection);
	}


	/**
	 * Parses HL7 Segment Strings from any Stream into HL7 Segment object.
	 * This method checks for the Repetition of the fields in the Segment.
	 * It also checks for the optionality of the fields as whether they are mandatory or optional.
	 * Successful parsing of the segment populates the object with the data present on the stream and provides
	 * easy accessor and mutator methods to navigate the message.
	 * It also leads to failure if version of given HL7 Message is not 2.8.2.
	 * This method raises exception if there is Segment which is not valid as per HL7 v 2.8.2 standard.
	 * @param strHL7segmentString Object of HL7Stream.
	 * @param objIDelimiter Object of class Delimiter.
	 * @return int - Success if segment is valid.
	 * 			   - Fail if segment in not valid.
	 * @throws InvalidSegmentException Thrown when Segment Validation Fails. 
	 * @throws IOException Signals that an I/O exception of some sort has occurred.
	 */
	public int parse(String strSegmentStream, IDelimiter objIDelimiter)
			throws InvalidSegmentException, IOException 
			{
				int iRetVal = HL7Constants.HL7_FUNCTION_FAIL;
				DataElementFactory objDataElementFactory = DataElementFactory.createInstance();
				char cReadChar = '\0';
				int i=-1;
				IDataType objIDataType = null;
				try
				{
					//get field separator from IDelimiter
					char cFSeparator = objIDelimiter.getFieldSeparator();
					cReadChar = strSegmentStream.charAt(++i);

					if(cReadChar == cFSeparator)
					{
						String strEnumSegment = enumSegments.getValue();
						if(strEnumSegment.length() > 3)
						{
							strEnumSegment = strEnumSegment.substring(0, 3);
						}
						ISingleCollection<Integer> objItemIDList = objSegmentMap.getItemIDList();
						int[] iValueTable = null;
						String strDTName = null;
						int iMinLength = 0;
						int iMaxLength = 0;
						String strCLength = null;
						boolean isOptional;
						String strFieldName = null;
						for(Integer objItemID : objItemIDList)
						{
							strDTName = objSegmentMap.getDataTypeName(objItemID);
							iValueTable = objSegmentMap.getValueTable(objItemID);
							iMinLength = objSegmentMap.getItemMinimumLength(objItemID);
							iMaxLength = objSegmentMap.getItemMaximumLength(objItemID);
							strCLength = objSegmentMap.getItemConformanceLength(objItemID);
							strFieldName = objSegmentMap.getFieldName(objItemID);
							isOptional=objSegmentMap.isOptional(objItemID);
							do
							{
								String strField="";
								objIDataType = objDataElementFactory.getDataElement(iValueTable,iMinLength, iMaxLength,strCLength, strDTName,HL7Constants.HL7_COMPONENT);
								if(objIDataType == null)
								{
									// if Data Type is withdrawn then skip that value by reading stream till next delimiter
									cReadChar = strSegmentStream.charAt(++i);
									strField=""+cReadChar;
									while(cReadChar != cFSeparator && cReadChar != '\r')
									{
										cReadChar=strSegmentStream.charAt(++i);
										strField= strField+cReadChar;
									}
									if(strField!=null && strField.charAt(0) != '|')
										setUnRecognizedField(strEnumSegment, strFieldName, strField);
								}
								else
								{
									do
									{
										i++;
										strField=strField+strSegmentStream.charAt(i);
									}while(strSegmentStream.charAt(i) != '~' && strSegmentStream.charAt(i)!='|' && strSegmentStream.charAt(i)!='\r');
									iRetVal = objIDataType.read(strField, objIDelimiter);
			
									if(iRetVal == 0)
									{
										if(!isOptional)
										{
											setUnRecognizedField(strEnumSegment, strFieldName, strField);
										}
										objIDataType = null;
										cReadChar = '\0';
										cReadChar = strSegmentStream.charAt(i);
										break;
									}
									else if(iRetVal == HL7Constants.HL7_FUNCTION_FAIL)
									{
										objIDataType = null;
										setUnRecognizedField(strEnumSegment, strFieldName, strField);
									}
									else if(iRetVal == -1)  
									{
										//Avoids the reading of extra characters from stream when Components data type is withdrawn
										objIDataType = null;
										cReadChar = '\0';
										cReadChar= objIDelimiter.getFieldSeparator();
										break;
									}
									else if(iRetVal == HL7Constants.HL7_WITHDRAWN_FIELD)
									{
										setUnRecognizedField(strEnumSegment, strFieldName, strField);
									}
									else
									{
										objDataElementList.put(objItemID,objIDataType);
										objIDataType = null;
									}
									cReadChar = '\0';
									cReadChar = strSegmentStream.charAt(i);
								}
							}while(cReadChar == objIDelimiter.getRepetitionSeparator());

							if(cReadChar != cFSeparator)
								break;
						}
					}


					if(cReadChar == '\r')
					{
						/*
						 * Conversion code for PrimaryKeyValue-MFA according to the value specified in PrimaryKeyValueType-MFA
						 * In initial parsing this field has been  parsed as UN.
						 */
						ISingleCollection<ID> objTypeList = getPrimaryKeyValueTypeMFA();
						ISingleCollection<IDataType> objValueList = getPrimaryKeyValueMFA();
						if(objTypeList != null && objValueList != null && objTypeList.size() == objValueList.size())
						{
							int index = 0;
							ISingleCollection<IDataType> objPrimaryKeyValueList = new SingleCollection<IDataType>();
							int iSize = objTypeList.size();
							while(index < iSize)
							{
								ID objID = objTypeList.elementAt(index);
								String strDatatype = (String)objID.getValue();

								//Since Data Type is Varies
								IDataType objTargetDataType = DataElementFactory.createInstance().getDataElement(9999,0 ,250, "250#" ,strDatatype,HL7Constants.HL7_COMPONENT);
								if(objTargetDataType != null)
								{
									//Serializing UN value to stream
									IDataType objUN = objValueList.elementAt(index);
									ByteArrayOutputStream objByteArrayOutputStream = new ByteArrayOutputStream();
									
									HL7BufferStream objHL7BufferStream = new HL7BufferStream();
									objHL7BufferStream.setOutputStream(objByteArrayOutputStream);
									objUN.write(objHL7BufferStream,objIDelimiter);

									//converting value to specified Data type
									ByteArrayInputStream objByteArrayInputStream = new ByteArrayInputStream(objByteArrayOutputStream.toByteArray());
									objHL7BufferStream.setInputStream(objByteArrayInputStream);
									String strTemp = "";
									if(objHL7BufferStream!= null)
									{
										
										char readCh;
										do
										{
											readCh = objHL7BufferStream.readChar();
											strTemp=strTemp+readCh;
										}while(readCh != '\0');
									}
									objTargetDataType.read(strTemp,objIDelimiter);
									objPrimaryKeyValueList.add(objTargetDataType);
								}
								index++;
							}
							if(objPrimaryKeyValueList.size() == iSize)
							{
								/*
								 * If all occurrences has been modified only then attribute will be replaced.
								 */
								setDataType(1308,objPrimaryKeyValueList);
							}
						}
						return HL7Constants.HL7_FUNCTION_SUCCESS;
					}
					else
						return HL7Constants.HL7_INVALID_SEGMENT_TERMINATOR;

				}
				catch(InvalidDataTypeException ex)
				{
					throw new InvalidSegmentException(this.getClass().getSimpleName(), ex);
				}
				catch(FieldMissingException ex)
				{
					throw new InvalidSegmentException(this.getClass().getSimpleName(),ex);
				}
				catch(InvalidFieldException ex)
				{
					throw new InvalidSegmentException(this.getClass().getSimpleName(),ex);
				}
				catch(InvalidDelimiterException ex)
				{
					throw new InvalidSegmentException(this.getClass().getSimpleName(),ex);
				}
			}

	/**
	 * Validates HL7 Message objects .
	 * Validate method checks for validation each and every segments in side the Message object against specified message Structure. 
	 * Validation chcecks include optionality of segment or group.
	 * It also verifies the number of times segment or group is repeated in message.
	 * e.g 
	 * {PSH} while parsing PSH segment validate method will check for its mandatory presence.
	 * [PSH] in this case validate will throw exception if one tries to enter more than one PSH segment.
	 * @return boolean - true or false.
	 * @throws InvalidSegmentException Throws when Segment Validation fails 
	 */	
	@Override
	public boolean validate() throws InvalidSegmentException 
	{

		/*
		 * Record-Level Event Code,MFN Record Level Error Return,Primary Key Value - MFE,Primary Key Value Type are required fields.
		 */
		try 
		{
			//Condition for MFN Control ID not clear.
			/*
			 * MFN Control ID is conditional field. 
			 * Condition rule : It is only required if Response Level Code requires responses at the record level (any value other than NE). 
			 */
			super.validate();

			//validation for Primary Key Value - MFA and Primary Key Value Type - MFA

			ISingleCollection<ID> objTypeList = getPrimaryKeyValueTypeMFA();
			ISingleCollection<IDataType> objValueList = getPrimaryKeyValueMFA();
			if(objTypeList.size() != objValueList.size())
				throw new InvalidFieldException(ResourceBundleWrapper.getValue("exceptions", "InvalidField", new Locale(HL7Config.createInstance().getLocale())) + ":" + objSegmentMap.getFieldName(1308) + ":" + objSegmentMap.getFieldName(1320));

			return true;
		}
		catch(FieldMissingException ex)
		{
			throw new InvalidSegmentException(enumSegments.getValue(),ex);
		}
	}
}