/*******************************************************************************
 *  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.dicommodel.modules;



import cdac.medinfo.sdk.dcm30_04.baselibs.CommonCTOrMRImageDescriptionMacro;
import cdac.medinfo.sdk.dcm30_04.baselibs.DicomV3Factory;
import cdac.medinfo.sdk.dcm30_04.baselibs.IconImageSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.RTEquipmentCorrelationMacro;
import cdac.medinfo.sdk.dcm30_04.baselibs.ReferencedGrayscalePresentationStateSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.ReferencedImageEvidenceSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.ReferencedRawDataSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.ReferencedWaveformSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.SourceImageEvidenceSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.Tag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomValue;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.enums.EnumBitsAllocated;
import cdac.medinfo.sdk.dcm30_04.enums.EnumBitsStored;
import cdac.medinfo.sdk.dcm30_04.enums.EnumBurnedInAnnotation;
import cdac.medinfo.sdk.dcm30_04.enums.EnumContentQualification;
import cdac.medinfo.sdk.dcm30_04.enums.EnumHighBit;
import cdac.medinfo.sdk.dcm30_04.enums.EnumImageType;
import cdac.medinfo.sdk.dcm30_04.enums.EnumLossyImageCompression;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPhotometricInterpretation;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPresentationLUTShape;
import cdac.medinfo.sdk.dcm30_04.enums.EnumRecognizableVisualFeatures;
import cdac.medinfo.sdk.dcm30_04.enums.EnumSamplesPerPixel;

import cdac.medinfo.sdk.dcm30_04.exceptions.ConditionFailedException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidModuleException;
import cdac.medinfo.sdk.dcm30_04.exceptions.MandatoryMissingException;
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.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;

// TODO: Auto-generated Javadoc
/**
 \* This module specifies the attributes of the Enhanced CT Image Module.
 * 
 * 
 */

public class EnhancedCTImageModule extends Module  
{


	/**
	 * The obj single collection.
	 */
	public static ISingleCollection<ITag> objSingleCollection = null;

	/**
	 * The obj common ct or mr image description macro.
	 */
	CommonCTOrMRImageDescriptionMacro objCommonCTOrMRImageDescriptionMacro = null;

	/**
	 * The obj RT Equipment Correlation Macro.
	 */
	RTEquipmentCorrelationMacro objRTEquipmentCorrelationMacro = null;
	
	/**
	 * Instantiates a new enhanced ct image module.
	 * 
	 * @param objIDataSet the obj i data set
	 */
	public EnhancedCTImageModule(IDataSet objIDataSet)
	{
		super(objIDataSet);
	}

	static
	{
		objSingleCollection = new SingleCollection<ITag>();
		objSingleCollection.add(new Tag(0x0008,0x0008));
		objSingleCollection.add(new Tag(0x0008,0x002A));
		objSingleCollection.add(new Tag(0x0008,0x113A));
		objSingleCollection.add(new Tag(0x0008,0x9092));
		objSingleCollection.add(new Tag(0x0008,0x9121));
		objSingleCollection.add(new Tag(0x0008,0x9154));
		objSingleCollection.add(new Tag(0x0008,0x9237));
		objSingleCollection.add(new Tag(0x0018,0x9004));
		objSingleCollection.add(new Tag(0x0018,0x9073));
		objSingleCollection.add(new Tag(0x0020,0x0012));
		objSingleCollection.add(new Tag(0x0020,0x4000));
		objSingleCollection.add(new Tag(0x0028,0x0002));
		objSingleCollection.add(new Tag(0x0028,0x0004));
		objSingleCollection.add(new Tag(0x0028,0x0100));
		objSingleCollection.add(new Tag(0x0028,0x0101));
		objSingleCollection.add(new Tag(0x0028,0x0102));
		objSingleCollection.add(new Tag(0x0028,0x2110));
		objSingleCollection.add(new Tag(0x0028,0x2112));
		objSingleCollection.add(new Tag(0x0088,0x0200));
		objSingleCollection.add(new Tag(0x0028,0x0301));
		objSingleCollection.add(new Tag(0x0028,0x0302));
		objSingleCollection.add(new Tag(0x2050,0x0020));
		objSingleCollection.add(new Tag(0x300A,0x012C));
	}

