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

import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomValue;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDictionaryReader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITransferSyntax;
import cdac.medinfo.sdk.dcm30_04.enums.EnumValueType;
import cdac.medinfo.sdk.dcm30_04.exceptions.ConditionFailedException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidItemException;
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;


/**
 * This item describes the conditions present during the acquisition of the
 *  data of the SOP Instance. Zero or more items may be included in this sequence.
 */
public class AcquisitionContextSequenceItem extends Item  
{
	
	private static final long serialVersionUID = 1L;

	/**
	 * This constructor creates the item with default TransferSyntax 
	 */
	AcquisitionContextSequenceItem()
	{
		super();
	}

	/*
	 * This constructor calls the respective superclass constructor
	 * This constructor should throw exception if null TS is tried to be set
	 */
	/**
	 * This constructor creates the item and internal code sequence macro with default TransferSyntax 
	 * and default DictionaryReader
	 * @param objITransferSyntax specifies the DICOM Standard defined TransfeSyntax
	 */
	AcquisitionContextSequenceItem(ITransferSyntax objITransferSyntax)
	{
		super(objITransferSyntax);
	}

	/**
	 * This constructor creates AcquisitionContextSequenceItem with specified TransferSyntax and
	 * specified DictionaryReader
	 * @param objTransferSyntax specifies the DICOM Standard defined TransfeSyntax
	 * @param objDictionaryReader specifies the DICOM Dictionary reader to be used 
	 */
	AcquisitionContextSequenceItem(ITransferSyntax objTransferSyntax, IDictionaryReader objDictionaryReader)
	{
		super(objTransferSyntax,objDictionaryReader);
	}

