/*******************************************************************************
 *  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.ConceptNameCodeSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.DicomV3Factory;
import cdac.medinfo.sdk.dcm30_04.baselibs.DocumentClassCodeSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.SourceInstanceSequence;
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.EnumBurnedInAnnotation;
import cdac.medinfo.sdk.dcm30_04.enums.EnumRecognizableVisualFeatures;
import cdac.medinfo.sdk.dcm30_04.enums.EnumSetupDeviceType;

import cdac.medinfo.sdk.dcm30_04.enums.EnumVerificationFlag;
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;
/**
 * This Module specifies the Attributes that identify and describe general information about Encapsulated Document.
 * @author saloni
 *
 */
public class EncapsulatedDocumentModule extends Module
{
	/**
	  * The obj single collection.
	  */
	 public static ISingleCollection<ITag> objSingleCollection = null;
		 

		/**
		 * Instantiates a new EncapsulatedDocumentModule
		 * 
		 * @param objIDataSet the obj i data set
		 */
		public EncapsulatedDocumentModule(IDataSet objIDataSet)
		{
			super(objIDataSet);
		}

		static
		{
			objSingleCollection = new SingleCollection<ITag>();
			
			objSingleCollection.add(new Tag(0x0020, 0x0013));
			objSingleCollection.add(new Tag(0x0008, 0x0023));
			objSingleCollection.add(new Tag(0x0008, 0x0033));
			objSingleCollection.add(new Tag(0x0008,0x002A));
			objSingleCollection.add(new Tag(0x0020,0x0062));
			objSingleCollection.add(new Tag(0x0028,0x0301));			
			objSingleCollection.add(new Tag(0x0028,0x0302));
			objSingleCollection.add(new Tag(0x0042,0x0013));
			objSingleCollection.add(new Tag(0x0042,0x0010));			
			objSingleCollection.add(new Tag(0x0040,0xA043));
			objSingleCollection.add(new Tag(0x0040,0xE008));
			objSingleCollection.add(new Tag(0x0040,0xA493));
			objSingleCollection.add(new Tag(0x0040,0xE001));
			objSingleCollection.add(new Tag(0x0042,0x0012));
			objSingleCollection.add(new Tag(0x0042,0x0014));
			objSingleCollection.add(new Tag(0x0042,0x0011));



			

		}