	/**
	 * This method validates each Attribute in the Module according to the Type
	 * of the Attribute.Attributes are of 5 types.
	 * Type 1,Type 2 are Mandatory:
	 * Mandatory Attributes have to present in the Module.
	 * Type 1C,2C are Conditional:
	 * Conditional Attributes' presence depend on a condition.
	 * If the condition is satisfied the Attribute has to be present.
	 * Type 3 are Optional
	 * Optional Attributes can be added as and when required.
	 * 
	 * @return Boolean - status indicating success or failure
	 * 
	 * @throws InvalidModuleException - Throws when validation for any Module.
	 */
	public  boolean validateModule() throws InvalidModuleException
	{

		try
		{			if(!isPresent(0x0008, 0x0008))
			throw new MandatoryMissingException("Missing Mandatory Element 0008,0008");
		if(!isPresent(0x0028, 0x0002))
			throw new MandatoryMissingException("Missing Mandatory Element 0028,0002");
		if(!isPresent(0x0028, 0x0004))
			throw new MandatoryMissingException("Missing Mandatory Element 0028,004");
		if(!isPresent(0x0028, 0x0100))
			throw new MandatoryMissingException("Missing Mandatory Element 0028,0100");
		if(!isPresent(0x0028, 0x0101))
			throw new MandatoryMissingException("Missing Mandatory Element 0028,0101");
		if(!isPresent(0x0028, 0x0102))
			throw new MandatoryMissingException("Missing Mandatory Element 0028,0102");
		if(!isPresent(0x0018, 0x9004))
			throw new MandatoryMissingException("Missing Mandatory Element 0018,9004");
		if(!isPresent(0x0028, 0x2110))
			throw new MandatoryMissingException("Missing Mandatory Element 0028,2110");

		String[] arrStrImageType = getImageType();
		if((arrStrImageType[0].equalsIgnoreCase(EnumImageType.Value1.ORIGINAL.getValue())||arrStrImageType[0].equalsIgnoreCase(EnumImageType.Value1.MIXED.getValue()))&&(!isPresent(0x0008, 0x002A)))
			throw new ConditionFailedException("If Image Type(0008,0008)is ORIGINAL or MIXED , 0008,002A is required ");
		if((arrStrImageType[0].equalsIgnoreCase(EnumImageType.Value1.ORIGINAL.getValue())||arrStrImageType[0].equalsIgnoreCase(EnumImageType.Value1.MIXED.getValue())) && (!isPresent(0x0018, 0x9073)))
			throw new ConditionFailedException("If Image Type(0008,0008) is  ORIGINAL or MIXED , 0018,9073 is required");
		if(isPresent(0x0008, 0x1140) && !isPresent(0x0008, 0x9092))
			throw new ConditionFailedException("If Referenced Image Sequence(0008,1140) is present, 0008,9092 is required");
		if(isPresent(0x0008, 0x2112) && !isPresent(0x0008,0x9154))
			throw new ConditionFailedException("If Source Image Sequence(0008,2112) is present, 0008,9154 is required");

		/*
		 * Referenced Grayscale Presentation State Sequence 0008,9237.
		 * Condition not clear.
		 * plz refer p.d.f Chapter 3 page no 640
		 */

		String strLossyImageCompression = getLossyImageCompression();
		if((strLossyImageCompression.equalsIgnoreCase(EnumLossyImageCompression.LOSSY_COMPRESSED.getValue()))&&(!(isPresent(0x0028, 0x2112))))
			throw new ConditionFailedException("If Lossy Image Compression(0028,2110) is 01 or 1 , then 0028,2112 is required");

		}catch(MandatoryMissingException mme)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(mme.getMessage());

			
				throw new InvalidModuleException(this.getClass().getSimpleName(),mme);

		}
		catch(ConditionFailedException cfe)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(cfe.getMessage());

			
				throw new InvalidModuleException(this.getClass().getSimpleName(),cfe);

		}
		return true;
	}

	/**
	 * Sets Image identification characteristics.
	 * 
	 * @param arrStrImageType - String array of Image identification characteristics.
	 */	
	public void setImageType(String[] arrStrImageType)
	{
		/*Accept Image identification characteristics in String Array format of type CS.
		 * Read the Transfer Syntax and check to create ImplicitDE or ExplicitDE .
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Hash Map
		 */
		addDataElement(0x0008, 0x0008, DicomConstants.DCM_DT_CS, arrStrImageType);
	}

	/**
	 * Return Image Type.
	 * 
	 * @return String[]- String array of Image identification characteristics.
	 */
	public String[] getImageType()
	{
		if (objIDataSet == null)
			return null;
		IDataElement objIDataElement =  objIDataSet.getDataForTag(0x0008, 0x0008);
		if(objIDataElement == null)
			return null;
		IDicomValue objIDicomValue = objIDataElement.getDicomValue();
		if(objIDicomValue == null)
			return null;
		if(objIDicomValue.getValue()==null)
			return null;
		return (String[])objIDicomValue.getValue();
	}

	/**
	 * Sets a number identifying the single continuous gathering of data over a period of time which resulted in this image.
	 * 
	 * @param strAcquisitionNumber - String value of Acquisition Number.
	 */
	public void setAcquisitionNumber(String strAcquisitionNumber)
	{
		/*Accept number identifying the single continuous gathering of data
		 * in String format of type IS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Hash Map
		 */
		addDataElement(0x0020, 0x0012, DicomConstants.DCM_DT_IS, strAcquisitionNumber);
	}

	/**
	 * Return the String value of the attribute Acquisition Number.
	 * 
	 * @return String - returns the Acquisition Number
	 */
	public String getAcquisitionNumber()
	{
		Object objectValue = getValue(0x0020, 0x0012);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * The method is used to set The Date and Time the acquisition of data that resulted in this image started
	 * The function accepts a String Value and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module HashMap
	 * 
	 * @param strAcquisitionDatetime - String value of Acquisition Date and Time
	 */
	public void setAcquisitionDatetime(String strAcquisitionDatetime)
	{
		/*Accept The Date and Time the acquisition of data that resulted in this image started in String format of type TM.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Hash Map
		 */
		addDataElement(0x0008, 0x002A, DicomConstants.DCM_DT_DT, strAcquisitionDatetime);
	}

	/**
	 * Retrieves the Date and Time of Acquisition.
	 * 
	 * @return String - returns the Date and Time of Acquisition
	 */
	public String getAcquisitionDatetime()
	{
		 Object objValue = getValue(0x0008,0x002A);
   if(objValue!=null)
      return objValue.toString();
   return null;

	}

	/**
	 * Sets the time in seconds needed to run the prescribed pulse sequence.
	 * 
	 * @param dAcquisitionDuration - double value of Acquisition Duration.
	 */
	public void setAcquisitionDuration(double dAcquisitionDuration)
	{
		/* Accept Acquisition Duration in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Hash Map
		 */
		addDataElement(0x0018, 0x9073, DicomConstants.DCM_DT_FD, dAcquisitionDuration);
	}

	/**
	 * Retrieves the time in seconds needed to run the prescribed pulse sequence.
	 * 
	 * @return double - double value of Acquisition Duration.
	 */
	public double getAcquisitionDuration()
	{Object objectValue = getValue(0x0018, 0x9073);
		if(objectValue!=null)
			return Double.parseDouble(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Retrieves a sequence that identifies the set of Raw Data SOP Class/Instance pairs of the Raw
	 * data which were used to derive this Image.
	 * 
	 * @return ReferencedRawDataSequence - instance of {@link ReferencedRawDataSequence}.
	 */
	public ReferencedRawDataSequence getReferencedRawDataSequence()
	{
		ReferencedRawDataSequence objReferencedRawDataSequence = (ReferencedRawDataSequence)getDicomValue(0x0008,0x9121);
		if(objReferencedRawDataSequence == null)
		{
			/*
			 * If the sequence object is not present in the DataSet, a new sequence object is created and
			 * the TransferSyntax and DictionaryReader is set into it as it is set in the Module. This ensures that 
			 * the DataElements getting added in the DataSet follow the same TransferSyntax and use the same
			 * DictionaryReader object as that of the module.
			 */
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			objReferencedRawDataSequence = (ReferencedRawDataSequence)objDicomV3Factory.createSequence(0x0008,0x9121, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0008,0x9121, DicomConstants.DCM_DT_SQ, objReferencedRawDataSequence.getValue());
		}
		return objReferencedRawDataSequence;
	}

	/**
	 * Retrieves a sequence of waveforms acquired in conjunction with this image. These
	 * Waveforms may or may not be temporally synchronized with this image.
	 * 
	 * @return ReferencedWaveformSequence - instance of {@link ReferencedWaveformSequence}.
	 */
	public ReferencedWaveformSequence getReferencedWaveformSequence()
	{
		ReferencedWaveformSequence objReferencedWaveformSequence = (ReferencedWaveformSequence)getDicomValue(0x0008,0x113A);
		if(objReferencedWaveformSequence == null)
		{
			/*
			 * If the sequence object is not present in the DataSet, a new sequence object is created and
			 * the TransferSyntax and DictionaryReader is set into it as it is set in the Module. This ensures that 
			 * the DataElements getting added in the DataSet follow the same TransferSyntax and use the same
			 * DictionaryReader object as that of the module.
			 */
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			objReferencedWaveformSequence = (ReferencedWaveformSequence)objDicomV3Factory.createSequence(0x0008,0x113A, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0008,0x113A, DicomConstants.DCM_DT_SQ, objReferencedWaveformSequence.getValue());
		}
		return objReferencedWaveformSequence;
	}

	/**
	 * Retrieves full set of Composite SOP Instances referred to inside the Referenced Image
	 * Sequences of this Enhanced MR Image SOP Instance.
	 * 
	 * @return ReferencedImageEvidenceSequence - instance of {@link ReferencedImageEvidenceSequence}.
	 */
	public ReferencedImageEvidenceSequence getReferencedImageEvidenceSequence()
	{
		ReferencedImageEvidenceSequence objReferencedImageEvidenceSequence = (ReferencedImageEvidenceSequence)getDicomValue(0x0008,0x9092);
		if(objReferencedImageEvidenceSequence == null)
		{
			/*
			 * If the sequence object is not present in the DataSet, a new sequence object is created and
			 * the TransferSyntax and DictionaryReader is set into it as it is set in the Module. This ensures that 
			 * the DataElements getting added in the DataSet follow the same TransferSyntax and use the same
			 * DictionaryReader object as that of the module.
			 */
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			objReferencedImageEvidenceSequence = (ReferencedImageEvidenceSequence)objDicomV3Factory.createSequence(0x0008,0x9092, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0008,0x9092, DicomConstants.DCM_DT_SQ, objReferencedImageEvidenceSequence.getValue());
		}
		return objReferencedImageEvidenceSequence;
	}

	/**
	 * Retrieves full set of Composite SOP Instances used as source image SOP Instances inside the
	 * frames of this Enhanced CT Image SOP Instance.
	 * 
	 * @return SourceImageEvidenceSequence - instance of {@link SourceImageEvidenceSequence}.
	 */
	public SourceImageEvidenceSequence getSourceImageEvidenceSequence()
	{
		SourceImageEvidenceSequence objSourceImageEvidenceSequence = (SourceImageEvidenceSequence)getDicomValue(0x0008,0x9154);
		if(objSourceImageEvidenceSequence == null)
		{
			/*
			 * If the sequence object is not present in the DataSet, a new sequence object is created and
			 * the TransferSyntax and DictionaryReader is set into it as it is set in the Module. This ensures that 
			 * the DataElements getting added in the DataSet follow the same TransferSyntax and use the same
			 * DictionaryReader object as that of the module.
			 */
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			objSourceImageEvidenceSequence = (SourceImageEvidenceSequence)objDicomV3Factory.createSequence(0x0008,0x9154, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0008,0x9154, DicomConstants.DCM_DT_SQ, objSourceImageEvidenceSequence.getValue());
		}
		return objSourceImageEvidenceSequence;
	}

	/**
	 * Retrieves References to Grayscale Presentation State instances acquired in conjunction
	 * with this instance.
	 * 
	 * @return ReferencedGrayscalePresentationStateSequence - instance of {@link ReferencedGrayscalePresentationStateSequence}.
	 */
	public ReferencedGrayscalePresentationStateSequence getReferencedGrayscalePresentationStateSequence()
	{
		ReferencedGrayscalePresentationStateSequence objReferencedGrayscalePresentationStateSequence = (ReferencedGrayscalePresentationStateSequence)getDicomValue(0x0008,0x9237);
		if(objReferencedGrayscalePresentationStateSequence == null)
		{
			/*
			 * If the sequence object is not present in the DataSet, a new sequence object is created and
			 * the TransferSyntax and DictionaryReader is set into it as it is set in the Module. This ensures that 
			 * the DataElements getting added in the DataSet follow the same TransferSyntax and use the same
			 * DictionaryReader object as that of the module.
			 */
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			objReferencedGrayscalePresentationStateSequence = (ReferencedGrayscalePresentationStateSequence)objDicomV3Factory.createSequence(0x0008,0x9237, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0008,0x9237, DicomConstants.DCM_DT_SQ, objReferencedGrayscalePresentationStateSequence.getValue());
		}
		return objReferencedGrayscalePresentationStateSequence;
	}

	/**
	 * Sets Samples per Pixel (0028,0002) is the number of separate planes in the image. One, three, and
	 * four image planes are defined. For monochrome (gray scale) and palette color images, the number of planes is 1. For RGB and
	 * other three vector color models, the value of this attribute is 3. For four vector color models, the
	 * value of this attribute is 4.
	 * 
	 * @param enumSamplesPerPixel - specifies the samples per pixel in the image
	 */
	public void setSamplesPerPixel(EnumSamplesPerPixel enumSamplesPerPixel)
	{
		/*Accept Number of samples (planes) in this image in short format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0028, 0x0002, DicomConstants.DCM_DT_US, enumSamplesPerPixel.getValue());
	}

	/**
	 * Retrieves the samples per pixel.
	 * 
	 * @return Short - returns the samples per pixel
	 */
	public short getSamplesPerPixel()
	{
		Object objectValue = getValue(0x0028, 0x0002);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets Specifies the intended interpretation of the pixel data.
	 * 
	 * @param enumPhotometricInterpretation - Enum value Photometric Interpretation
	 */
	public void setPhotometricInterpretation(EnumPhotometricInterpretation enumPhotometricInterpretation)
	{
		/*Accept Specifies the intended interpretation of the pixel data in String format of type ST.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0028, 0x0004, DicomConstants.DCM_DT_CS, enumPhotometricInterpretation.getValue());
	}

	/**
	 * Retrieves the photometric interpretation.
	 * 
	 * @return String - returns the photometric interpretation
	 */
	public String getPhotometricInterpretation()
	{
		Object objectValue = getValue(0x0028, 0x0004);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Sets Number of bits allocated for each pixel sample. Each sample shall have the same
	 * number of bits allocated.
	 * 
	 * @param enumBitsAllocated - specifies the number of bits allocated
	 */
	public void setBitsAllocated(EnumBitsAllocated enumBitsAllocated)
	{
		/*Accept bits allocated for each pixel in this image in short format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0028, 0x0100, DicomConstants.DCM_DT_US, enumBitsAllocated.getValue());
	}

	/**
	 * Retrieves the number of bits allocated.
	 * 
	 * @return Short - returns the number of bits allocated
	 */
	public short getBitsAllocated()
	{
		Object objectValue = getValue(0x0028, 0x0100);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets Number of bits stored for each pixel sample. Each sample shall have the same
	 * number of bits stored.
	 * 
	 * @param enumBitsStored - specifies the number of bits stored
	 */
	public void setBitsStored(EnumBitsStored enumBitsStored)
	{
		/*Accept bits stored for each pixel in this image in short format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0028, 0x0101, DicomConstants.DCM_DT_US, enumBitsStored.getValue());
	}

	/**
	 * Retrieves the number of bits stored.
	 * 
	 * @return Short - returns the number of bits stored
	 */
	public short getBitsStored()
	{
		Object objectValue = getValue(0x0028, 0x0101);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}


	/**
	 * Sets Most significant bit for pixel sample data. Each sample shall have the same high bit.
	 * 
	 * @param enumHighBit - specifies the high bit
	 */
	public void setHighBit(EnumHighBit enumHighBit)
	{
		/*Accept Most significant bit for pixel in this image in short format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0028, 0x0102, DicomConstants.DCM_DT_US, enumHighBit.getValue());
	}

	/**
	 * Retrieves the high bit.
	 * 
	 * @return Short - returns the high bit
	 */
	public short getHighBit()
	{
		Object objectValue = getValue(0x0028, 0x0102);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets Content Qualification Indicator.
	 * Enumerated Values:
	 * 1) PRODUCT.
	 * 2) RESEARCH.
	 * 3) SERVICE.
	 * 
	 * @param enumContentQualification - Enum value of Content Qualification.
	 * 
	 * @return the int
	 */
	public void setContentQualification(EnumContentQualification enumContentQualification)
	{
		/*Accept the Content Qualification in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0018, 0x9004, DicomConstants.DCM_DT_CS, enumContentQualification.getValue());
	}

	/**
	 * Retrieves Content Qualification Indicator.
	 * 
	 * @return String - String value of Content Qualification.
	 */
	public String getContentQualification()
	{
		Object objectValue = getValue(0x0018, 0x9004);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Sets User-defined comments about the image.
	 * 
	 * @param strImageComments - String value of Image Comments.
	 * 
	 * @return the int
	 */
	public void setImageComments(String strImageComments)
	{
		/*Accept the Image Comments in String format of type LT.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0020, 0x4000, DicomConstants.DCM_DT_LT, strImageComments);
	}

	/**
	 * Retrieves User-defined comments about the image.
	 * 
	 * @return String - String value of Image Comments.
	 */
	public String getImageComments()
	{
		Object objectValue = getValue(0x0020, 0x4000);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}
	
	/**
	 * Sets value that indicates whether or not image contains sufficient burned in annotation to identify the
	 * patient and date the image was acquired.
	 * Enumerated Values:
	 * YES
	 * NO
	 * 
	 * @param enumBurnedInAnnotation the enum burned in annotation
	 */
	public void setBurnedInAnnotation(EnumBurnedInAnnotation enumBurnedInAnnotation)
	{
		/*Accept Indicates whether or not image contains 
		 * sufficient burned in annotation to identify the patient and date the image was acquired 
		 * in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Hash Map
		 */
		addDataElement(0x0028, 0x0301, DicomConstants.DCM_DT_CS, enumBurnedInAnnotation.getValue());
	}

	/**
	 * Retrieves value that indicates whether or not image contains sufficient burned in annotation to identify the
	 * patient and date the image was acquired.
	 * 
	 * @return - String value of Burned In Annotation(Yes or No)
	 */
	public String getBurnedInAnnotation()
	{Object objectValue = getValue(0x0028,0x0301);
	if(objectValue!=null)
		return objectValue.toString();
	return null;
	}
	
	/**
	 * Sets Recognizable Visual Features.
	 * Indicates whether or not the image contains sufficiently recognizable visual features 
	 * to allow the image or a reconstruction from a set of images to identify the patient.
	 * Enumerated Values:
	 * 1) YES 
	 * 2) NO
	 * 
	 * @param enumRecognizableVisualFeatures the enum Recognizable Visual Features
	 */
	public void setRecognizableVisualFeatures(EnumRecognizableVisualFeatures  enumRecognizableVisualFeatures)
	{
		/* Accept Recognizable Visual Features in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0028, 0x0302, DicomConstants.DCM_DT_CS, enumRecognizableVisualFeatures.getValue());
	}

	/**
	 * Retrieves Recognizable Visual Features.
	 * 
	 * @return String - String value of Recognizable Visual Features.
	 */ 
	public String getRecognizableVisualFeatures()
	{
		Object objValue = getValue(0x0028,0x0302);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets a value that specifies whether an Image has undergone lossy compression.
	 * Enumerated Values:
	 * 00 = Image has NOT been subjected to lossy compression,
	 * 01 = Image has been subjected to lossy compression.
	 * 
	 * @param enumLossyImageCompression the enum lossy image compression
	 */
	public void setLossyImageCompression(EnumLossyImageCompression enumLossyImageCompression)
	{
		/*Accept Specifies whether an Image has undergone lossy compression.
		 * in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Hash Map
		 */
		addDataElement(0x0028, 0x2110, DicomConstants.DCM_DT_CS, enumLossyImageCompression.getValue());
	}

	/**
	 * Retrieves the Lossy Image Compression.
	 * 
	 * @return String - returns the Lossy Image Compression
	 */
	public String getLossyImageCompression()
	{
		Object objectValue = getValue(0x0028, 0x2110);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Sets the approximate lossy compression ratio(s) that have been applied to this image.
	 * 
	 * @param arrStrLossyImageCompressionRatio - String array of Lossy Image Compression Ratio
	 */
	public void setLossyImageCompressionRatio(String[] arrStrLossyImageCompressionRatio)
	{
		/*Accept the approximate lossy compression ratio(s) that have been applied to this image.
		 * in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Hash Map
		 */
		addDataElement(0x0028, 0x2112, DicomConstants.DCM_DT_DS, arrStrLossyImageCompressionRatio);
	}

	/**
	 * Retrieves the Lossy Image Compression.
	 * 
	 * @return String[] - returns the Lossy Image Compression
	 */
	public String[] getLossyImageCompressionRatio()
	{
		 Object objValue = getValue(0x0028,0x2112);
   if(objValue!=null)
      return (String[])objValue;
   return null;

	}

	/**
	 * Sets a subset of a conceptual Presentation LUT.
	 * Enumerated Values:
	 * IDENTITY - output is in P-Values.
	 * 
	 * @param enumPresentationLUTShape the enum presentation lut shape
	 */
	public void setPresentationLUTShape(EnumPresentationLUTShape enumPresentationLUTShape)
	{
		/* Accept Presentation LUT Shape in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Hash Map
		 */
		addDataElement(0x2050,0x0020, DicomConstants.DCM_DT_CS, enumPresentationLUTShape.getValue());
	}

	/**
	 * Retrieves a subset of a conceptual Presentation LUT.
	 * 
	 * @return - String value of Presentation LUT Shape
	 */
	public String getPresentationLUTShape()
	{Object objectValue = getValue(0x2050,0x0020);
	if(objectValue!=null)
		return objectValue.toString();
	return null;
	}
	
	/**
	 * Returns provides the pre-initialized object of Icon Image Sequence.
	 * If the module contains the sequence object it returns the same otherwise it creates the
	 * sequence adds to the module with proper initialization and then returns the object of sequence.
	 * 
	 * @return IconImageSequence - instance of the icom image sequence.
	 */
	public IconImageSequence getIconImageSequence()
	{
		IconImageSequence objIconImageSequence = (IconImageSequence)getDicomValue(0x0088, 0x0200);
		if(objIconImageSequence == null)
		{
			/*
			 * If the sequence object is not present in the DataSet, a new sequence object is created and
			 * the TransferSyntax and DictionaryReader is set into it as it is set in the Module. This ensures that 
			 * the DataElements getting added in the DataSet follow the same TransferSyntax and use the same
			 * DictionaryReader object as that of the module.
			 */
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			objIconImageSequence = (IconImageSequence)objDicomV3Factory.createSequence(0x0088, 0x0200, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0088, 0x0200, DicomConstants.DCM_DT_SQ, objIconImageSequence.getValue());
		}
		return objIconImageSequence;
	}
	
	/**
	 * Sets Isocenter Position
	 * @param strIsocenterPositionString value of Isocenter Position.
	 */
	public void setIsocenterPosition(String[] strIsocenterPositionString)
	{
		/*Accept the IsocenterPosition in String format of type DS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */

		addDataElement(0x300A,0x012C, DicomConstants.DCM_DT_DS,strIsocenterPositionString);
	}
	/**
	 * Retrieves Isocenter Position.
	 * @return String - value of Isocenter Position.
	 */
	public String[] getIsocenterPosition()
	{
		Object objValue = getValue(0x300A,0x012C);
		if(objValue != null)
			return (String[])objValue;
		return null;
	}

	/**
	 * This method returns the vector of keys representing the DataElements
	 * that belong to this module.
	 * 
	 * @return ISingleCollection - the customized collection containing the dataelement tags
	 * that beling to this module
	 */
	public ISingleCollection<ITag> getVectorOfKeys()
	{
		return objSingleCollection;
	}

	/**
	 * Retrieves pre-initialized instance of CommonCTOrMRImageDescriptionMacro.
	 * 
	 * @return CommonCTOrMRImageDescriptionMacro - instance of {@link CommonCTOrMRImageDescriptionMacro}.
	 */
	public CommonCTOrMRImageDescriptionMacro getCommonCTOrMRImageDescriptionMacro()
	{

		if(objCommonCTOrMRImageDescriptionMacro == null)
		{
			objCommonCTOrMRImageDescriptionMacro = new CommonCTOrMRImageDescriptionMacro(objIDataSet,objIDictionaryReader);
		}
		return objCommonCTOrMRImageDescriptionMacro;
	}
	
	/**
	 * Retrieves pre-initialized instance of RTEquipmentCorrelationMacro.
	 * 
	 * @return RTEquipmentCorrelationMacro - instance of {@link RTEquipmentCorrelationMacro}.
	 */
	public RTEquipmentCorrelationMacro getRTEquipmentCorrelationMacro()
	{

		if(objRTEquipmentCorrelationMacro == null)
		{
			objRTEquipmentCorrelationMacro = new RTEquipmentCorrelationMacro(objIDataSet,objIDictionaryReader);
		}
		return objRTEquipmentCorrelationMacro;
	}
}
