/*******************************************************************************
 *  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.CodingSchemeIdentificationSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.ContributingEquipmentSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.ContributingEquipmentSequenceItem;
import cdac.medinfo.sdk.dcm30_04.baselibs.ConversionSourceAttributesSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.DicomV3Factory;
import cdac.medinfo.sdk.dcm30_04.baselibs.DigitalSignaturesMacro;
import cdac.medinfo.sdk.dcm30_04.baselibs.EncryptedAttributesSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.HL7StructuredDocumentReferenceSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.OriginalAttributesSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.PrivateDataElementCharacteristicsSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.Tag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IItem;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.enums.EnumContentQualification;
import cdac.medinfo.sdk.dcm30_04.enums.EnumLongitudinalTemporalInformationModified;
import cdac.medinfo.sdk.dcm30_04.enums.EnumQueryRetrieveView;

import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidModuleException;
import cdac.medinfo.sdk.dcm30_04.exceptions.ItemLimitException;
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.ICollectionIterator;
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 that describe SOP Common Module.
*/
public class SOPCommonModule extends Module   
{


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

	/**
	 * The obj digital signatures macro.
	 */
	DigitalSignaturesMacro objDigitalSignaturesMacro = null;



	/**
	 * Instantiates a new sOP common module.
	 * 
	 * @param objIDataSet the obj i data set
	 */
	public SOPCommonModule(IDataSet objIDataSet)
	{
		super(objIDataSet);
	}

	static
	{
		objSingleCollection = new SingleCollection<ITag>();
		objSingleCollection.add(new Tag(0x0008,0x0005));
		objSingleCollection.add(new Tag(0x0008,0x0012));
		objSingleCollection.add(new Tag(0x0008,0x0013));
		objSingleCollection.add(new Tag(0x0008,0x0014));
		objSingleCollection.add(new Tag(0x0008,0x0016));
		objSingleCollection.add(new Tag(0x0008,0x0018));
		objSingleCollection.add(new Tag(0x0008,0x001A));
		objSingleCollection.add(new Tag(0x0008,0x001B));
		objSingleCollection.add(new Tag(0x0008,0x0110));
		objSingleCollection.add(new Tag(0x0008,0x0201));
		objSingleCollection.add(new Tag(0x0018,0xA001));		
		objSingleCollection.add(new Tag(0x0020,0x0013));
		objSingleCollection.add(new Tag(0x0100,0x0410));
		objSingleCollection.add(new Tag(0x0100,0x0420));
		objSingleCollection.add(new Tag(0x0100,0x0424));
		objSingleCollection.add(new Tag(0x0100,0x0426));
		objSingleCollection.add(new Tag(0x0400,0x0500));//SQ Type Parent DE	
		objSingleCollection.add(new Tag(0x0400,0x0561));
		objSingleCollection.add(new Tag(0x0040,0xA390));
		objSingleCollection.add(new Tag(0x0028,0x0303));
		objSingleCollection.add(new Tag(0x0008,0x0053));
		objSingleCollection.add(new Tag(0x0020,0x9172));
		objSingleCollection.add(new Tag(0x0018,0x9004));
		objSingleCollection.add(new Tag(0x0008,0x0300));
	}