		/**
		 * This method validates each Attribute in the Module according to the Type
		 * of the Attribute.Attributes are of 5 types.
		 * Type 1,Type 2 are Mandatory:
		 * Mandatory Attributes have to present in the Module.
		 * Type 1C,2C are Conditional:
		 * Conditional Attributes' presence depend on a condition.
		 * If the condition is satisfied the Attribute has to be present.
		 * Type 3 are Optional
		 * Optional Attributes can be added as and when required.
		 * 
		 * @return boolean - returns validation status as success or failure
		 * 
		 * @throws InvalidModuleException - If validation of Module fails
		 */	
		public  boolean validateModule() throws InvalidModuleException
		{
			
				try
				{		
					if(!isPresent(0x0008, 0x0023))
					{
						throw new MandatoryMissingException("Missing Mandatory DataElement 0008,0023");
					}
					if(!isPresent(0x0008, 0x0033))
					{
						throw new MandatoryMissingException("Missing Mandatory DataElement 0008,0033");
					}
					if(!isPresent(0x0020, 0x0013))
					{
						throw new MandatoryMissingException("Missing Mandatory DataElement 0020, 0013");
					}
					if(!isPresent(0x0008,0x002A))
					{
						throw new MandatoryMissingException("Missing Mandatory DataElement 0008,002A");
					}
					if(!isPresent(0x0028,0x0301))
					{
						throw new MandatoryMissingException("Missing Mandatory DataElement 0028,0301");
					}
					if(!isPresent(0x0042, 0x0010))
					{
						throw new MandatoryMissingException("Missing Mandatory DataElement 0042,0010");
					}
					if(!isPresent(0x0040, 0xA043))
					{
						throw new MandatoryMissingException("Missing Mandatory DataElement 0040,A043");
					}
					if(!isPresent(0x0042,0x0012))
					{
						throw new MandatoryMissingException("Missing Mandatory DataElement 0042,0012");
					}
					if(!isPresent(0x0042,0x0011))
					{
						throw new MandatoryMissingException("Missing Mandatory DataElement 0042,0011");
					}
					
				
				}
				catch(MandatoryMissingException mme)
				{
					if(DicomConfig.createInstance().isLoggingOn())
						DicomLogger.getLogger().log(mme.getMessage());

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

				}
			return true;
		}
		/**
		 * Sets A number that identifies this SOP Instance. The value shall be unique within a series. 
		 * @param strInstanceNumber String value of Instance Number.
		 */
		public void setInstanceNumber(String strInstanceNumber )
		{
			/*Accept the Instance Number  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 Data Set
			 */
			addDataElement(0x0020, 0x0013, DicomConstants.DCM_DT_IS,strInstanceNumber);
		}
		/**
		 * Retrieves A number that identifies this SOP Instance. The value shall be unique within a series. 
		 * @return String - value of Instance Number.
		 */
		public String getInstanceNumber()
		{
			Object objValue = getValue(0x0020, 0x0013);
			if(objValue != null)
				return objValue.toString();
			return null;
		}
		/**
		 * Sets date the content creation started.
		 * @param strContentDate String value of date the content creation started.
		 */
		public void setContentDate(String strContentDate)
		{
			/* Accept the date the content creation started. 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, 0x0023, DicomConstants.DCM_DT_DA,strContentDate);
		}
		/**
		 * Retrieves date the content creation started.
		 * @return String - value of date the content creation started.
		 */
		public String getContentDate()
		{
			Object objValue = getValue(0x0008, 0x0023);
			if(objValue != null)
				return objValue.toString();
			return null;
		}

		/**
		 * Sets time the content creation started
		 * @param strContentTime String value of time the content creation started
		 */
		public void setContentTime(String strContentTime)
		{
			/* Accept time the content creation started 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,0x0033, DicomConstants.DCM_DT_TM,strContentTime);
		}

		/**
		 * Retrieves time the content creation started
		 * @return String - value of time the content creation started
		 */
		public String getContentTime()
		{
			Object objValue = getValue(0x0008, 0x0033);
			if(objValue != null)
				return objValue.toString();
			return null;
		}
		/**
		 * Sets date and time that the original generation of the data in the document started
		 * @param strAcquisitionDateTime String value of date and time that the original generation of the data in the document started
		 */
		public void setAcquisitionDateTime(String strAcquisitionDateTime)
		{
			/* Accept the Verification DateTime 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(0x0008,0x002A, DicomConstants.DCM_DT_DT,strAcquisitionDateTime);
		}

		/**
		 * Retrieves date and time that the original generation of the data in the document started
		 * @return String - value of date and time that the original generation of the data in the document started
		 */
		public String getAcquisitionDateTime()
		{
			Object objValue = getValue(0x0008,0x002A);
			if(objValue != null)
				return objValue.toString();
			return null;
		}
		/**
		 * Sets Laterality of the (possibly paired) body part that is the subject of the encapsulated document.
		 * @param enumImageLaterality enum value of Image Laterality.
		 */
		public void setImageLaterality(EnumSetupDeviceType enumImageLaterality)
		{
			/* Accept the Image Laterality 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(0x0020,0x0062, DicomConstants.DCM_DT_CS,enumImageLaterality);
		}
		/**
		 * Returns Laterality of the (possibly paired) body part that is the subject of the encapsulated document.
		 * @return String - value of Image Laterality.
		 */
		public String getImageLaterality()
		{
			Object objValue = getValue(0x0020,0x0062);
			if(objValue != null)
				return objValue.toString();
			return null;
		}
		/**
		 * Sets Indicates whether or not the encapsulated document contains sufficient burned in annotation to identify the patient and date the data was acquired.
		 * @param enumBurnedInAnnotation enum value of BurnedInAnnotation
		 */
		public void setBurnedInAnnotation(EnumBurnedInAnnotation enumBurnedInAnnotation)
		{
			/* Accept the BurnedInAnnotation 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,0x0301, DicomConstants.DCM_DT_CS,enumBurnedInAnnotation);
		}
		/**
		 * Returns Indicates whether or not the encapsulated document contains sufficient burned in annotation to identify the patient and date the data was acquired.
		 * @return String - value of BurnedInAnnotation
		 */
		public String getBurnedInAnnotation()
		{
			Object objValue = getValue(0x0028,0x0301);
			if(objValue != null)
				return objValue.toString();
			return null;
		}		
		/**
		 * Sets Indicates whether or not the image contains sufficiently recognizable visual features to allow the image or a reconstruction from a set ofimages to identify the patient.
		 * @param enumRecognizableVisualFeatures enum value of Recognizable VisualFeatures
		 */
		public void setRecognizableVisualFeatures(EnumRecognizableVisualFeatures enumRecognizableVisualFeatures)
		{
			/* Accept the Recognizable VisualFeatures in String format of type CS.
			 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create
			 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
			 * Set the iVRType
			 * Set length from the element
			 * Add this element to the Data Set
			 */
			addDataElement(0x0028,0x0302, DicomConstants.DCM_DT_CS,enumRecognizableVisualFeatures);
		}
		/**
		 * Returns Indicates whether or not the image contains sufficiently recognizable visual features to allow the image or a reconstruction from a set ofimages to identify the patient.
		 * @return String - value of Recognizable VisualFeatures
		 */
		public String getRecognizableVisualFeatures()
		{
			Object objValue = getValue(0x0028,0x0302);
			if(objValue != null)
				return objValue.toString();
			return null;
		}
		/**
		 * Retrieves Source Instance Sequence 
		 * @return - instance of Source Instance Sequence
		 */
		public SourceInstanceSequence getSourceInstanceSequence()
		{
			SourceInstanceSequence objSourceInstanceSequence = (SourceInstanceSequence)getDicomValue(0x0042,0x0013);
			if(objSourceInstanceSequence == 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();
				objSourceInstanceSequence = (SourceInstanceSequence)objDicomV3Factory.createSequence(0x0042,0x0013, objITransferSyntax, objIDictionaryReader);
				
				// This will add Data Element of SQ to the DataSet.
				addDataElement(0x0042,0x0013, DicomConstants.DCM_DT_SQ, objSourceInstanceSequence.getValue());
			}
			return objSourceInstanceSequence;
		}
		/**
		 * Sets the title of the document.
		 * @param strDocumentTitle -title of the document.
		 */
		public void setDocumentTitle(String strDocumentTitle)
		{
			/*Accept the Coding Scheme Name in String format of type ST.
			 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create
			 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
			 * Set the iVRType
			 * Set length from the element
			 * Add this element to the Data Set
			 */
			addDataElement(0x0042,0x0010, DicomConstants.DCM_DT_ST,strDocumentTitle);
		}

		/**
		 * Retrieves the title of the document.
		 * @return String value of title of the document.
		 */
		public String getDocumentTitle()
		{
			Object objValue = getValue(0x0042,0x0010);
			if(objValue != null)
				return objValue.toString();
			return null;
		}
		/**
		 * Retrieves Concept Name CodeSequence
		 * @return - instance of Concept Name CodeSequence
		 */
		public ConceptNameCodeSequence getConceptNameCodeSequence()
		{
			ConceptNameCodeSequence objConceptNameCodeSequence = (ConceptNameCodeSequence)getDicomValue(0x0040,0xA043);
			if(objConceptNameCodeSequence == 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();
				objConceptNameCodeSequence = (ConceptNameCodeSequence)objDicomV3Factory.createSequence(0x0040,0xA043, objITransferSyntax, objIDictionaryReader);
				
				// This will add Data Element of SQ to the DataSet.
				addDataElement(0x0040,0xA043, DicomConstants.DCM_DT_SQ, objConceptNameCodeSequence.getValue());
			}
			return objConceptNameCodeSequence;
		}
		
		/**
		 * Retrieves Document Class Code Sequence
		 * @return - instance of Document Class Code Sequence
		 */
		public DocumentClassCodeSequence getDocumentClassCodeSequence()
		{
			DocumentClassCodeSequence objDocumentClassCodeSequence = (DocumentClassCodeSequence)getDicomValue(0x0040,0xE008);
			if(objDocumentClassCodeSequence == 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();
				objDocumentClassCodeSequence = (DocumentClassCodeSequence)objDicomV3Factory.createSequence(0x0040,0xE008, objITransferSyntax, objIDictionaryReader);
				
				// This will add Data Element of SQ to the DataSet.
				addDataElement(0x0040,0xE008, DicomConstants.DCM_DT_SQ, objDocumentClassCodeSequence.getValue());
			}
			return objDocumentClassCodeSequence;
		}
		
		/**
		 * Sets  whether the Encapsulated Document is Verified
		 * @param enumVerificationFlag enum value of Verification Flag
		 */
		public void setVerificationFlag(EnumVerificationFlag enumVerificationFlag)
		{
			/* Accept the Verification Flag 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(0x0040,0xA493, DicomConstants.DCM_DT_CS,enumVerificationFlag);
		}
		/**
		 * Returns whether the Encapsulated Document is Verified
		 * @return String - value of Verification Flag
		 */
		public String getVerificationFlag()
		{
			Object objValue = getValue(0x0040,0xA493);
			if(objValue != null)
				return objValue.toString();
			return null;
		}
		/**
		 * Sets the Instance Identifier of the encapsulated HL7 Structured Document,encoded as a UID (OID or UUID), concatenated with a caret ("^") andExtension value (if Extension is present in Instance Identifier
		 * @param strHL7InstanceIdentifier -HL7InstanceIdentifier.
		 */
		public void setHL7InstanceIdentifier(String strHL7InstanceIdentifier)
		{
			/*Accept the Coding Scheme Name in String format of type ST.
			 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create
			 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
			 * Set the iVRType
			 * Set length from the element
			 * Add this element to the Data Set
			 */
			addDataElement(0x0040,0xE001, DicomConstants.DCM_DT_ST,strHL7InstanceIdentifier);
		}

		/**
		 * Retrieves the Instance Identifier of the encapsulated HL7 Structured Document,encoded as a UID (OID or UUID), concatenated with a caret ("^") andExtension value (if Extension is present in Instance Identifier
		 * @return String value of HL7InstanceIdentifier.
		 */
		public String getHL7InstanceIdentifier()
		{
			Object objValue = getValue(0x0040,0xE001);
			if(objValue != null)
				return objValue.toString();
			return null;
		}
		/**
		 * Sets MIME Type of EncapsulatedDocument
		 * @param strMIMETypeOfEncapsulatedDocument String value of MIME Type of EncapsulatedDocument
		 */
		public void setMIMETypeOfEncapsulatedDocument(String strMIMETypeOfEncapsulatedDocument)
		{
			/* Accept the MIME Type of EncapsulatedDocument 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(0x0042,0x0012, DicomConstants.DCM_DT_LO,strMIMETypeOfEncapsulatedDocument);
		}

		/**
		 * Return MIME Type of EncapsulatedDocument
		 * @return String - value of MIME Type of EncapsulatedDocument
		 */
		public String getMIMETypeOfEncapsulatedDocument()
		{
			Object objValue = getValue(0x0042,0x0012);
			if(objValue != null)
				return objValue.toString();
			return null;
		}
		/**
		 * Sets List of MIME Types
		 * @param strArrListOfMIMETypes String value o List of MIME Types
		 */
		public void setListOfMIMETypes(String[] strArrListOfMIMETypes)
		{
			/* Accept the List of MIME Types 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(0x0042,0x0014, DicomConstants.DCM_DT_LO,strArrListOfMIMETypes);
		}

		/**
		 * Return List of MIME Types
		 * @return String - value of List of MIME Types
		 */
		public String[] getListOfMIMETypes()
		{
			Object objValue = getValue(0x0042,0x0014);
			if(objValue != null)
				return (String[])objValue;
			return null;
		}
		
		/**
		 * Sets the Encapsulated Document stream,containing a document encoded according to the MIME Type.
		 * @param vectEncapsulatedDocument collection of byte array of Encapsulated Document
		 */
		public void setEncapsulatedDocument(ISingleCollection<byte[]> vectEncapsulatedDocument)
		{
			/*Accept the Signature in vector of byte array format of type OB.
			 * 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(0x0042,0x0011, DicomConstants.DCM_DT_OB,vectEncapsulatedDocument);
		}

		/**
		 * Retrieves the Encapsulated Document stream,containing a document encoded according to the MIME Type.
		 * @return ISingleCollection<byte[]> - collection of byte array of EncapsulatedDocument
		 */
		@SuppressWarnings("unchecked")
		public ISingleCollection<byte[]> getEncapsulatedDocument()
		{
			Object objValue = getValue(0x0042,0x0011);
			if(objValue != null)
				return (ISingleCollection<byte[]>)objValue;
			return null;
		}

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