/*******************************************************************************
 *  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.ContentIdentificationMacro;
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.EnumBitsAllocated;
import cdac.medinfo.sdk.dcm30_04.enums.EnumBitsStored;
import cdac.medinfo.sdk.dcm30_04.enums.EnumBurnedInAnnotation;
import cdac.medinfo.sdk.dcm30_04.enums.EnumContentQualification;
import cdac.medinfo.sdk.dcm30_04.enums.EnumHighBit;
import cdac.medinfo.sdk.dcm30_04.enums.EnumLossyImageCompression;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPhotometricInterpretation;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPresentationLUTShape;
import cdac.medinfo.sdk.dcm30_04.enums.EnumRecognizableVisualFeatures;
import cdac.medinfo.sdk.dcm30_04.enums.EnumSamplesPerPixel;

import cdac.medinfo.sdk.dcm30_04.exceptions.ConditionFailedException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidModuleException;
import cdac.medinfo.sdk.dcm30_04.exceptions.MandatoryMissingException;
import cdac.medinfo.sdk.dcm30_04.exceptions.ValidationException;
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 of Parametric Map Image Module.
 */
public class ParametricMapImageModule extends Module
{
	/**
	 * The obj single collection.
	 */
	public static ISingleCollection<ITag> objSingleCollection = null;

	/**
	 * Instantiates a new ParametricMapImageModule.
	 * 
	 * @param objIDataSet the obj i data set
	 */
	public ParametricMapImageModule(IDataSet objIDataSet)
	{
		super(objIDataSet);
	}
	ContentIdentificationMacro objContentIdentificationMacro=null;
	static
	{
		objSingleCollection = new SingleCollection<ITag>();
		//Data Element Hash Map
		objSingleCollection.add(new Tag(0x0008,0x0008));
		objSingleCollection.add(new Tag(0x0028,0x0002));
		objSingleCollection.add(new Tag(0x0028,0x0004));
		objSingleCollection.add(new Tag(0x0028,0x0100));
		objSingleCollection.add(new Tag(0x0028,0x0101));
		objSingleCollection.add(new Tag(0x0028,0x0102));
		objSingleCollection.add(new Tag(0x2050,0x0020));
		objSingleCollection.add(new Tag(0x0028,0x2110));
		objSingleCollection.add(new Tag(0x0028,0x2112));
		objSingleCollection.add(new Tag(0x0028,0x2114));
		objSingleCollection.add(new Tag(0x0028,0x0301));			
		objSingleCollection.add(new Tag(0x0028,0x0302));
		objSingleCollection.add(new Tag(0x0018,0x9004));			
	
	}

