/*******************************************************************************
 *  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.DicomV3Factory;
import cdac.medinfo.sdk.dcm30_04.baselibs.EnergyWindowRangeSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.Tag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.enums.EnumAcquisitionStartCondition;
import cdac.medinfo.sdk.dcm30_04.enums.EnumAcquisitionTerminationCondition;
import cdac.medinfo.sdk.dcm30_04.enums.EnumCollimatorType;
import cdac.medinfo.sdk.dcm30_04.enums.EnumImageType;
import cdac.medinfo.sdk.dcm30_04.enums.EnumTableMotion;

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;
import cdac.medinfo.sdk.dcm30_04.baselibs.MandatoryViewandSliceProgressionDirectionMacro;
import cdac.medinfo.sdk.dcm30_04.enums.EnumTimeOfFlightInformationUsed;
import cdac.medinfo.sdk.dcm30_04.enums.EnumDetectorGeometry;

/**
\* This module is used for Enhanced PET Acquisition Module.
*/
public class EnhancedPETAcquisitionModule extends Module
{
	/**
	 * The obj single collection.
	 */
	public static ISingleCollection<ITag> objSingleCollection = null;


	/**
	 * Creates EnhancedPETAcquisitionModule with default initialization.
	 * 
	 * @param objIDataSet the obj i data set
	 */
	MandatoryViewandSliceProgressionDirectionMacro objMandatoryViewandSliceProgressionDirectionMacro=null;
	public EnhancedPETAcquisitionModule(IDataSet objIDataSet)
	{
		super(objIDataSet);
	}

	static
	{
		objSingleCollection = new SingleCollection<ITag>();
		objSingleCollection.add(new Tag(0x0018, 0x0073));
		objSingleCollection.add(new Tag(0x0018,0x9715));
		objSingleCollection.add(new Tag(0x0018,0x9716));
		objSingleCollection.add(new Tag(0x0018,0x9717));
		
		objSingleCollection.add(new Tag(0x0018,0x9718));
		objSingleCollection.add(new Tag(0x0018, 0x0071));
		objSingleCollection.add(new Tag(0x0018,0x9719));
		
		objSingleCollection.add(new Tag(0x0018,0x9720));
		objSingleCollection.add(new Tag(0x0018,0x9721));		
		objSingleCollection.add(new Tag(0x0018,0x9722));
		objSingleCollection.add(new Tag(0x0018,0x9723));
		objSingleCollection.add(new Tag(0x0018,0x9724));
		objSingleCollection.add(new Tag(0x0054, 0x0202));
		
		objSingleCollection.add(new Tag(0x0018, 0x9725));
		objSingleCollection.add(new Tag(0x0018, 0x9726));
		objSingleCollection.add(new Tag(0x0018, 0x9727));
		objSingleCollection.add(new Tag(0x0018, 0x1181));
		
		objSingleCollection.add(new Tag(0x0054, 0x1210));
		objSingleCollection.add(new Tag(0x0054, 0x0013));
		objSingleCollection.add(new Tag(0x0018, 0x1134));
		
		objSingleCollection.add(new Tag(0x0018, 0x9755));
		objSingleCollection.add(new Tag(0x300A,0x012C));
		objSingleCollection.add(new Tag(0x0054,0x0501));
	}