	/**
	 * 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 - returns validation status as success or failure.
	 * 
	 * @throws InvalidModuleException If validation of Module fails.
	 */
	public  boolean validateModule() throws InvalidModuleException
	{

		try
		{			//Check for the Type 1,2 Mandatory Attributes.
			if(!isPresent(0x0008,0x0016))
				throw new MandatoryMissingException("0008,0016");
			if(!isPresent(0x0008,0x0018))
			{
				throw new MandatoryMissingException("0008,0018");
				/*  
				 * For the Data Element (0008,0005)----1C type
				 * The Condition is not understood :
				 * Character Set that expands or replaces the Basic Graphic Set. 
				 * Required if an expanded or replacement character set is used.
				 * See C.12.1.1.2 for Defined Terms.
				 */

				/*  
				 * For the Data Element (0400,0500)----1C type
				 * The Condition is not understood :
				 * Sequence of Items containing encrypted DICOM data. 
				 * One or more Items shall be present. 
				 * Required if application level confidentiality is needed and certain 
				 * recipients are allowed to decrypt all or portions of 
				 * the Encrypted Attributes Data Set. See C.12.1.1.4.1.
				 */
			}

			getDigitalSignaturesMacro().validate();
			if(isPresent(0x0008,0x0110))
				getCodingSchemeIdentificationSequence().validateForModule();
			if(isPresent(0x0018,0xA001))
			{
				getContributingEquipmentSequence().validateForModule();
				ICollectionIterator<IItem> objContributingEquipmentSequenceIterator = getContributingEquipmentSequence().iterator();
				ContributingEquipmentSequenceItem objContributingEquipmentSequenceItem = null;
				while(objContributingEquipmentSequenceIterator.hasNext())
				{
					objContributingEquipmentSequenceItem = (ContributingEquipmentSequenceItem)objContributingEquipmentSequenceIterator.next();
					int iNoOfItems = objContributingEquipmentSequenceItem.getPurposeOfReferenceCodeSequence().noOfItems();
					if(iNoOfItems > 1)
						throw new ItemLimitException("0040,A170 shall contain Single Item");
				}

			}
			if(isPresent(0x0400,0x0500))
				getEncryptedAttributesSequence().validateForModule();
		}
		catch(MandatoryMissingException mme)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(mme.getMessage());

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

		}
		return true;
	}

	/**
	 * The method is used to set Unique identifier the SOP Class.
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strSOPClassUID the str sop class uid
	 */
	public void setSOPClassUID(String strSOPClassUID)
	{
		/*Accept Unique identifier the SOP Class in String format of type UI.
		 * 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(0x0008,0x0016, DicomConstants.DCM_DT_UI, strSOPClassUID);
	}

	/**
	 * The method is used to set Unique identifier the SOP Instance.
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strSOPInstanceUID  Unique identifier the SOP Instance.
	 */
	public void setSOPInstanceUID(String strSOPInstanceUID)
	{
		/*Accept Unique identifier the SOP Instance in String format of type UI.
		 * 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(0x0008,0x0018, DicomConstants.DCM_DT_UI, strSOPInstanceUID);
	}

	/**
	 * This method is used to set Character Set that expands or replaces the Basic Graphic Set.
	 * 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 DataSet
	 * 
	 * @param arrStrSpecificCharacterSet  Character Set that expands or replaces the Basic Graphic Set.
	 */	
	public void setSpecificCharacterSet(String[] arrStrSpecificCharacterSet)
	{
		/*Accept  Character Set that expands or replaces the Basic Graphic Set
		 *  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 Data Set
		 */
		addDataElement(0x0008, 0x0005, DicomConstants.DCM_DT_CS, arrStrSpecificCharacterSet);
	}

	/**
	 * The method is used to set Date the SOP Instance was created.
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strInstanceCreationDate  Date the SOP Instance was created.
	 */
	public void setInstanceCreationDate(String strInstanceCreationDate)
	{
		/*Accept Date the SOP Instance was created in String format of type DA.
		 * 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(0x0008,0x0012, DicomConstants.DCM_DT_DA, strInstanceCreationDate);
	}

	/**
	 * The method is used to set Time the SOP Instance was created.
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strInstanceCreationTime  Time the SOP Instance was created.
	 */
	public void setInstanceCreationTime(String strInstanceCreationTime)
	{
		/*Accept Time the SOP Instance was created 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 Data Set
		 */
		addDataElement(0x0008,0x0013, DicomConstants.DCM_DT_TM, strInstanceCreationTime);
	}

	/**
	 * The method is used to set Uniquely identifies device which created the SOP Instance.
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strInstanceCreatorUID Uniquely identifies device which created the SOP Instance.
	 */
	public void setInstanceCreatorUID(String strInstanceCreatorUID)
	{
		/*Accept Uniquely identifies device which created the SOP Instance in String format of type UI.
		 * 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(0x0008,0x0014, DicomConstants.DCM_DT_UI, strInstanceCreatorUID);
	}

	/**
	 * This method is used to set Uniquely identifies a Related General SOP Class
	 * for the SOP Class of this Instance.
	 * 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 DataSet
	 * 
	 * @param arrStrRelatedGeneralSOPClassUID  Uniquely identifies a Related General SOP Class
	 * for the SOP Class of this Instance.
	 */	
	public void setRelatedGeneralSOPClassUID(String[] arrStrRelatedGeneralSOPClassUID)
	{
		/*Accept  Uniquely identifies a Related General SOP Class 
		 * for the SOP Class of this Instance. 
		 * in String Array format of type UI.
		 * 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 Data Set
		 */
		addDataElement(0x0008, 0x001A, DicomConstants.DCM_DT_UI, arrStrRelatedGeneralSOPClassUID);
	}

	/**
	 * The method is used to set The SOP Class in which the Instance was originally encoded,
	 * but which has been replaced during a fall-back conversion to the current Related General SOP Class.
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strOriginalSpecializedSOPClassUID  Unique identifier of Original Specialized SOP Class.
	 */
	public void setOriginalSpecializedSOPClassUID(String strOriginalSpecializedSOPClassUID)
	{
		/*Accept The SOP Class in which the Instance was originally encoded, 
		 * 	but which has been replaced during a fall-back conversion to the current Related General SOP Class
		 * in String format of type UI.
		 * 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(0x0008,0x001B, DicomConstants.DCM_DT_UI, strOriginalSpecializedSOPClassUID);
	}

	/**
	 * The method is used to set Contains the offset from UTC to the
	 * timezone for all DA and TM Attributes present in this SOP Instance.
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strTimezoneOffsetFromUTC  Contains the offset from UTC to the timezone for all DA and TM Attributes present in this SOP Instance.
	 */
	public void setTimezoneOffsetFromUTC(String strTimezoneOffsetFromUTC)
	{
		/* Accept Contains the offset from UTC to the
		 * timezone for all DA and TM Attributes present in this SOP Instance  in String format of type SH.
		 * 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(0x0008,0x0201, DicomConstants.DCM_DT_SH, strTimezoneOffsetFromUTC);
	}

	/**
	 * The method is used to set A number that identifies this Composite object instance.
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strInstanceNumber A number that identifies this Composite object instance.
	 */
	public void setInstanceNumber(String strInstanceNumber)
	{
		/* Accept Instance Numberin 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 Data Set
		 */
		addDataElement(0x0020, 0x0013, DicomConstants.DCM_DT_IS, strInstanceNumber);
	}

	/**
	 * The method is used to set A flag that indicates the storage status of the SOP Instance.
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strSOPInstanceStatus  A flag that indicates the storage status of the SOP Instance.
	 */
	public void setSOPInstanceStatus(String strSOPInstanceStatus)
	{
		/*Accept A flag that indicates the storage status of the SOP Instance 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(0x0100,0x0410, DicomConstants.DCM_DT_CS, strSOPInstanceStatus);
	}

	/**
	 * The method is used to set The date and time when the SOP Instance
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strSOPAuthorizationDateandTime  The date and time when the SOP Instance
	 */
	public void setSOPAuthorizationDateandTime(String strSOPAuthorizationDateandTime)
	{
		/*Accept The date and time when the SOP Instance in String format of type DT.
		 * 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(0x0100,0x0420, DicomConstants.DCM_DT_DT, strSOPAuthorizationDateandTime);
	}

	/**
	 * The method is used to set Any comments associated with the setting of the SOP Instance Status
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strSOPAuthorizationComment  Any comments associated with the setting of the SOP Instance Status
	 */
	public void setSOPAuthorizationComment(String strSOPAuthorizationComment)
	{
		/*Accept Any comments associated with the setting of the SOP Instance Status 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(0x0100,0x0424, DicomConstants.DCM_DT_LT, strSOPAuthorizationComment);
	}

	/**
	 * The method is used to set The certification number issued to the
	 * Application Entity that set the SOP Instance Status.
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module DataSet
	 * 
	 * @param strAuthorizationEquipmentCertificationNumber  The certification number issued to the
	 * Application Entity that set the SOP Instance Status.
	 * 
	 * 
	 */
	public void setAuthorizationEquipmentCertificationNumber(String strAuthorizationEquipmentCertificationNumber)
	{
		/*Accept The certification number issued to the Application Entity that set 
		 * the SOP Instance Status in String format of type LO.
		 * 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(0x0100,0x0426, DicomConstants.DCM_DT_LO, strAuthorizationEquipmentCertificationNumber);
	}
	
	/**
	 * Sets status of Longitudinal Temporal Information Modified.
	 * Indicates whether or not the date and time attributes in the instance have been modified during de-identification.
	 * Enumerated Values:
	 * 1) UNMODIFIED
	 * 2) MODIFIED
	 * 3) REMOVED
	 * 
	 * @param enumLongitudinalTemporalInformationModified the enum Longitudinal Temporal Information Modified
	 */
	public void setLongitudinalTemporalInformationModified(EnumLongitudinalTemporalInformationModified  enumLongitudinalTemporalInformationModified)
	{
		/* Accept Longitudinal Temporal Information Modified 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, 0x0303, DicomConstants.DCM_DT_CS, enumLongitudinalTemporalInformationModified.getValue());
	}

	/**
	 * Sets Query/Retrieve View.
	 * The view requested during the C-MOVE operation that resulted in the transfer of this instance.
	 * Enumerated Values:
	 * 1) CLASSIC
	 * 2) ENHANCED
	 * 
	 * @param enumQueryRetrieveView the enum Query/Retrieve View
	 */
	public void setQueryRetrieveView(EnumQueryRetrieveView  enumQueryRetrieveView)
	{
		/* Accept Query/Retrieve View 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(0x0008,0x0053, DicomConstants.DCM_DT_CS, enumQueryRetrieveView.getValue());
	}
	
	/**
	 * Sets Content Qualification Indicator
	 * Enumerated Values:
	 * 1) PRODUCT
	 * 2) RESEARCH
	 * 3) SERVICE
	 * 
	 * @param enumContentQualification the enum Content Qualification
	 */
	public void setContentQualification(EnumContentQualification  enumContentQualification)
	{
		/* Accept 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 the UID of SOP Class.
	 * 
	 * @return String - returns the UID of SOP Class
	 */
	public String getSOPClassUID()
	{
		Object objValue = objIDataSet.getValue(0x0008,0x0016);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Retreives the UID of SOP Instance.
	 * 
	 * @return String - retruns the SOP Instance UID
	 */
	public String getSOPInstanceUID()
	{
		Object objValue = objIDataSet.getValue(0x0008,0x0018);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Retrieves the Specific Character Set.
	 * 
	 * @return String[] - returns the Specific Character Set
	 */
	public String[] getSpecificCharacterSet()
	{
		Object objValue = objIDataSet.getValue(0x0008, 0x0005);
		if(objValue != null)
			return (String[])objValue;
		return null;
	}

	/**
	 * Retrieves the Instance Creation Date.
	 * 
	 * @return String - returns the Date of Instance Creation
	 */
	public String getInstanceCreationDate()
	{
		Object objValue = objIDataSet.getValue(0x0008,0x0012);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Retrieves the Instance Creation Time.
	 * 
	 * @return String - returns the Time of Instance Creation
	 */
	public String getInstanceCreationTime()
	{
		Object objValue = objIDataSet.getValue(0x0008,0x0013);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Retrieves the UID of Instance Creator.
	 * 
	 * @return String - return the Instance Creator UID
	 */
	public String getInstanceCreatorUID()
	{
		Object objValue = objIDataSet.getValue(0x0008,0x0014);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Retrieves the UID of Related General SOP Class.
	 * 
	 * @return String - returns Related General SOP Class UID
	 */
	public String[] getRelatedGeneralSOPClassUID()
	{
		Object objValue = objIDataSet.getValue(0x0008, 0x001A);
		if(objValue != null)
			return (String[])objValue;
		return null;
	}

	/**
	 * Retrieves the Original Specialized SOP Class UID.
	 * 
	 * @return String - returns the UID of Original Specialized SOP Class
	 */
	public String getOriginalSpecializedSOPClassUID()
	{
		Object objValue = objIDataSet.getValue(0x0008,0x001B);
		if(objValue != null)
			return (String)objValue;
		return null;
	}

	/**
	 * Retrieves the Time zone Offset From UTC.
	 * 
	 * @return String - returns Time zone Offset From UTC
	 */
	public String getTimezoneOffsetFromUTC()
	{
		Object objValue = objIDataSet.getValue(0x0008,0x0201);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * This method provides the pre-initialized object of Contributing Equipment Sequence.
	 * 
	 * @return objContributingEquipmentSequence - object of Contributing Equipment 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
	 */
	public ContributingEquipmentSequence getContributingEquipmentSequence()
	{
		ContributingEquipmentSequence objContributingEquipmentSequence = (ContributingEquipmentSequence)getDicomValue(0x0018, 0xA001);
		if(objContributingEquipmentSequence == 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();
			objContributingEquipmentSequence = (ContributingEquipmentSequence)objDicomV3Factory.createSequence(0x0018, 0xA001, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0018, 0xA001, DicomConstants.DCM_DT_SQ, objContributingEquipmentSequence.getValue());
		}
		return objContributingEquipmentSequence;
	}

	/**
	 * This method provides the pre-initialized object of Contributing Equipment Sequence.
	 * 
	 * @return objCodingSchemeIdentificationSequence - object of Contributing Equipment 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
	 */
	public CodingSchemeIdentificationSequence getCodingSchemeIdentificationSequence()
	{
		CodingSchemeIdentificationSequence objCodingSchemeIdentificationSequence = (CodingSchemeIdentificationSequence)getDicomValue(0x0008, 0x0110);
		if(objCodingSchemeIdentificationSequence == 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();
			objCodingSchemeIdentificationSequence = (CodingSchemeIdentificationSequence)objDicomV3Factory.createSequence(0x0008, 0x0110, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0008, 0x0110, DicomConstants.DCM_DT_SQ, objCodingSchemeIdentificationSequence.getValue());
		}
		return objCodingSchemeIdentificationSequence;
	}

	/**
	 * This method provides the pre-initialized object of Contributing Equipment Sequence.
	 * 
	 * @return objEncryptedAttributesSequence - object of Contributing Equipment 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
	 */
	public EncryptedAttributesSequence getEncryptedAttributesSequence()
	{
		EncryptedAttributesSequence objEncryptedAttributesSequence = (EncryptedAttributesSequence)getDicomValue(0x0400, 0x0500);
		if(objEncryptedAttributesSequence == 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();
			objEncryptedAttributesSequence = (EncryptedAttributesSequence)objDicomV3Factory.createSequence(0x0400, 0x0500, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0400, 0x0500, DicomConstants.DCM_DT_SQ, objEncryptedAttributesSequence.getValue());
		}
		return objEncryptedAttributesSequence;
	}

	/**
	 * Retrieves the Instance Number.
	 * 
	 * @return String - returns  Instance Number
	 */
	public String getInstanceNumber()
	{
		Object objValue = objIDataSet.getValue(0x0020,0x0013);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Retrieves the status of SOPInstance.
	 * 
	 * @return String - returns SOP Instance Status
	 */
	public String getSOPInstanceStatus()
	{
		Object objValue = objIDataSet.getValue(0x0100,0x0410);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Retrieves the SOP Authorization Date and Time.
	 * 
	 * @return String - returns SOP Authorization Date and Time
	 */
	public String getSOPAuthorizationDateandTime()
	{
		Object objValue = objIDataSet.getValue(0x0100,0x0420);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Retrieves the comment for SOP Authorization.
	 * 
	 * @return String - returns SOP Authorization Comment
	 */
	public String getSOPAuthorizationComment()
	{
		Object objValue = objIDataSet.getValue(0x0100,0x0424);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Retrieves Authorization Equipment Certification Number.
	 * 
	 * @return String - the number of Authorization Equipment Certification
	 */
	public String getAuthorizationEquipmentCertificationNumber()
	{
		Object objValue = objIDataSet.getValue(0x0100,0x0426);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	
	/**
	 * This method provides the pre-initialized object of Original Attributes Sequence.
	 * 
	 * @return - object of Original Attributes 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
	 */
	public OriginalAttributesSequence getOriginalAttributesSequence()
	{
		OriginalAttributesSequence objOriginalAttributesSequence = (OriginalAttributesSequence)getDicomValue(0x0400, 0x0561);
		if(objOriginalAttributesSequence == 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();
			objOriginalAttributesSequence = (OriginalAttributesSequence)objDicomV3Factory.createSequence(0x0400, 0x0561, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0400, 0x0561, DicomConstants.DCM_DT_SQ, objOriginalAttributesSequence.getValue());
		}
		return objOriginalAttributesSequence;
	}
	
	/**
	 * This method provides the pre-initialized object of HL7 Structured Document Reference Sequence.
	 * 
	 * @return - object of HL7 Structured Document Reference 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
	 */
	public HL7StructuredDocumentReferenceSequence getHL7StructuredDocumentReferenceSequence()
	{
		HL7StructuredDocumentReferenceSequence objHL7StructuredDocumentReferenceSequence = (HL7StructuredDocumentReferenceSequence)getDicomValue(0x0040,0xA390);
		if(objHL7StructuredDocumentReferenceSequence == 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();
			objHL7StructuredDocumentReferenceSequence = (HL7StructuredDocumentReferenceSequence)objDicomV3Factory.createSequence(0x0040,0xA390, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0040,0xA390, DicomConstants.DCM_DT_SQ, objHL7StructuredDocumentReferenceSequence.getValue());
		}
		return objHL7StructuredDocumentReferenceSequence;
	}
	
	/**
	 * Retrieves Longitudinal Temporal Information Modified.
	 * 
	 * @return String - String value of Longitudinal Temporal Information Modified.
	 */ 
	public String getLongitudinalTemporalInformationModified()
	{
		Object objValue = getValue(0x0028,0x0303);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	
	/**
	 * Retrieves Query/Retrieve View.
	 * 
	 * @return String - String value of Query/Retrieve View.
	 */ 
	public String getQueryRetrieveView()
	{
		Object objValue = getValue(0x0008,0x0053);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * This method provides the pre-initialized object of Conversion Source Attributes Sequence.
	 * 
	 * @return - object of Conversion Source Attributes 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
	 */
	public ConversionSourceAttributesSequence getConversionSourceAttributesSequence()
	{
		ConversionSourceAttributesSequence objConversionSourceAttributesSequence = (ConversionSourceAttributesSequence)getDicomValue(0x0020,0x9172);
		if(objConversionSourceAttributesSequence == 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();
			objConversionSourceAttributesSequence = (ConversionSourceAttributesSequence)objDicomV3Factory.createSequence(0x0020,0x9172, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0020,0x9172, DicomConstants.DCM_DT_SQ, objConversionSourceAttributesSequence.getValue());
		}
		return objConversionSourceAttributesSequence;
	}

	/**
	 * Retrieves Content Qualification Indicator.
	 * 
	 * @return String - String value of Content Qualification.
	 */ 
	public String getContentQualification()
	{
		Object objValue = getValue(0x0018,0x9004);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	
	/**
	 * This method provides the pre-initialized object of Private Data Element Characteristics Sequence.
	 * 
	 * @return - object of Private Data Element Characteristics 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
	 */
	public PrivateDataElementCharacteristicsSequence getPrivateDataElementCharacteristicsSequence()
	{
		PrivateDataElementCharacteristicsSequence objPrivateDataElementCharacteristicsSequence = (PrivateDataElementCharacteristicsSequence)getDicomValue(0x0008,0x0300);
		if(objPrivateDataElementCharacteristicsSequence == 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();
			objPrivateDataElementCharacteristicsSequence = (PrivateDataElementCharacteristicsSequence)objDicomV3Factory.createSequence(0x0008,0x0300, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0008,0x0300, DicomConstants.DCM_DT_SQ, objPrivateDataElementCharacteristicsSequence.getValue());
		}
		return objPrivateDataElementCharacteristicsSequence;
	}
	
	/* 
	 * I have modified the collection type from vector to custom class
	 * This method is used by the Module Iterator to iterate through the DataSet and return only
	 * those elements that belong to the respective Module class whose getVectorOfKeys is called.
	 */
	/**
	 * This method returns the custom collection containing the list of DataElements belonging to the CT
	 * Image Module specified by DICOM Standard.
	 * 
	 * @return collection - custom collection containing the list of DataElements belonging to the CT Image Module
	 */
	public ISingleCollection<ITag> getVectorOfKeys()
	{
		return objSingleCollection;
	}

	/*
	 * made DigitalSignaturesMacro as instance member and took caution to create new object if already 
	 * not created.
	 */
	/**
	 * This method provides the Digital Signatures Macro which is the part of SOP Common Module.
	 * 
	 * @return object of Digital Signatures Macro which can be populated by the user programmer
	 */
	public DigitalSignaturesMacro getDigitalSignaturesMacro()
	{
		if(objDigitalSignaturesMacro == null)
			objDigitalSignaturesMacro = new DigitalSignaturesMacro(objIDataSet); 
		return new DigitalSignaturesMacro(objIDataSet);
	}
}