	/**
	 * 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
		{			
			if(!isPresent(0x0008, 0x0008))
				throw new MandatoryMissingException("0008,0008");
			if(!isPresent(0x0028, 0x0002))
				throw new MandatoryMissingException("0028,0002");
			 if(!isPresent(0x0028, 0x0004))
				throw new MandatoryMissingException("0028,0004");
			 if(!isPresent(0x0028, 0x0100))
				throw new MandatoryMissingException("0028,0100");			 
			 if((isPresent(0x7FE0,0x0010)||isPresent(0x0028,0x7FE0))&&(!isPresent(0x0028,0x0101)))
					throw new ConditionFailedException("0028,0101 required if Pixel Data (7FE0,0010) or Pixel Data Provider URL (0028,7FE0)is present.");
			 
			 if((isPresent(0x7FE0,0x0010)||isPresent(0x0028,0x7FE0))&&(!isPresent(0x0028,0x0102)))
					throw new ConditionFailedException("0028,0102 required if Pixel Data (7FE0,0010) or Pixel Data Provider URL (0028,7FE0)is present.");

			 if(!isPresent(0x2050, 0x0020))
					throw new MandatoryMissingException("2050,0020");
			 if(!isPresent(0x0028, 0x2110))
					throw new MandatoryMissingException("0028,2110");
			 if(!isPresent(0x0028, 0x0301))
					throw new MandatoryMissingException("0028,0301");
			 if(!isPresent(0x0028, 0x0302))
					throw new MandatoryMissingException("0028,0302");
			 if(!isPresent(0x0018, 0x9004))
					throw new MandatoryMissingException("0018,9004");
		}
		catch(MandatoryMissingException mme)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(mme.getMessage());

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

		}
		catch(ConditionFailedException ce)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ce.getMessage());
			}
			throw new ValidationException(this.getClass().getSimpleName(),ce); 
		}
		return true;
	}
	/**
	 * This method is used to set Image identification characteristics.
	 * The function accepts a String Value and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module HashMap
	 * 
	 * @param arrStrImageType : Image identification characteristics.
	 */	
	public void setImageType(String[] arrStrImageType)
	{
		/*Accept Image identification characteristics in String Array format of type CS.
		 * Read the Transfer Syntax and check to create ImplicitDE or ExplicitDE .
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Hash Map
		 */
		addDataElement(0x0008, 0x0008, DicomConstants.DCM_DT_CS, arrStrImageType);
	}
	/**
	 * Returns Image identification characteristics.
	 * 
	 * @return String[] - String value of Image type.
	 */
	public String[] getImageType()
	{
		Object objectValue = getValue(0x0008, 0x0008);
		if(objectValue!=null)
			return (String[])objectValue;
		return null;
	}
	 /* Get the Instance of Content Identification Macro related to Content Identification  will be set in Macro
	 * using the setter methods provided in the Macro.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 Content Identification Macro which the user programmer can populate
	 */
	public ContentIdentificationMacro getContentIdentificationMacro()
	{
		if(objContentIdentificationMacro == null)
			objContentIdentificationMacro = new ContentIdentificationMacro(objIDataSet);
		return objContentIdentificationMacro; 
	}
	/**
	 * Samples per Pixel (0028,0002) is the number of separate planes in the image. One, three, and
	 * four image planes are defined. For monochrome (gray scale) and palette color images, the number of planes is 1. For RGB and
	 * other three vector color models, the value of this attribute is 3. For four vector color models, the
	 * value of this attribute is 4.
	 * 
	 * @param enumSamplesPerPixel Number of samples (planes) in this image.
	 */
	public void setSamplesPerPixel(EnumSamplesPerPixel enumSamplesPerPixel)
	{
		/*Accept Number of samples (planes) in this image in short format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0028, 0x0002, DicomConstants.DCM_DT_US, enumSamplesPerPixel.getValue());
	}
	/**
	 * Return the number of separate planes in the image.
	 * 
	 * @return short - Short value of Samples Per Pixel.
	 */
	public short getSamplesPerPixel()
	{Object objectValue = getValue(0x0028, 0x0002);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * The method is used to set Specifies the intended interpretation of the pixel data.
	 * The function accepts a String Value and creates the
	 * DE based on the transfer syntax and populates the DE with right values.
	 * This De is then added to the Module HashMap
	 * 
	 * @param enumPhotometricInterpretation : Enum value of Photometric Interpretation
	 */
	public void setPhotometricInterpretation(EnumPhotometricInterpretation enumPhotometricInterpretation)
	{
		/*Accept Specifies the intended interpretation of the pixel data in String format of type ST.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0028, 0x0004, DicomConstants.DCM_DT_CS, enumPhotometricInterpretation.getValue());
	}	
	/**
	 * Return the intended interpretation of the pixel data.
	 * 
	 * @return String - String value of Photometric Interpretation.
	 */
	public String getPhotometricInterpretation()
	{
		Object objectValue = getValue(0x0028, 0x0004);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}
	/**
	 * Number of bits allocated for each pixel sample. Each sample shall have the same
	 * number of bits allocated.
	 * 
	 * @param enumBitsAllocated Enum value of Bits Allocated.
	 */
	public void setBitsAllocated(EnumBitsAllocated enumBitsAllocated)
	{
		/*Accept bits allocated for each pixel in this image in short format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0028, 0x0100, DicomConstants.DCM_DT_US, enumBitsAllocated.getValue());
	}
	/**
	 * Return Number of bits allocated for each pixel sample.
	 * 
	 * @return short - Short value of Bits Allocated.
	 */
	public short getBitsAllocated()
	{
		Object objectValue = getValue(0x0028, 0x0100);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	
	/**
	 * Number of bits stored for each pixel sample. Each sample shall have the same
	 * number of bits stored.
	 * 
	 * @param enumBitsStored Enum value of Bits Stored.
	 */
	public void setBitsStored(EnumBitsStored enumBitsStored)
	{
		/*Accept bits stored for each pixel in this image in short format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0028, 0x0101, DicomConstants.DCM_DT_US, enumBitsStored.getValue());
	}
	/**
	 * Number of bits stored for each pixel sample.
	 * 
	 * @return short - short value of Bits Stored.
	 */
	public short getBitsStored()
	{
		Object objectValue = getValue(0x0028, 0x0101);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Most significant bit for pixel sample data. Each sample shall have the same high bit.
	 * 
	 * @param enumHighBit Enum value of high bit.
	 */
	public void setHighBit(EnumHighBit enumHighBit)
	{
		/*Accept Most significant bit for pixel in this image in short format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x0028, 0x0102, DicomConstants.DCM_DT_US, enumHighBit.getValue());
	}
	/**
	 * Most significant bit for pixel sample data.
	 * 
	 * @return short - Short value of High Bit.
	 */
	public short getHighBit()
	{
		Object objectValue = getValue(0x0028, 0x0102);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets the PresentationLUTShape
	 * 
	 * @param enumPresentationLUTShape Enum value of PresentationLUTShape
	 */
	public void setPresentationLUTShape(EnumPresentationLUTShape enumPresentationLUTShape)
	{
		/*Accept PresentationLUTShape in short format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Data Set
		 */
		addDataElement(0x2050, 0x0020, DicomConstants.DCM_DT_CS, enumPresentationLUTShape.getValue());
	}
	/**
	 * Retrieves PresentationLUTShape
	 * 
	 * @return short - Short value of PresentationLUTShape
	 */
	public short getPresentationLUTShape()
	{
		Object objectValue = getValue(0x2050, 0x0020);
		if(objectValue!=null)
			return Short.parseShort(objectValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Specifies whether an Image has undergone lossy compression.
	 * Enumerated Values: 00 = Image has NOT been subjected to lossy compression,
	 * 01 = Image has been subjected to lossy compression.
	 * 
	 * @param enumLossyImageCompression Enum value of Lossy Image Compression.
	 */
	public void setLossyImageCompression(EnumLossyImageCompression enumLossyImageCompression)
	{
		/*Accept Specifies whether an Image has undergone lossy compression.
		 * in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Hash Map
		 */
		addDataElement(0x0028, 0x2110, DicomConstants.DCM_DT_CS, enumLossyImageCompression.getValue());
	}
	/**
	 * Return whether an Image has undergone lossy compression.
	 * 
	 * @return String - String value of Lossy Image Compression.
	 */
	public String getLossyImageCompression()
	{
		Object objectValue = getValue(0x0028, 0x2110);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}
	/**
	 * Sets the approximate lossy compression ratio(s) that have been applied to this image.
	 * @param strLossyImageCompressionRatio String value of Lossy ImageCompression Ratio
	 */
	public void setLossyImageCompressionRatio(String[] strLossyImageCompressionRatio)
	{
		/*Accept the Lossy ImageCompression Ratio 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(0x0028, 0x2112, DicomConstants.DCM_DT_DS,strLossyImageCompressionRatio);
	}
	/**
	 * Retrieves the approximate lossy compression ratio(s) that have been applied to this image.
	 * @return String - value of Lossy ImageCompression Ratio
	 */
	public String[] getLossyImageCompressionRatio()
	{
		Object objValue = getValue(0x0028,0x2112);
		if(objValue != null)
			return (String[])objValue;
		return null;
	}
	
	/**
	 * Sets LossyImageCompressionMethod
	 * @param strLossyImageCompressionMethod String Value component of LossyImageCompressionMethod
	 */
	public void setLossyImageCompressionMethod(String strLossyImageCompressionMethod)
	{
		/*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
		 */
		addDataElement(0x0028, 0x2114, DicomConstants.DCM_DT_CS,strLossyImageCompressionMethod);
	}
	/**
	 * Retrieves Numeric Value component of LossyImageCompressionMethod
	 * @return String Array -  Value component of LossyImageCompressionMethod
	 */
	public String[] getLossyImageCompressionMethod()
	{
		Object objectValue = getValue(0x0028,0x2114);
		if(objectValue!=null)
			return (String[])objectValue;
		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;
	}
	/**
	 * Sets ContentQualification
	 * @param enumContentQualification enum value of ContentQualification
	 */
	public void setContentQualification(EnumContentQualification enumContentQualification)
	{
		/* Accept the ContentQualification 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);
	}
	/**
	 * Returns ContentQualification
	 * @return String - value of ContentQualification
	 */
	public String getContentQualification()
	{
		Object objValue = getValue(0x0018,0x9004);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	/**
	 * This method returns the custom collection containing the list of DataElements belonging to the CT
	 * Image Module specified by DICOM Standard.
	 * 
	 * @return - the customized collection containing the dataelement tags
	 * that beling to this module
	 */
	public ISingleCollection<ITag> getVectorOfKeys()
	{
		return objSingleCollection;
	}
}
