/*******************************************************************************
 *  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.IDictionaryReader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITransferSyntax;
import cdac.medinfo.sdk.dcm30_04.enums.EnumGeometricalProperties;
import cdac.medinfo.sdk.dcm30_04.enums.EnumImageProcessingApplied;
import cdac.medinfo.sdk.dcm30_04.enums.EnumImageType;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPixelIntensityRelationshipSign;
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 class contains the methods to set, get and validate the attribute present in  Frame Pixel Data Properties Sequence.
 */

public class FramePixelDataPropertiesSequenceItem extends Item
{


	private static final long serialVersionUID = 1L;

	/**
	 * This constructor creates the item and internal code sequence macro with default TransferSyntax 
	 */
	FramePixelDataPropertiesSequenceItem()
	{
		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.
	 * @param objTransferSyntax specifies the DICOM Standard defined TransfeSyntax 
	 */
	FramePixelDataPropertiesSequenceItem(ITransferSyntax objITransferSyntax)
	{
		super(objITransferSyntax);
	}

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

	/**
	 * Validates all the attributes in FieldOfViewSequenceItem that are present in the DataSet
	 * @return boolean - Success -true, Failure - false
	 * @throws InvalidItemException throws InvalidItemException If Mandatory or Conditional element fails.
	 */
	public boolean validateForModule()  throws InvalidItemException
	{
		try{
		    if(!contains(0x0008,0x9007))
				throw new MandatoryMissingException("0008,9007");
			if(!contains(0x0028,0x1040))
				throw new MandatoryMissingException("0028,1040");
			if(!contains(0x0028,0x1041))
				throw new MandatoryMissingException("0028,1041");
			if(!contains(0x0028,0x9444))
				throw new MandatoryMissingException("0028,9444");
			if(!contains(0x0028,0x9446))
				throw new MandatoryMissingException("0028,9446");
			if((getDataForTag(0x0008, 0x0008).getValue().toString().equals(EnumImageType.Value1.ORIGINAL)))
				if(!contains(0x0018, 0x1164))
					throw new ConditionFailedException("value for conditional Element 0x0018, 0x1164 required if value of Image Type (0008,0008) Value 1 equals ORIGINAL.");
			if((getDataForTag(0x0028, 0x9444).getValue().toString().equals(EnumGeometricalProperties.NON_UNIFORM)))
				if(!contains(0x0028, 0x9445))
					throw new ConditionFailedException("value for conditional Element 0x0028, 0x9445 required if value of Geometrical Properties (0028,9444) equals NON_UNIFORM");

			}
		catch(MandatoryMissingException mme)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(mme.getMessage());
			}
			throw new InvalidItemException(this.getClass().getSimpleName(),mme);
		}
		catch( ConditionFailedException cfe)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(cfe.getMessage());
			}
			throw new InvalidItemException(this.getClass().getSimpleName(),cfe);
		}
		return true;
	}
	/**
	 * Sets Type of Frame. A multi-valued attribute analogous to Image Type (0008,0008)
	 * @param strFrameType String Value of Frame Type
	 */
	public void setFrameType(String strFrameType)
	{
		/*Accept the Frame 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(0x0008, 0x9007, strFrameType,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0008, 0x9007,DicomConstants.DCM_DT_CS, strFrameType);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Type of Frame. A multi-valued attribute analogous to Image Type (0008,0008)
	 * @return String Array -  Value of Frame Type
	 */
	public String[] getFrameType()
	{
		if(getDataForTag(0x0008, 0x9007)!=null)
		{
			if(getDataForTag(0x0008, 0x9007).getValue()!=null)
			{
				Object objValue = getDataForTag(0x0008, 0x9007).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 relationship between the Pixel and the X-Ray beam intensity.
	 * @param strPixelIntensityRelationship Specifies Pixel IntensityRelationship encoded in this Item
	 */
	public void setPixelIntensityRelationship(String strPixelIntensityRelationship)
	{
		/*Accept the Pixel IntensityRelationship 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(0x0028, 0x1040, strPixelIntensityRelationship,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0028, 0x1040,DicomConstants.DCM_DT_CS, strPixelIntensityRelationship);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves the relationship between the Pixel and the X-Ray beam intensity.
	 * @return String - value of Pixel Intensity Relationship
	 */
	public String getPixelIntensityRelationship()
	{
		Object objValue = getValue(0x0028, 0x1040);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	/**
	 * Sets the sign of the relationship between the Pixel sample values stored in PixelData (7FE0,0010) and the X-Ray beam intensity.
	 *Enumerated Values:
	 *1		Lower pixel values correspond to less X-Ray beam intensity
	 *-1	Higher pixel values correspond to less X-Ray beam intensity
	 * @param enumPixelIntensityRelationshipSign enum value of Setup Device Type.
	 */
	public void setPixelIntensityRelationshipSign(EnumPixelIntensityRelationshipSign enumPixelIntensityRelationshipSign)
	{
		/* Accept the Pixel IntensityRelationship Sign 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(0x0028,0x1041, enumPixelIntensityRelationshipSign.getValue(),getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0028,0x1041,DicomConstants.DCM_DT_CS, enumPixelIntensityRelationshipSign.getValue());

		addDataElement(objIDataElement);
	}
	/**
	 * Return Pixel IntensityRelationship Sign. 
	 * @return String - value of Pixel IntensityRelationship Sign.
	 */
	public String getPixelIntensityRelationshipSign()
	{
		Object objValue = getValue(0x0028,0x1041);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	/**
	 * Sets Physical distance measured at the receptor plane of the detector between thecenters of each pixel specified by a numeric pair - row spacing value (delimiter)column spacing value in mm.
	 * @param strImagerPixelSpacing String value of Imager Pixel Spacing.
	 */
	public void setImagerPixelSpacing(String[] strImagerPixelSpacing)
	{
		/*Accept the Imager Pixel Spacing 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(0x0018,0x1164, strImagerPixelSpacing,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x1164,DicomConstants.DCM_DT_DS, strImagerPixelSpacing);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Physical distance measured at the receptor plane of the detector between thecenters of each pixel specified by a numeric pair - row spacing value (delimiter)column spacing value in mm.
	 * @return String - value of Imager Pixel Spacing.
	 */
	public String[] getImagerPixelSpacing()
	{
		Object objValue = getValue(0x0018,0x1164);
		if(objValue != null)
			return (String[])objValue;
		return null;
	}
	/**
	 * Sets Offset of the TLHC of the image stored in Pixel Data (7FE0,0010) from theTLHC of the Field Of View Area after FOV rotation and Flip. It is measured inimage stored pixels as a row offset followed by a column offset.
	 * @param arrFPixelDataAreaOriginRelativeToFOV pair of floating point numbers
	 */
	public void setPixelDataAreaOriginRelativeToFOV(float[] arrFPixelDataAreaOriginRelativeToFOV)
	{
		/* Accept the PixelDataAreaOriginRelativeToFOVin short format of type FL.
		 * 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(0x0018,0x7036, arrFPixelDataAreaOriginRelativeToFOV,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x7036,DicomConstants.DCM_DT_FL, arrFPixelDataAreaOriginRelativeToFOV);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Offset of the TLHC of the image stored in Pixel Data (7FE0,0010) from theTLHC of the Field Of View Area after FOV rotation and Flip. It is measured inimage stored pixels as a row offset followed by a column offset.
	 * @return float[] - Float array of PixelDataAreaOriginRelativeToFOV.
	 */
	public float[] getPixelDataAreaOriginRelativeToFOV()
	{
		Object objValue = getValue(0x0018,0x7036);
		if(objValue != null)
			return (float[])objValue;
		return null;
	}

	/**
	 * Sets the Angle clockwise of the row direction of the image stored in Pixel Data(7FE0,0010) relative to the row direction of the Field Of View Area after FOVrotation and Flip. It is measured in degrees.
	 * @param fPixelDataAreaRotationAngleRelativeToFOV Float value of the Pixel Data Area RotationAngle Relative To FOV
	 */
	public void setPixelDataAreaRotationAngleRelativeToFOV( float fPixelDataAreaRotationAngleRelativeToFOV)
	{
		/*
		 * Accept the Pixel Data Area RotationAngle Relative To FOV in String format of type FL.
		 * 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(0x0018,0x7038, fPixelDataAreaRotationAngleRelativeToFOV,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x7038,DicomConstants.DCM_DT_FL, fPixelDataAreaRotationAngleRelativeToFOV);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves the Angle clockwise of the row direction of the image stored in Pixel Data(7FE0,0010) relative to the row direction of the Field Of View Area after FOVrotation and Flip. It is measured in degrees.
	 * @return float - Float value of the Pixel Data Area RotationAngle Relative To FOV
	 */
	public float getPixelDataAreaRotationAngleRelativeToFOV()
	{
		Object objValue = getValue(0x0018,0x7038);
		if(objValue != null)
			return Float.parseFloat(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	 * Sets Geometrical characteristics of the pixel data to indicate whether pixel spacingis uniform for all pixels or not.
	 *Enumerated Values:
	 *UNIFORM
	 *NON_UNIFORM
	 * @param enumGeometricalProperties enum value of GeometricalProperties.
	 */
	public void setGeometricalProperties(EnumGeometricalProperties enumGeometricalProperties)
	{
		/* Accept the GeometricalProperties 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(0x0028,0x9444, enumGeometricalProperties.getValue(),getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0028,0x9444,DicomConstants.DCM_DT_CS, enumGeometricalProperties.getValue());

		addDataElement(objIDataElement);


	}

	/**
	 * Return Geometrical Properties.
	 * @return String - value of Geometrical Properties.
	 */
	public String getGeometricalProperties()
	{
		Object objValue = getValue(0x0028,0x9444);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets the percentage of the maximum deviation of the pixel spacing values of imagesfor which the geometric properties are non-uniform.
	 * @param fGeometricMaximumDistortion Float value of Geometric MaximumDistortion
	 */
	public void setGeometricMaximumDistortion( float fGeometricMaximumDistortion)
	{
		/*
		 * Accept the Geometric MaximumDistortion in String format of type FL.
		 * 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(0x0028,0x9445, fGeometricMaximumDistortion,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0028,0x9445,DicomConstants.DCM_DT_FL, fGeometricMaximumDistortion);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves the percentage of the maximum deviation of the pixel spacing values of imagesfor which the geometric properties are non-uniform.
	 * @return float - Float value of the Geometric MaximumDistortion
	 */
	public float getGeometricMaximumDistortion()
	{
		Object objValue = getValue(0x0028,0x9445);
		if(objValue != null)
			return Float.parseFloat(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	/**
	* Sets the type or a combination of types of image processing applied to the pixeldata before being stored.
	*Defined Terms:
	*DIGITAL_SUBTR
	*HIGH_PASS_FILTER
	*LOW_PASS_FILTER
	*MULTI_BAND_FLTR
	*FRAME_AVERAGING
	*NONE
	 * @param enumImageProcessingApplied enum value of Image ProcessingApplied
	 */
	public void setImageProcessingApplied(EnumImageProcessingApplied enumImageProcessingApplied)
	{
		/* Accept the Setup Device 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(0x0028,0x9446, enumImageProcessingApplied.getValue(),getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0028,0x9446,DicomConstants.DCM_DT_CS, enumImageProcessingApplied.getValue());

		addDataElement(objIDataElement);
	}
	/**
	 * Return Image ProcessingApplied.
	 * @return String - value of Image ProcessingApplied.
	 */
	public String getImageProcessingApplied()
	{
		Object objValue = getValue(0x0028,0x9446);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

}