	/*
	 * (non-Javadoc) This method validates the contents of the Item
	 * @see cdac.medinfo.sdk.dcm30_04.commoninterface.IItem#validate()
	*/
	/**
	 * Validates all the attributes in AcquisitionContextSequenceItem that are present in the DataSet
	 * @return int - Success -true, Failure - false
	 * @throws InvalidItemException throws InvalidItemException If Mandatory or Conditional element fails.
	 */
	public boolean validateForModule()  throws InvalidItemException
	{
		try{
			/*
			 * Condition for (0040,A136) not understood. PDF 3, Pg. No. 301.
			 */
			if(!contains(0x0040,0xA043))
				throw new MandatoryMissingException("0040,A043");
			else
			{
				IDataElement objIDataElement = getDataForTag(0x0040, 0xA040);
				if(objIDataElement != null)
				{
					String strValue = objIDataElement.getDicomValue().getValue().toString();
					if(contains(0x0040,0xA30A) && strValue == null || !EnumValueType.NUMERIC.getValue().equals(strValue))
						throw new ConditionFailedException("value of conditional Element 0040,A040 required to be NUMERIC for Tag 0040,A30A") ;
					else if(contains(0x0040,0x08EA) && !contains(0x0040,0xA30A))
						throw new ConditionFailedException("conditional Element 0040,A30A required for Tag 0040,08EA is missing") ;
					else if(contains(0x0040,0xA121) && strValue == null || !EnumValueType.DATE.getValue().equals(strValue))
						throw new ConditionFailedException("value of conditional Element 0040,A040 required to be DATE for Tag 0040,A121") ;
					else if(contains(0x0040,0xA122) && strValue == null || !EnumValueType.TIME.getValue().equals(strValue))
						throw new ConditionFailedException("value of conditional Element 0040,A040 required to be TIME for Tag 0040,A121") ;		
					else if(contains(0x0040,0xA123) && strValue == null || !EnumValueType.PNAME.getValue().equals(strValue))
						throw new ConditionFailedException("value of conditional Element 0040,A040 required to be PNAME for Tag 0040,A123") ;			
				}
				else
				{
					if(contains(0x0040,0xA160) && contains(0x0040,0xA121))
						throw new ConditionFailedException("conditional Element 0040,A160 should not be present for Tag 0040,A121") ;
					else if(contains(0x0040,0xA160) && contains(0x0040,0xA122))
						throw new ConditionFailedException("conditional Element 0040,A160 should not be present for Tag 0040,A122") ;
					else if(contains(0x0040,0xA160) && contains(0x0040,0xA123))	
						throw new ConditionFailedException("conditional Element 0040,A160 should not be present for Tag 0040,A123") ;
					else if(contains(0x0040,0xA168) && contains(0x0040,0xA121))
						throw new ConditionFailedException("conditional Element 0040,A168 should not be present for Tag 0040,A121") ;
					else if(contains(0x0040,0xA168) && contains(0x0040,0xA122))
						throw new ConditionFailedException("conditional Element 0040,A168 should not be present for Tag 0040,A122") ;	
					else if(contains(0x0040,0xA168) && contains(0x0040,0xA123)) 
						throw new ConditionFailedException("conditional Element 0040,A168 should not be present for Tag 0040,A123") ;
					else if(contains(0x0040,0xA168) && contains(0x0040,0xA160))
						throw new ConditionFailedException("conditional Element 0040,A168 should not be present for Tag 0040,A160") ;					
					else if(contains(0x0040,0xA168) && contains(0x0040,0xA30A))
						throw new ConditionFailedException("conditional Element 0040,A168 should not be present for Tag 0040,A30A") ;
					else if(contains(0x0040,0xA168) && contains(0x0040,0x08EA))
						throw new ConditionFailedException("conditional Element 0040,A168 should not be present for Tag 0040,08EA") ;
				}
			}
		}
		catch(ConditionFailedException ce)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ce.getMessage());
			}
			throw new InvalidItemException(this.getClass().getSimpleName(),ce); 
		}
		catch( MandatoryMissingException me)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(me.getMessage());
			}
			throw new InvalidItemException(this.getClass().getSimpleName(),me);
		}
		return true;
	}

	/**
	 * 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 setValueType(String strValueType)
	{
		/*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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0040, 0xA040, strValueType,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0040, 0xA040,DicomConstants.DCM_DT_CS, strValueType);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves type of the value encoded in this Item
	 * @return String - Type of the value encoded in this Item
	 */
	public String getValueType()
	{
		Object objValue = getValue(0x0040, 0xA040);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Retrieves pre-initialized object of Concept Name Code 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 ConceptNameCodeSequence - instance of Concept Name Code Sequence. 
	 */
	public ConceptNameCodeSequence getConceptNameCodeSequence()
	{
		ConceptNameCodeSequence objConceptNameCodeSequence = null;
		IDataElement objIDataElement =  getDataForTag(0x0040,0xA043);
		if(objIDataElement != null)
		{
			IDicomValue objIDicomValue = objIDataElement.getDicomValue();
			if(objIDicomValue != null)
				objConceptNameCodeSequence = (ConceptNameCodeSequence)objIDicomValue;
		}
		else
		{
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			int iVRTransferSyntax = objITransferSyntax.getVRTransferSyntax();
			objIDataElement = null;
			objConceptNameCodeSequence = (ConceptNameCodeSequence)objDicomV3Factory.createSequence(0x0040,0xA043, objITransferSyntax, objIDictionaryReader);

			if(iVRTransferSyntax == DicomConstants.DCM_VR_IMPLICIT)
				objIDataElement = new ImplicitDE(0x0040,0xA043, objConceptNameCodeSequence.getValue(),objIDictionaryReader);
			else
				objIDataElement = new ExplicitDE(0x0040,0xA043, DicomConstants.DCM_DT_SQ, objConceptNameCodeSequence.getValue());
			objIDataElement.setTransferSyntax(objITransferSyntax);
			if(objIDataElement != null)
				addDataElement(objIDataElement);
		}
		return objConceptNameCodeSequence;
	}

	/**
	 * Sets References to one or more frames in a Multi-frame SOP Instance. The first frame shall be denoted
	 * as frame number one.
	 * @param arrShReferencedFrameNumbers short Array of one or more frames in a Multi-frame SOP Instance
	 */
	public void setReferencedFrameNumbers(short[] arrShReferencedFrameNumbers)
	{
		/*Accept the Referenced Frame Numbers in Array of 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)	
			objIDataElement = new ImplicitDE(0x0040, 0xA136, arrShReferencedFrameNumbers,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0040, 0xA136,DicomConstants.DCM_DT_US, arrShReferencedFrameNumbers);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves one or more frames in a Multi-frame SOP Instance.
	 * @return short Array - frames in a Multi-frame SOP Instance.
	 */
	public short[] getReferencedFrameNumbers()
	{
		Object objValue = getValue(0x0040, 0xA136);
		if(objValue != null)
			return (short[])objValue;
		return null;
	}

	/**
	 * Sets Numeric Value component of a Name/Value pair 
	 * @param arrStrNumericValue Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043) is a set of one or more numeric values.
	 */
	public void setNumericValue(String[] arrStrNumericValue)
	{
		/*Accept the Numeric Value 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0040, 0xA30A, arrStrNumericValue,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0040, 0xA30A,DicomConstants.DCM_DT_DS, arrStrNumericValue);

		addDataElement(objIDataElement);
	}

	/**
	 * Sets Numeric Value component of a Name/Value pair.
	 * @param strNumericValue String Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043) is a set of one or more numeric values.
	 */
	public void setNumericValue(String strNumericValue)
	{
		/*Accept the Numeric Value 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0040, 0xA30A, strNumericValue,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0040, 0xA30A,DicomConstants.DCM_DT_CS, strNumericValue);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Numeric Value component of a Name/Value pair
	 * @return String Array -  Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043) is a Numeric Value.
	 */
	public String[] getNumericValue()
	{
		if(getDataForTag(0x0040, 0xA30A)!=null)
		{
			if(getDataForTag(0x0040, 0xA30A).getValue()!=null)
			{
				Object objValue = getDataForTag(0x0040, 0xA30A).getValue();
				if(objValue!=null)
				{
					if(objValue instanceof String)
					{
						String strTemp = (String)objValue;
						String[] strArr = new String[1];
						strArr[0] = strTemp;
						return strArr;
					}
					else
						return (String[])objValue;
				}
			}
		}
		return null;
	}
	
	/**
	 * Sets the Floating Point Value.
	 * @param dblArrFloatingPointValue Double value of FloatingPointValue
	 */
	public void setFloatingPointValue(double[] dblArrFloatingPointValue)
	{
		/*Accept the Floating Point Value 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0040,0xA161, dblArrFloatingPointValue,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0040,0xA161,DicomConstants.DCM_DT_FD, dblArrFloatingPointValue);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves the Floating Point Value.
	 * @return double - double value of Floating Point Value
	 */
	public double[] getFloatingPointValue()
	{
		Object objValue = getValue(0x0040,0xA161);
		if(objValue != null)
			return (double[])objValue;
		return null;
	}

	/**
	 * Sets Rational Numerator Value.
	 * @param lArrRationalNumeratorValue Long array of Rational Numerator Value.
	 */
	public void setRationalNumeratorValue(Long[] lArrRationalNumeratorValue)
	{
		/* 
		 * Accept the Rational Numerator Value in String format of type SL.
		 * 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)	
			objIDataElement = new ImplicitDE(0x0040,0xA162, lArrRationalNumeratorValue,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0040,0xA162,DicomConstants.DCM_DT_SL, lArrRationalNumeratorValue);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves the Rational Numerator Value.
	 * @return Long[] - Long array of Rational Numerator Value.
	 */
	public Long[] getRationalNumeratorValue()
	{
		Object objValue = getValue(0x0040,0xA162);
		if(objValue != null)
			return (Long[])objValue;
		return null;
	}
	
	/**
	 * Sets Rational Denominator Value.
	 * @param lArrRationalDenominatorValue Long value ofRational Denominator Value
	 */
	public void setRationalDenominatorValue(long[] lArrRationalDenominatorValue)
	{
		/* Accept the Rational Denominator Value in long format of type UL
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)	
			objIDataElement = new ImplicitDE(0x0040,0xA163, lArrRationalDenominatorValue,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0040,0xA163,DicomConstants.DCM_DT_UL, lArrRationalDenominatorValue);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Rational Denominator Value.
	 * @return long[] - long value of Rational Denominator Value.
	 */
	public long[] getRationalDenominatorValue()
	{
		Object objValue = getValue(0x0040,0xA163);
		if(objValue != null)
			return (long[])objValue;
		return null;
	}
	
	
	/**
	 * Retrieves pre-initialized object of Measurement Units Code 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 MeasurementUnitsCodeSequence - instance of MeasurementUnitsCodeSequence. 
	 */
	public MeasurementUnitsCodeSequence getMeasurementUnitsCodeSequence()
	{
		MeasurementUnitsCodeSequence objMeasurementUnitsCodeSequence = null;
		IDataElement objIDataElement =  getDataForTag(0x0040,0x08EA);
		if(objIDataElement != null)
		{
			IDicomValue objIDicomValue = objIDataElement.getDicomValue();
			if(objIDicomValue != null)
				objMeasurementUnitsCodeSequence = (MeasurementUnitsCodeSequence)objIDicomValue;
		}
		else
		{
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			int iVRTransferSyntax = objITransferSyntax.getVRTransferSyntax();
			objIDataElement = null;
			objMeasurementUnitsCodeSequence = (MeasurementUnitsCodeSequence)objDicomV3Factory.createSequence(0x0040,0x08EA, objITransferSyntax, objIDictionaryReader);

			if(iVRTransferSyntax == DicomConstants.DCM_VR_IMPLICIT)
				objIDataElement = new ImplicitDE(0x0040,0x08EA, objMeasurementUnitsCodeSequence.getValue(),objIDictionaryReader);
			else
				objIDataElement = new ExplicitDE(0x0040,0x08EA, DicomConstants.DCM_DT_SQ, objMeasurementUnitsCodeSequence.getValue());
			objIDataElement.setTransferSyntax(objITransferSyntax);
			if(objIDataElement != null)
				addDataElement(objIDataElement);
		}
		return objMeasurementUnitsCodeSequence;
	}

	/**
	 * Sets Date Value component of Name/Value pair.Required if the value that Concept Name Code
	 * Sequence (0040,A043) requires (implies) is a date. Shall not be present otherwise.
	 * @param strDate String Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043) is a date.
	 */
	public void setDate(String strDate)
	{
		/*Accept the Date 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0040, 0xA121, strDate,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0040, 0xA121,DicomConstants.DCM_DT_DA, strDate);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Date Value component of a Name/Value pair
	 * @return String - Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043) is Date
	 */
	public String getDate()
	{
		Object objValue = getValue(0x0040,0xA121);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets Time value component of a Name/Value pair
	 * @param strTime String Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043)
	 */
	public void setTime(String strTime)
	{
		/*Accept the Time 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0040, 0xA122, strTime,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0040, 0xA122,DicomConstants.DCM_DT_TM, strTime);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Time Value component of a Name/Value pair
	 * @return String - Time Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043) is a time.
	 */
	public String getTime()
	{
		Object objValue = getValue(0x0040,0xA122);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * This method sets Person Name Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043)
	 * @param strPersonName String Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043) is a Person Name.
	 */
	public void setPersonName(String strPersonName)
	{
		/*Accept the Person Name 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0040, 0xA123, strPersonName,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0040, 0xA123,DicomConstants.DCM_DT_PN, strPersonName);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Person Name Value component of a Name/Value pair
	 * @return String - Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043) is a Person Name.
	 */
	public String getPersonName()
	{
		Object objValue = getValue(0x0040,0xA123);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets Text Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043)
	 * @param strTextValue String Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043) is a Text Observation Value.
	 */
	public void setTextValue(String strTextValue)
	{
		/*Accept the Text Value in String format of type UT.
		 * 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0040, 0xA160, strTextValue,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0040, 0xA160,DicomConstants.DCM_DT_UT, strTextValue);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Text Value Component of a Name/Value pair
	 * @return String - Value component of a Name/Value pair when the Concept implied by Concept Name
	 * Code Sequence (0040,A043) is a Text Observation Value.
	 */
	public String getTextValue()
	{
		Object objValue = getValue(0x0040,0xA160);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Retrieves pre-initialized object of Concept Code 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 ConceptCodeSequence - instance of ConceptCodeSequence. 
	 */
	public ConceptCodeSequence getConceptCodeSequence()
	{
		ConceptCodeSequence objConceptCodeSequence = null;
		IDataElement objIDataElement =  getDataForTag(0x0040, 0xA168);
		if(objIDataElement != null)
		{
			IDicomValue objIDicomValue = objIDataElement.getDicomValue();
			if(objIDicomValue != null)
				objConceptCodeSequence = (ConceptCodeSequence)objIDicomValue;
		}
		else
		{
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			int iVRTransferSyntax = objITransferSyntax.getVRTransferSyntax();
			objIDataElement = null;
			objConceptCodeSequence = (ConceptCodeSequence)objDicomV3Factory.createSequence(0x0040,0xA168, objITransferSyntax, objIDictionaryReader);

			if(iVRTransferSyntax == DicomConstants.DCM_VR_IMPLICIT)
				objIDataElement = new ImplicitDE(0x0040,0xA168, objConceptCodeSequence.getValue(),objIDictionaryReader);
			else
				objIDataElement = new ExplicitDE(0x0040,0xA168, DicomConstants.DCM_DT_SQ, objConceptCodeSequence.getValue());
			objIDataElement.setTransferSyntax(objITransferSyntax);
			if(objIDataElement != null)
				addDataElement(objIDataElement);
		}
		return objConceptCodeSequence;
	}
}