	/**
	 * 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 true, if validate module
	 * 
	 * @throws InvalidModuleException - If validation of Module fails
	 */
	public  boolean validateModule() throws InvalidModuleException
	{

		try
		{	
			WholeSlideMicroscopyImageModule objWholeSlideMicroscopyImageModule = null;
			@SuppressWarnings("null")
			String strImageType=objWholeSlideMicroscopyImageModule.getImageType();			
			if(strImageType.equalsIgnoreCase(EnumImageType.Value1.ORIGINAL.getValue()) && !isPresent(0x0018, 0x0073))
				throw new ConditionFailedException("0018, 0073 is required if Image Type (0008,0008) Value 1 is ORIGINAL");
			
			String strAcquisitionStartCondition=getAcquisitionStartCondition();
			if(strAcquisitionStartCondition.equalsIgnoreCase(EnumAcquisitionStartCondition.DENSITY.getValue()) && !isPresent(0x0018,0x9715))
				throw new ConditionFailedException("0018,9715 is required if Acquisition Start Condition (0018,0073) equals DENS.");
			
			if(strAcquisitionStartCondition.equalsIgnoreCase(EnumAcquisitionStartCondition.RELATIVE_DENSITY_DIFFERENCE.getValue()) && !isPresent(0x0018,0x9716))
				throw new ConditionFailedException("0018,9716 is required if Acquisition Start Condition (0018,0073) equals RDD.");

			if(strAcquisitionStartCondition.equalsIgnoreCase(EnumAcquisitionStartCondition.CARD_TRIG.getValue()) && !isPresent(0x0018,0x9717))
				throw new ConditionFailedException("0018,9717 is required if Acquisition Start Condition (0018,0073) equals CARD_TRIG.");
			
			if(strAcquisitionStartCondition.equalsIgnoreCase(EnumAcquisitionStartCondition.RESP_TRIG.getValue()) && !isPresent(0x0018,0x9718))
				throw new ConditionFailedException("0018,9718 is required if Acquisition Start Condition (0018,0073) equals RESP_TRIG.");
			
			if(strImageType.equalsIgnoreCase(EnumImageType.Value1.ORIGINAL.getValue()) && !isPresent(0x0018, 0x0071))
				throw new ConditionFailedException("0018, 0071 is required if Image Type (0008,0008) Value 1 is ORIGINAL");
			
			String strAcquisitionTerminationCondition=getAcquisitionTerminationCondition();
			if(strAcquisitionTerminationCondition.equalsIgnoreCase(EnumAcquisitionTerminationCondition.COUNTS.getValue()) && !isPresent(0x0018,0x9719))
				throw new ConditionFailedException("0018,9719 is required if Acquisition Termination Condition (0018,0071) equals CNTS.");
			
			if(strAcquisitionTerminationCondition.equalsIgnoreCase(EnumAcquisitionTerminationCondition.DENSITY.getValue()) && !isPresent(0x0018,0x9720))
				throw new ConditionFailedException("0018,9720 is required if Acquisition Termination Condition (0018,0071) equals DENS.");
			
			if(strAcquisitionTerminationCondition.equalsIgnoreCase(EnumAcquisitionTerminationCondition.RELATIVE_DENSITY_DIFFERENCE.getValue()) && !isPresent(0x0018,0x9721))
				throw new ConditionFailedException("0018,9721 is required if Acquisition Termination Condition (0018,0071) equals RDD.");
			
			if(strAcquisitionTerminationCondition.equalsIgnoreCase(EnumAcquisitionTerminationCondition.TIME.getValue()) && !isPresent(0x0018,0x9722))
				throw new ConditionFailedException("0018,9722 is required if Acquisition Termination Condition (0018,0071) equals TIME.");
			
			if(strAcquisitionTerminationCondition.equalsIgnoreCase(EnumAcquisitionTerminationCondition.CARD_TRIG.getValue()) && !isPresent(0x0018,0x9723))
				throw new ConditionFailedException("0018,9723 is required if Acquisition Termination Condition (0018,0071) equals CARD_TRIG.");
			
			if(strAcquisitionTerminationCondition.equalsIgnoreCase(EnumAcquisitionTerminationCondition.RESP_TRIG.getValue()) && !isPresent(0x0018,0x9724))
				throw new ConditionFailedException("0018,9724 is required if Acquisition Termination Condition (0018,0071) equals RESP_TRIG.");
			
			if(strImageType.equalsIgnoreCase(EnumImageType.Value1.ORIGINAL.getValue()) && !isPresent(0x0054,0x9202))
				throw new ConditionFailedException("0054, 0202 is required if Image Type (0008,0008) Value 1 is ORIGINAL");
			
			if(strImageType.equalsIgnoreCase(EnumImageType.Value1.ORIGINAL.getValue()) && !isPresent(0x0018, 0x9726))
				throw new ConditionFailedException("0018, 9726 is required if Image Type (0008,0008) Value 1 is ORIGINAL");
			
			if(strImageType.equalsIgnoreCase(EnumImageType.Value1.ORIGINAL.getValue()) && !isPresent(0x0018, 0x9727))
				throw new ConditionFailedException("0018, 9727 is required if Image Type (0008,0008) Value 1 is ORIGINAL");
			
			if(strImageType.equalsIgnoreCase(EnumImageType.Value1.ORIGINAL.getValue()) && !isPresent(0x0018, 0x1181))
				throw new ConditionFailedException("0018, 1181 is required if Image Type (0008,0008) Value 1 is ORIGINAL");
			
			if(strImageType.equalsIgnoreCase(EnumImageType.Value1.ORIGINAL.getValue()) && !isPresent(0x0054, 0x1210))
				throw new ConditionFailedException("0054, 1210 is required if Image Type (0008,0008) Value 1 is ORIGINAL");
			
			if(strImageType.equalsIgnoreCase(EnumImageType.Value1.ORIGINAL.getValue()) && !isPresent(0x0054, 0x0013))
				throw new ConditionFailedException("0054, 10013 is required if Image Type (0008,0008) Value 1 is ORIGINAL");
			
			if(!isPresent(0x0018, 0x1134))
				throw new MandatoryMissingException("0018, 1134");	
			
			if(!isPresent(0x0018, 0x9755))
				throw new MandatoryMissingException("0018, 9755");
		}
		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 Description of how the data collection was started. Defined terms
	 * DENS = density (counts/sec)
	 * RDD = relative density difference(change in counts/sec)
	 * MANU = manual
	 * TIME = time
	 * AUTO = automatic, when ready
	 * TRIG = physiological trigger
	 * 
	 * @param strAcquisitionStartCondition String value of Acquisition Start Condition
	 */
	public void setAcquisitionStartCondition(String strAcquisitionStartCondition)
	{
		/* Accept Acquisition Start Condition 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, 0x0073, DicomConstants.DCM_DT_CS, strAcquisitionStartCondition);
	}

	/**
	 * Return Description of how the data collection was started.
	 * 
	 * @return String - String value of Acquisition Start Condition
	 */
	public String getAcquisitionStartCondition()
	{
		Object objectValue = getValue(0x0018, 0x0073);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}
	/**
	 * Sets Start Density Threshold
	 * @param dblStartDensityThreshold Double value of Start Density Threshold
	 */
	public void setStartDensityThreshold(double dblStartDensityThreshold)
	{
		/*Accept the Start Density Threshold in double format of type FD.
		 * 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, 0x9715, DicomConstants.DCM_DT_FD,dblStartDensityThreshold);
	}
	/**
	 * Retrieves Start Density Threshold
	 * @return double - double value of Start Density Threshold
	 */
	public double getStartDensityThreshold()
	{
		Object objValue = getValue(0x0018,0x9715);
		if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets Start Relative DensityDifference Threshold
	 * @param dblStartRelativeDensityDifferenceThreshold value of Start Relative DensityDifference Threshold
	 */
	public void setStartRelativeDensityDifferenceThreshold(double dblStartRelativeDensityDifferenceThreshold)
	{
		/*Accept the Start Relative DensityDifference Threshold in double format of type FD.
		 * 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, 0x9716, DicomConstants.DCM_DT_FD,dblStartRelativeDensityDifferenceThreshold);
	}
	/**
	 * Retrieves Start Relative DensityDifference Threshold
	 * @return double - double value of Start Relative DensityDifference Threshold
	 */
	public double getStartRelativeDensityDifferenceThreshold()
	{
		Object objValue = getValue(0x0018,0x9716);
		if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets Start Cardiac Trigger CountThreshold
	 * @param dblStartCardiacTriggerCountThreshold value of Start Cardiac Trigger CountThreshold
	 */
	public void setStartCardiacTriggerCountThreshold(double dblStartCardiacTriggerCountThreshold)
	{
		/*Accept the Start Cardiac Trigger CountThreshold in double format of type FD.
		 * 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, 0x9717, DicomConstants.DCM_DT_FD,dblStartCardiacTriggerCountThreshold);
	}
	/**
	 * Retrieves Start Cardiac Trigger CountThreshold
	 * @return double - double value of Start Cardiac Trigger CountThreshold
	 */
	public double getStartCardiacTriggerCountThreshold()
	{
		Object objValue = getValue(0x0018,0x9717);
		if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets Start Respiratory TriggerCount Threshold
	 * @param dblStartRespiratoryTriggerCountThreshold value of Start Respiratory TriggerCount Threshold
	 */
	public void setStartRespiratoryTriggerCountThreshold(double dblStartRespiratoryTriggerCountThreshold)
	{
		/*Accept the Start Respiratory TriggerCount Threshold in double format of type FD.
		 * 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, 0x9718, DicomConstants.DCM_DT_FD,dblStartRespiratoryTriggerCountThreshold);
	}
	/**
	 * Retrieves Start Respiratory TriggerCount Threshold
	 * @return double - double value of Start Respiratory TriggerCount Threshold
	 */
	public double getStartRespiratoryTriggerCountThreshold()
	{
		Object objValue = getValue(0x0018,0x9718);
				if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets Description of how the data collection was stopped. Defined Terms:
	 * CNTS = counts,DENS = density,MANU = manual,OVFL = data overflow,TIME = time,TRIG = physiological trigger,RDD = relative density difference
	 * 
	 * @param enumAcquisitionTerminationCondition - Specifies how the data collection was stopped
	 */
	public void setAcquisitionTerminationCondition(EnumAcquisitionTerminationCondition enumAcquisitionTerminationCondition)
	{
		/*Accept Acquisition Termination Condition in String 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(0x0018, 0x0071, DicomConstants.DCM_DT_CS, enumAcquisitionTerminationCondition.getValue());
	}

	/**
	 * Returns Description of how the data collection was stopped.
	 * 
	 * @return String - String value of Acquisition Termination Condition
	 */
	public String getAcquisitionTerminationCondition()
	{
		Object objectValue = getValue(0x0018, 0x0071);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}
	/**
	 * Sets Start Termination Counts Threshold
	 * @param dblTerminationCountsThreshold value of Termination Counts Threshold
	 */
	public void setTerminationCountsThreshold(double dblTerminationCountsThreshold)
	{
		/*Accept the Termination Counts Threshold in double format of type FD.
		 * 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, 0x9719, DicomConstants.DCM_DT_FD,dblTerminationCountsThreshold);
	}
	/**
	 * Retrieves Termination Counts Threshold
	 * @return double - double value of Termination Counts Threshold
	 */
	public double getTerminationCountsThreshold()
	{
		Object objValue = getValue(0x0018,0x9719);
				if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets Termination Density Threshold
	 * @param dblTerminationDensityThreshold value of Termination Density Threshold
	 */
	public void setTerminationDensityThreshold(double dblTerminationDensityThreshold)
	{
		/*Accept the Termination Density Threshold in double format of type FD.
		 * 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, 0x9720, DicomConstants.DCM_DT_FD,dblTerminationDensityThreshold);
	}
	/**
	 * Retrieves Termination Density Threshold
	 * @return double - double value of Termination Density Threshold
	 */
	public double getTerminationDensityThreshold()
	{
		Object objValue = getValue(0x0018,0x9720);
				if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	
	/**
	 * Sets Termination Relative DensityThreshold
	 * @param dblTerminationRelativeDensityThreshold value of Termination Relative DensityThreshold
	 */
	public void setTerminationRelativeDensityThreshold(double dblTerminationRelativeDensityThreshold)
	{
		/*Accept the Termination Relative DensityThreshold in double format of type FD.
		 * 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, 0x9721, DicomConstants.DCM_DT_FD,dblTerminationRelativeDensityThreshold);
	}
	/**
	 * Retrieves Termination Relative DensityThreshold
	 * @return double - double value of Termination Relative DensityThreshold
	 */
	public double getTerminationRelativeDensityThreshold()
	{
		Object objValue = getValue(0x0018,0x9721);
				if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	
	/**
	 * Sets Termination Time Threshold
	 * @param dblTerminationTimeThreshold value of Termination Time Threshold
	 */
	public void setTerminationTimeThreshold(double dblTerminationTimeThreshold)
	{
		/*Accept the Termination Time Threshold in double format of type FD.
		 * 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, 0x9722, DicomConstants.DCM_DT_FD,dblTerminationTimeThreshold);
	}
	/**
	 * Retrieves Termination Time Threshold
	 * @return double - double value of Termination Time Threshold
	 */
	public double getTerminationTimeThreshold()
	{
		Object objValue = getValue(0x0018,0x9722);
				if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets Termination Cardiac Trigger CountThreshold
	 * @param dblTerminationCardiacTriggerCountThreshold value of Termination Cardiac Trigger CountThreshold
	 */
	public void setTerminationCardiacTriggerCountThreshold(double dblTerminationCardiacTriggerCountThreshold)
	{
		/*Accept the Termination Cardiac Trigger CountThreshold in double format of type FD.
		 * 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, 0x9723, DicomConstants.DCM_DT_FD,dblTerminationCardiacTriggerCountThreshold);
	}
	/**
	 * Retrieves Termination Cardiac Trigger CountThreshold
	 * @return double - double value of Termination Cardiac Trigger CountThreshold
	 */
	public double getTerminationCardiacTriggerCountThreshold()
	{
		Object objValue = getValue(0x0018,0x9723);
				if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets Termination Respiratory TriggerCount Threshold
	 * @param dblTerminationRespiratoryTriggerCountThreshold value of Termination Respiratory TriggerCount Threshold
	 */
	public void setTerminationRespiratoryTriggerCountThreshold(double dblTerminationRespiratoryTriggerCountThreshold)
	{
		/*Accept the Termination Respiratory TriggerCount Threshold in double format of type FD.
		 * 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, 0x9724, DicomConstants.DCM_DT_FD,dblTerminationRespiratoryTriggerCountThreshold);
	}
	/**
	 * Retrieves Termination Respiratory TriggerCount Threshold
	 * @return double - double value of Termination Respiratory TriggerCount Threshold
	 */
	public double getTerminationRespiratoryTriggerCountThreshold()
	{
		Object objValue = getValue(0x0018,0x9724);
				if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets the activity of the Detector during acquisition.
	 * @param strTypeOfDetectorMotion Specifies the activity of the Detector during acquisition.
	 */
	public void setTypeOfDetectorMotion(String strTypeOfDetectorMotion)
	{
		/*Accept the Value Type 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(0x0054, 0x0202, DicomConstants.DCM_DT_CS,strTypeOfDetectorMotion);
	}
	/**
	 * Retrieves the activity of the Detector during acquisition.
	 * @return String - the activity of the Detector during acquisition.
	 */
	public String getTypeOfDetectorMotion()
	{
		Object objValue = getValue(0x0054, 0x0202);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	/**
	 * Sets Physical arrangement of the detectors in the acquisition system
	 * @param enumDetectorGeometry - Specifies Detector Geometry
	 */
	public void setDetectorGeometry(EnumDetectorGeometry enumDetectorGeometry)
	{
		/*Accept Acquisition Termination Condition in String 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(0x0018, 0x9725, DicomConstants.DCM_DT_CS, enumDetectorGeometry.getValue());
	}

	/**
	 * Returns Physical arrangement of the detectors in the acquisition system
	 * @return String - String value of DetectorGeometry
	 */
	public String getDetectorGeometry()
	{
		Object objectValue = getValue(0x0018, 0x9725);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}
	/**
	 * Sets Transverse DetectorSeparation
	 * @param dblTransverseDetectorSeparation value of Transverse DetectorSeparation
	 */
	public void setTransverseDetectorSeparation(double dblTransverseDetectorSeparation)
	{
		/*Accept the Transverse DetectorSeparation in double format of type FD.
		 * 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, 0x9726, DicomConstants.DCM_DT_FD,dblTransverseDetectorSeparation);
	}
	/**
	 * Retrieves Transverse DetectorSeparation
	 * @return double - double value of Transverse DetectorSeparation
	 */
	public double getTransverseDetectorSeparation()
	{
		Object objValue = getValue(0x0018,0x9726);
				if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets Axial Detector Dimension
	 * @param dblAxialDetectorDimension value of Axial Detector Dimension
	 */
	public void setAxialDetectorDimension(double dblAxialDetectorDimension)
	{
		/*Accept the Axial Detector Dimension in double format of type FD.
		 * 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, 0x9727, DicomConstants.DCM_DT_FD,dblAxialDetectorDimension);
	}
	/**
	 * Retrieves Axial Detector Dimension
	 * @return double - double value ofAxial Detector Dimension
	 */
	public double getAxialDetectorDimension()
	{
		Object objValue = getValue(0x0018,0x9727);
				if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets Collimator Type.
	 * Defined Terms:
	 * NONE = no collimator
	 * RING = transverse septa
	 * 
	 * @param enumCollimatorType Enum value of Collimator Type.
	 */
	public void setCollimatorType(EnumCollimatorType enumCollimatorType)
	{
		/* Accept Collimator Type in String 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(0x0018,0x1181, DicomConstants.DCM_DT_CS, enumCollimatorType.getValue());
	}

	/**
	 * Retrieves the Type of Collimator.
	 * 
	 * @return String - returns the type of Collimator
	 */
	public String getCollimatorType()
	{
		Object objectValue = getValue(0x0018, 0x1181);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}
	/**
	 * Sets The width of the coincidence timing window, in nsec.
	 * The maximum time difference accepted between two single events.
	 * 
	 * @param strCoincidenceWindowWidth String value of Coincidence Window Width.
	 */
	public void setCoincidenceWindowWidth(String strCoincidenceWindowWidth)
	{
		/* Accept Transverse Mash in String format of type IS.
		 * 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(0x0054,0x1210, DicomConstants.DCM_DT_DS, strCoincidenceWindowWidth);
	}

	/**
	 * Retrieves The width of the coincidence timing window, in nsec.
	 * 
	 * @return String - String value of Coincidence Window Width
	 */
	public String getCoincidenceWindowWidth()
	{
		Object objectValue = getValue(0x0054, 0x1210);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}
	/**
	 * Retrieves pre-initialized object of Energy Window RangeSequence.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 EnergyWindowRangeSequence - instance of Energy Window RangeSequence
	 */
	public EnergyWindowRangeSequence getEnergyWindowRangeSequence()
	{
		EnergyWindowRangeSequence objEnergyWindowRangeSequence = (EnergyWindowRangeSequence)getDicomValue(0x0054, 0x0013);
		if(objEnergyWindowRangeSequence == 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();
			objEnergyWindowRangeSequence = (EnergyWindowRangeSequence)objDicomV3Factory.createSequence(0x0054, 0x0013, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0054, 0x0013, DicomConstants.DCM_DT_SQ, objEnergyWindowRangeSequence.getValue());
		}
		return objEnergyWindowRangeSequence;
	}
	/**
	 * Sets Table Motion value. Defined terms: STATIC, DYNAMIC
	 * 
	 * @param enumTableMotion Enum value of Table Motion
	 */
	public void setTableMotion(EnumTableMotion enumTableMotion)
	{
		/* Accept Table Motion 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(0x0018, 0x1134, DicomConstants.DCM_DT_IS, enumTableMotion.getValue());
	}
	/**
	 * Return Table Motion.
	 * 
	 * @return - String value of Table Motion
	 */
	public String getTableMotion()
	{
		Object objValue = getValue(0x0018,0x1134);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	/**
	 * Sets whether or not Time-of-Flight information was used in creationof the image.
	 * @param enumTimeOfFlightInformationUsed - Specifies Time of Flight InformationUsed
	 */
	public void setTimeOfFlightInformationUsed(EnumTimeOfFlightInformationUsed enumTimeOfFlightInformationUsed)
	{
		/*Accept Time of Flight InformationUsed in String 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(0x0018, 0x9755, DicomConstants.DCM_DT_CS, enumTimeOfFlightInformationUsed.getValue());
	}

	/**
	 * Returns whether or not Time-of-Flight information was used in creationof the image.
	 * @return String - String value of Time of Flight InformationUsed
	 */
	public String getTimeOfFlightInformationUsed()
	{
		Object objectValue = getValue(0x0018, 0x9755);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}
	/**
	 * Get the Instance of Mandatory View and Slice ProgressionDirection Macro Attributes .Calling this method multiple times will return the same Marco
	 * Instance that was created at first. Hence, any attributes in this Macro,if set multiple times will contain the value that was
	 * set in the last call to its setter method.
	 * 
	 * @return - object of Mandatory View and Slice ProgressionDirection Macro Attributes
	 */
	public MandatoryViewandSliceProgressionDirectionMacro getMandatoryViewandSliceProgressionDirectionMacro()
	{
		if(objMandatoryViewandSliceProgressionDirectionMacro == null)
			objMandatoryViewandSliceProgressionDirectionMacro = new MandatoryViewandSliceProgressionDirectionMacro(objIDataSet);
		return objMandatoryViewandSliceProgressionDirectionMacro; 
	}
	/**
	 * Sets Isocenter Position
	 * @param strIsocenterPosition String value of Isocenter Position
	 */
	public void setIsocenterPosition(String[] strIsocenterPosition)
	{
		/*Accept the SliceThickness 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,strIsocenterPosition);
	}
	/**
	 * 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;
	}
	/**
	 * Sets the Value Type Defined in Terms of TEXT,NUMERIC,CODE,DATE,TIME,PNAME
	 * @param strValueType Specifies type of the value encoded in this Item
	 */
	public void setScanProgressionDirection(String strSUVType)
	{
		/*Accept the Value Type 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(0x0054, 0x0501,DicomConstants.DCM_DT_CS, strSUVType);
		
	}
	/**
	 * Retrieves type of the value encoded in this Item
	 * @return String - Type of the value encoded in this Item
	 */
	public String getScanProgressionDirection()
	{
		Object objValue = getValue(0x0054, 0x0501);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	/**
	 * This method returns the collection of keys representing the DataElements that belong to this module.
	 * 
	 * @return Collection of Tags - returns the collection containing the tags
	 */
	public ISingleCollection<ITag> getVectorOfKeys()
	{
		return objSingleCollection;
	}

}
