/*******************************************************************************
 *  Copyright 2017-2018 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.dcm30_04.baselibs;

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

import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomFileHeader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomStream;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITransferSyntax;
import cdac.medinfo.sdk.dcm30_04.dicomstreams.DicomBufferStream;
import cdac.medinfo.sdk.dcm30_04.enums.EnumLoggingLevel;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidDataElementException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidHeaderException;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConfig;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConstants;
import cdac.medinfo.sdk.dcm30_04.utils.DicomLogger;

import cdac.medinfo.sdk.dcm30_04.utils.ICollectionIterator;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.PairedCollection;
import cdac.medinfo.sdk.dcm30_04.utils.ResourceBundleWrapper;


/* Registry of DICOM File Meta Elements
 * 
 * This section specifies the File Meta Elements needed to support the formatting of the File Meta
 * Information of the DICOM File Format (See PS 3.10). 

			    Tag			Name 										VR 								VM
			(0002,0000) 	Group Length 								UL 								1
			(0002,0001) 	File Meta Information Version 				OB 								1
			(0002,0002) 	Media Storage SOP Class UID 				UI								1
			(0002,0003) 	Media Storage SOP Instance UID 				UI 								1
			(0002,0010) 	Transfer Syntax UID 						UI								1
			(0002,0012) 	Implementation Class UID					UI								1
			(0002,0013) 	Implementation Version Name 				SH 								1
			(0002,0016) 	Source Application Entity Title 			AE 								1
			(0002,0100) 	Private Information Creator UID 			UI 								1
			(0002,0102) 	Private Information 						OB 								1
 */

/**
 * This class represents the part-10 compliant Dicom File.
 * It provides the functionality of populating itself from the byte buffer containing
 * header information
 * It also provides the functionality of serializing itself onto the stream  
 */
public class DicomFileHeader implements IDicomFileHeader  
{
	
	//This map holds the DataElements present in the header
	PairedCollection<ITag, IDataElement> objPairedCollection = null;

	private final int DEFAULT_HEADER_LENGTH = 28;
	private final String DEFAULT_TS = DicomConstants.TS_DEFAULT_IMPLICIT_VR_LITTLE_ENDIAN;
	byte[] preAmble = null;
	int iHeaderLength;

	/**
	 * Constructs DicomFileHeader by initializing headerlength to zero
	 */
	public DicomFileHeader()
	{
		objPairedCollection = new PairedCollection<ITag,IDataElement>();
		iHeaderLength = 0;
	}

	/**
	 * This method sets the 128 byte preamble in the dicom file header
	 * @param bytePreamble : 128 byte buffer containing preamble data
	 * @return : function status success/failure
	 */
	public void setPreAmble(byte[] bytePreamble)
	{
		if(bytePreamble.length > 128)
		{
			return ; //Throw exception or error code indicating that the preamble length should be exactly 128
		}
		preAmble = bytePreamble;
	}

	/**
	 * This method is used to get the preamble to be written before the header part
	 * @return byte array containing preamble value. 
	 */
	public byte[] getPreAmble()
	{
		return preAmble;
	}

	/**
	 * This method gets the byte buffer containing header part of a dicom file and
	 * populates itself with the DataElements present in the header 
	 * @param header byte array containing header value.
	 * @throws InvalidHeaderException if validation of header fails.
	 * @throws IOException if Input/Output operation fails.
	 */
	public void populate(byte[] header) throws InvalidHeaderException, IOException 
	{
		IDataElement current = null , prev = null;
		DicomBufferStream objDicomBufferStream = null;
		try
		{
			int prevGroupNumber,prevElementNumber;

			iHeaderLength = header.length;
			ITransferSyntax objITransferSyntax = new TransferSyntax(); 
			current = new ExplicitDE();

			ByteArrayInputStream objByteArrayInputStream = new ByteArrayInputStream(header);
			objDicomBufferStream  = new DicomBufferStream();
			objDicomBufferStream.setInputStream(objByteArrayInputStream);

			objITransferSyntax.setEndianNess(DicomConstants.DCM_ENDIANNESS_LITTLE_ENDIAN);
			objDicomBufferStream.setEndianNess(DicomConstants.DCM_ENDIANNESS_LITTLE_ENDIAN);
			objITransferSyntax.setVRTransferSyntax(DicomConstants.DCM_VR_EXPLICIT);

			while(true)
			{
				current.setTransferSyntax(objITransferSyntax);

				current.parse(objDicomBufferStream);
				if(prev != null)
				{
					prevGroupNumber = prev.getTag().getGroupNumber();
					prevElementNumber = prev.getTag().getElementNumber();
					if(prevGroupNumber > current.getTag().getGroupNumber())
						throw new InvalidHeaderException(ResourceBundleWrapper.getValue("exceptions","InvalidOrder",new Locale(DicomConfig.createInstance().getLocale())));
					if(prevGroupNumber  == current.getTag().getGroupNumber()
							&& prevElementNumber > current.getTag().getElementNumber())
						throw new InvalidHeaderException(ResourceBundleWrapper.getValue("exceptions","InvalidOrder",new Locale(DicomConfig.createInstance().getLocale())));
				}
				addDataElement(current);
				prev = current;	
				//This logic is implemented because the TransferSyntax needs to be changed 
				//only after complete header is read.
				if(objDicomBufferStream.available() == 0)
					break;
				current = new ExplicitDE();
			}
		}
		catch( InvalidDataElementException de)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(de.getMessage());
			}
			throw new InvalidHeaderException(de.getMessage(),de);
		}
		catch( InvalidHeaderException de)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(de.getMessage());
			}
			String strMessage = Integer.toHexString(current.getTag().getGroupNumber()) + "," + Integer.toHexString(current.getTag().getElementNumber());
			if(DicomConfig.createInstance().isLoggingOn()&&(DicomConfig.createInstance().getLoggingLevel() == EnumLoggingLevel.INFO))
			{
				DicomBufferStream objBuffStream = new DicomBufferStream();
				ByteArrayOutputStream objByteArrayOutputStream = new ByteArrayOutputStream();
				objBuffStream.setOutputStream(objByteArrayOutputStream);
				this.serialize(objBuffStream);
				String strLogMessage = objBuffStream.toString();
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(strLogMessage);
				objDicomLogger.log(de);
			}
			else if(DicomConfig.createInstance().isLoggingOn()&&(DicomConfig.createInstance().getLoggingLevel() == EnumLoggingLevel.SEVERE))
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();	
				objDicomLogger.log(de);
			}


				throw new InvalidHeaderException(strMessage, de);

		}
	}

	/**
	 * This method checks the UID for TransferSyntax and returns the appropriate TransferSyntax object
	 * @return objITransferSyntax - object populated with appropriate transfersyntax from header
	 */
	public ITransferSyntax getTransferSyntax()
	{
		ITag objMapKey = new Tag(0x0002,0x0010);
		IDataElement objIDataElement =  objPairedCollection.get(objMapKey);
		ITransferSyntax objITransferSyntax = new TransferSyntax();
		String strTransferSyntaxUID = (String)objIDataElement.getDicomValue().getValue();
		if(strTransferSyntaxUID.equalsIgnoreCase(DicomConstants.TS_LOSSY_JPEG_8_BIT) || strTransferSyntaxUID.equalsIgnoreCase(DicomConstants.TS_EXPLICIT_VR_LITTLE_ENDIAN))
		{
			objITransferSyntax.setVRTransferSyntax(DicomConstants.DCM_VR_EXPLICIT);
			objITransferSyntax.setEndianNess(DicomConstants.DCM_ENDIANNESS_LITTLE_ENDIAN);
		}
		else if(strTransferSyntaxUID.equalsIgnoreCase(DicomConstants.TS_DEFAULT_LOSSLESS_JPEG))
		{
			objITransferSyntax.setVRTransferSyntax(DicomConstants.DCM_VR_EXPLICIT);
			objITransferSyntax.setEndianNess(DicomConstants.DCM_ENDIANNESS_LITTLE_ENDIAN);
		}
		else if(strTransferSyntaxUID.equalsIgnoreCase(DicomConstants.TS_EXPLICIT_VR_BIG_ENDIAN))
		{
			objITransferSyntax.setVRTransferSyntax(DicomConstants.DCM_VR_EXPLICIT);
			objITransferSyntax.setEndianNess(DicomConstants.DCM_ENDIANNESS_BIG_ENDIAN);
		}
		else if(strTransferSyntaxUID.equalsIgnoreCase(DicomConstants.TS_DEFAULT_IMPLICIT_VR_LITTLE_ENDIAN))
		{
			objITransferSyntax.setVRTransferSyntax(DicomConstants.DCM_VR_IMPLICIT);
			objITransferSyntax.setEndianNess(DicomConstants.DCM_ENDIANNESS_LITTLE_ENDIAN);
		}
		/*
		 * For JPEG LOSSLESS PROCESS 14 Transfer Syntax the Default VR Transfer Sytnax is LittleEndianExplicit
		 */
		else if(strTransferSyntaxUID.equalsIgnoreCase(DicomConstants.TS_JPEG_LOSSLESS_NON_HIERARCHICAL_PROCESS_14))
		{
			objITransferSyntax.setVRTransferSyntax(DicomConstants.DCM_VR_EXPLICIT);
			objITransferSyntax.setEndianNess(DicomConstants.DCM_ENDIANNESS_LITTLE_ENDIAN);
		}
		objITransferSyntax.setTransferSyntax(strTransferSyntaxUID);
		return objITransferSyntax;
	}

	/**
	 * This method serializes the FileMetaElements which are populated in the DicomFileHeader
	 * @return byte[] - Byte array containing header value.
	 * @throws InvalidHeaderException if Header validation fails.
	 * @throws IOException if Input/Output operation fails.
	 */
	public byte[] getHeader() throws InvalidHeaderException, IOException
	{
		IDataElement objIDataElement = null;

		ByteArrayOutputStream objByteArrayOutputStream = new ByteArrayOutputStream(iHeaderLength);
		DicomBufferStream objDicomBufferStream  = new DicomBufferStream();
		objDicomBufferStream.setOutputStream(objByteArrayOutputStream);
		objDicomBufferStream.setEndianNess(DicomConstants.DCM_ENDIANNESS_LITTLE_ENDIAN);

		ICollectionIterator<IDataElement> objDicomFileHeaderIterator = iterator();
		while(objDicomFileHeaderIterator.hasNext())
		{
			objIDataElement =  objDicomFileHeaderIterator.next();
			objIDataElement.serialize(objDicomBufferStream);
		}
		byte[] header = objDicomBufferStream.toByteArray(); 
		return header;
	}

	/**
	 * Provides iterator over the collection of DataElements
	 * @return Iterator - custom iterator over the collection of DataElements
	 */
	public ICollectionIterator<IDataElement> iterator()
	{
		return objPairedCollection.sortedIterator();
	}

	/**
	 * This method retrieves the data for specified Tag.
	 * @param iGroupNumber integer value of group number.
	 * @param iElementNumber integer value of element number.
	 * @return IDataElement - instance of DataElement.
	 */
	public IDataElement getDataFromTag(int iGroupNumber,int iElementNumber)
	{
		ITag objITag = new Tag(iGroupNumber,iElementNumber);
		return objPairedCollection.get(objITag);
	}

	/**
	 * This method creates default header with MetaGroupLengthElement and TransferSyntaxUID
	 * @throws InvalidHeaderException if Header validation fails.
	 */
	public void createDefaultHeader() throws InvalidHeaderException
	{
		try
		{
			IDataElement objIDataElement = new ExplicitDE(0x0002, 0x0000, DicomConstants.DCM_DT_UL, DEFAULT_HEADER_LENGTH);
			ITag objITag = new Tag(0x0002,0x0000);
			objPairedCollection.put(objITag, objIDataElement);
			objIDataElement = new ExplicitDE(0x0002, 0x0010, DicomConstants.DCM_DT_UI, DEFAULT_TS);
			objITag = new Tag(0x0002, 0x0010);
			objPairedCollection.put(objITag, objIDataElement);
		}
		catch( InvalidDataElementException de)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(de.getMessage());
			}
			throw new InvalidHeaderException(de.getMessage(),de);
		}
	}

	/**
	 * This method serializes Dicom File Header onto the stream attached to the header 
	 * @param objIDicomStream Stream on which the DICOM data is available
	 * @return int - shows status as success or failure.
	 * @throws IOException If Input/Output operation fails.
	 */
	public int serialize(IDicomStream objIDicomStream) throws IOException
	{
		IDataElement objIDataElement = null;
		ITag objITag = new Tag(0x0002,0x0000);
		ICollectionIterator<IDataElement> objDicomFileHeaderIterator = null;

		int iValue = 0;

		objDicomFileHeaderIterator = iterator();

		/*
		 * This if loop is added to avoid first MetaGroupLengthDataElement in the calculation 
		 * of length of MetaGroupLengthDataElement. Because MetaGroupLengthDataElement represents
		 * the length of header next after its own DataElement
		 */
		while(objDicomFileHeaderIterator.hasNext())
		{
			objIDataElement = objDicomFileHeaderIterator.next();
			ITag objDummyTag = objIDataElement.getTag();
			if(!(objDummyTag.getGroupNumber() == 0x0002 && objDummyTag.getElementNumber() == 0x0000))
				iValue += objIDataElement.getDataElementLength();
		}

		objIDataElement = new ExplicitDE(0x0002,0x0000,DicomConstants.DCM_DT_UL,iValue);

		objDicomFileHeaderIterator = null;

		objPairedCollection.put(objITag, objIDataElement);

		objDicomFileHeaderIterator = iterator();
		while(objDicomFileHeaderIterator.hasNext())
		{
			objIDataElement = objDicomFileHeaderIterator.next();
			objIDataElement.serialize(objIDicomStream);
		}
		return 1;
	}

	/**
	 * This method sets the transfersyntax unique ID.
	 * @param strTransferSyntaxUID string value of transfersyntax.
	 * @return int shows status as success or failure.
	 */
	public void setTransferSyntaxUID(String strTransferSyntaxUID)
	{
		/*
		 *Accept the TransferSyntaxUID in String format of type UI.
		 *TransferSyntax will be Little Endian Explicit always for the header
		 */
		IDataElement objIDataElement = new ExplicitDE(0x0002, 0x0010,DicomConstants.DCM_DT_UI, strTransferSyntaxUID);
		addDataElement(objIDataElement);
	}

	/**
	 * This is the accessor method for TransferSyntax unique ID
	 * @return String - string value of transfersyntax unique ID
	 */
	public String getTransferSyntaxUID()
	{
		ITag objITag = new Tag(0x0002,0x0010);
		return objPairedCollection.get(objITag).getDicomValue().getValue().toString();
	}

	/**
	 * Adds DataElements in the Header.
	 * @param objIDataElement specifies the Data Element to be added.
	 * @throws InvalidHeaderException throws when the DataElement to be added does not obey increasing order 
	 * 									of the Header DataElements
	 * @return int - shows status as success or failure.
	 */
	public int addDataElement(IDataElement objIDataElement) throws InvalidHeaderException
	{
		objPairedCollection.put(objIDataElement.getTag(), objIDataElement);
		return 1;
	}

	/**
	 * This is a two byte field where each bit identifies a version of this File Meta Information header.
	 * @param objFileMetaInformationVersion - value of File Meta Information Version.
	 */
	public void setFileMetaInformationVersion(ISingleCollection<byte[]> objFileMetaInformationVersion)
	{
		IDataElement objIDataElement = new ExplicitDE(0x0002, 0x0001,DicomConstants.DCM_DT_OB, objFileMetaInformationVersion);
		addDataElement(objIDataElement);
	}

	/**
	 * Gets the File Meta Information Version.
	 * @return ISingleCollection<byte[]> - collection of byte array containing File Meta Information Version.
	 */
	@SuppressWarnings("unchecked")
	public ISingleCollection<byte[]> getFileMetaInformationVersion()
	{
		ITag objITag = new Tag(0x0002, 0x0001);
		IDataElement objIDataElement = objPairedCollection.get(objITag);
		if(objIDataElement != null)
		{
			if(objIDataElement.getValue() != null)
			{
				return (ISingleCollection<byte[]>)(objIDataElement.getValue());
			}
		}
		return null;
	}

	/**
	 * Sets the SOP Class associated with the Data Set.
	 * @param strMediaStorageSOPClassUID  String vlaue of Media Storage SOP Class UID
	 */
	public void setMediaStorageSOPClassUID(String strMediaStorageSOPClassUID)
	{
		IDataElement objIDataElement = new ExplicitDE(0x0002, 0x0002,DicomConstants.DCM_DT_UI, strMediaStorageSOPClassUID);
		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves the SOP Class associated with the Data Set.
	 * @return String - value of Media Storage SOP Class UID
	 */
	public String getMediaStorageSOPClassUID()
	{
		ITag objITag = new Tag(0x0002, 0x0002);
		IDataElement objIDataElement = objPairedCollection.get(objITag);
		if(objIDataElement != null)
		{
			if(objIDataElement.getValue() != null)
			{
				return (String)(objIDataElement.getValue());
			}
		}
		return null;
	}

	/**
	 * Sets the SOP Instance associated with the Data Set placed in the file and following the File Meta Information.
	 * @param strMediaStorageSOPInstanceUID String value of Media Storage SOP Instance UID
	 */
	public void setMediaStorageSOPInstanceUID(String strMediaStorageSOPInstanceUID)
	{
		IDataElement objIDataElement = new ExplicitDE(0x0002, 0x0003,DicomConstants.DCM_DT_UI, strMediaStorageSOPInstanceUID);
		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves the SOP Instance associated with the Data Set placed in the file and following the File Meta Information.
	 * @return String - String value of Media Storage SOP Instance UID. 
	 */
	public String getMediaStorageSOPInstanceUID()
	{
		ITag objITag = new Tag(0x0002, 0x0003);
		IDataElement objIDataElement = objPairedCollection.get(objITag);
		if(objIDataElement != null)
		{
			if(objIDataElement.getValue() != null)
			{
				return (String)(objIDataElement.getValue());
			}
		}
		return null;
	}

	/**
	 * Uniquely identifies the implementation which wrote this file and its content.
	 * @param strImplementationClassUID String value of Implementation Class UID.
	 */
	public void setImplementationClassUID(String strImplementationClassUID)
	{
		IDataElement objIDataElement = new ExplicitDE(0x0002, 0x0012,DicomConstants.DCM_DT_UI, strImplementationClassUID);
		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Implementation Class UID.
	 * @return String - String value of Implementation Class UID.
	 */
	public String getImplementationClassUID()
	{
		ITag objITag = new Tag(0x0002, 0x0012);
		IDataElement objIDataElement = objPairedCollection.get(objITag);
		if(objIDataElement != null)
		{
			if(objIDataElement.getValue() != null)
			{
				return (String)(objIDataElement.getValue());
			}
		}
		return null;
	}

	/**
	 * Sets a version for an Implementation Class UID using up to 16 characters of the repertoire.
	 * @param strImplementationVersionName String value of Implementation Version Name.
	 */
	public void setImplementationVersionName(String strImplementationVersionName)
	{
		IDataElement objIDataElement = new ExplicitDE(0x0002, 0x0013,DicomConstants.DCM_DT_SH, strImplementationVersionName);
		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves a version for an Implementation Class UID using up to 16 characters of the repertoire.
	 * @return String - String value of Implementation Version Name.
	 */
	public String getImplementationVersionName()
	{
		ITag objITag = new Tag(0x0002, 0x0013);
		IDataElement objIDataElement = objPairedCollection.get(objITag);
		if(objIDataElement != null)
		{
			if(objIDataElement.getValue() != null)
			{
				return (String)(objIDataElement.getValue());
			}
		}
		return null;
	}

	/**
	 * Sets the DICOM Application Entity (AE) Title of the AE which wrote this file's content.
	 * @param strSourceApplicationEntityTitle String value of Source Application Entity Title.
	 */
	public void setSourceApplicationEntityTitle(String strSourceApplicationEntityTitle)
	{
		IDataElement objIDataElement = new ExplicitDE(0x0002, 0x0016,DicomConstants.DCM_DT_AE, strSourceApplicationEntityTitle);
		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves The DICOM Application Entity (AE) Title of the AE which wrote this file's content.
	 * @return String - String value of Source Application Entity Title.
	 */
	public String getSourceApplicationEntityTitle()
	{
		ITag objITag = new Tag(0x0002, 0x0016);
		IDataElement objIDataElement = objPairedCollection.get(objITag);
		if(objIDataElement != null)
		{
			if(objIDataElement.getValue() != null)
			{
				return (String)(objIDataElement.getValue());
			}
		}
		return null;
	}

	/**
	 * This function sets the The UID of the creator of the private information
	 * @param strPrivateInformationCreatorUID String value of Private Information Creator UID.
	 */
	public void setPrivateInformationCreatorUID(String strPrivateInformationCreatorUID)
	{
		IDataElement objIDataElement = new ExplicitDE(0x0002, 0x0100,DicomConstants.DCM_DT_UI, strPrivateInformationCreatorUID);
		addDataElement(objIDataElement);
	}

	/**
	 * This function gets the The UID of the creator of the private information
	 * @return String - value of Private Information Creator UID.
	 */
	public String getPrivateInformationCreatorUID()
	{
		ITag objITag = new Tag(0x0002, 0x0100);
		IDataElement objIDataElement = objPairedCollection.get(objITag);
		if(objIDataElement != null)
		{
			if(objIDataElement.getValue() != null)
			{
				return (String)(objIDataElement.getValue());
			}
		}
		return null;
	}

	/**
	 * This function sets the Private Information placed in the File Meta Information.
	 * @param objPrivateInformation byte array collection containing Private Information placed in the File Meta Information.
	 */
	public void setPrivateInformation(ISingleCollection<byte[]> objPrivateInformation)
	{
		IDataElement objIDataElement = new ExplicitDE(0x0002, 0x0102,DicomConstants.DCM_DT_OB, objPrivateInformation);
		addDataElement(objIDataElement);
	}

	/**
	 * This function gets the Private Information placed in the File Meta Information.
	 * @return ISingleCollection<byte[]> - Collection of byte array containing Private Information.
	 */
	@SuppressWarnings("unchecked")
	public ISingleCollection<byte[]> getPrivateInformation()
	{
		ITag objITag = new Tag(0x0002, 0x0102);
		IDataElement objIDataElement = objPairedCollection.get(objITag);
		if(objIDataElement != null)
		{
			if(objIDataElement.getValue() != null)
			{
				return (ISingleCollection<byte[]>)(objIDataElement.getValue());
			}
		}
		return null;
	}

	/**
	 * This function gets the length of Dicom File Header.
	 * 
	 * @return
	 */
	public int getLength()
	{
		/*
		 * 128 bytes of preamble
		 * 4 bytes of DICM
		 * 12 bytes of data element 0x0002,0x0000. This data element is written at time of serialization
		 * thus its length should also be added.
		 */
		int iHeaderLength = 128 + 4+ 12;
		ICollectionIterator<IDataElement> objDataElementCollection = objPairedCollection.iterator();
		while(objDataElementCollection.hasNext())
		{
			iHeaderLength = iHeaderLength +objDataElementCollection.next().getDataElementLength();
		}
		return iHeaderLength;
	}
}
