/*******************************************************************************
 *  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.EnumRotationDirection;
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 methods used to set,get and validate the attributes in Rotation Information Sequence. 
 */
public class RotationInformationSequenceItem extends Item  
{
	

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/**
	 * This constructor creates the item and internal code sequence macro with default TransferSyntax 
	 * and default DictionaryReader.
	 */
	RotationInformationSequenceItem()
	{
		super();
	}

	/**
	 * This constructor creates the item and internal code sequence macro with default TransferSyntax 
	 * and default DictionaryReader.
	 * @param objITransferSyntax specifies the DICOM Standard defined TransfeSyntax.
	 */
	RotationInformationSequenceItem(ITransferSyntax objITransferSyntax)
	{
		super(objITransferSyntax);
	}

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

	/**
	 * Validates all the attributes in RotationInformationSequenceItem 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(0x0054,0x0200))
				throw new MandatoryMissingException("0x0054,0x0200");
			if(!contains(0x0018,0x1144))
				throw new MandatoryMissingException("0x0018,0x1144");
			if(!contains(0x0018,0x1140))
				throw new MandatoryMissingException("0x0018,0x1140");
			if(!contains(0x0018,0x1143))
				throw new MandatoryMissingException("0x0018,0x1143");
			if(!contains(0x0018,0x1242))
				throw new MandatoryMissingException("0x0018,0x1242");
			if(!contains(0x0054,0x0053))
				throw new MandatoryMissingException("0x0054,0x0053");
			else
			{
				/*(0018,1110)Distance Source to Detector depends upon Image
				 * Type (0008,0008), Value 4,the value should be TRANSMISSION.
				 * Image Type can be retrieved DataSet. How can we access DataSet here!
				 */
			}
		}
		catch(MandatoryMissingException me)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(me.getMessage());
			}
			throw new InvalidItemException(this.getClass().getSimpleName(),me);
		}
		return true;
	}

	/**
	 * Sets position of the detector about the patient for the start of this rotation, in degrees.
	 *  Zero degrees is referenced to the origin at the patient's back. Viewing from the
	 *  patient's feet, angle increases in a counterclockwise direction (detector normal
	 *  rotating from the patient's back towards the patient's left side). Required if a sequence
	 *  Item is present.
	 *  @param strStartAngle String value of Start Angle.
	 */
	public void setStartAngle(String strStartAngle)
	{
		/* Accept the Start Angle 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(0x0054,0x0200, strStartAngle,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0054,0x0200,DicomConstants.DCM_DT_DS, strStartAngle);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves position of the detector about the patient for the start of this rotation, in degrees.
	 * @return String - value of Start Angle.
	 */
	public String getStartAngle()
	{
		Object objValue = getValue(0x0054,0x0200);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets the angular scan arc step between views of the TOMO acquisition, in degrees.
	 * @param strAngularStep String value of Angular Step.
	 */
	public void setAngularStep(String strAngularStep)
	{
		/* Accept the Angular Step 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,0x1144, strAngularStep,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0018,0x1144,DicomConstants.DCM_DT_DS, strAngularStep);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves the angular scan arc step between views of the TOMO acquisition, in degrees.
	 * @return String - value of Angular Step.
	 */
	public String getAngularStep()
	{
		Object objValue = getValue(0x0018,0x1144);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets direction of rotation of the detector about the patient. See Start Angle (0054,0200)
	 * for further explanation of direction. Enumerated Values: CW = clockwise (decreasing angle),
	 * CC = counter-clockwise (increasing angle).
	 * @param enumRotationDirection enum value of direction of rotation of the detector about the patient.
	 */
	public void setRotationDirection(EnumRotationDirection enumRotationDirection)
	{
		/* Accept the Rotation Direction 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,0x1140, enumRotationDirection.getValue(),objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0018,0x1140,DicomConstants.DCM_DT_DS, enumRotationDirection.getValue());

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves direction of rotation of the detector about the patient.
	 * @return String - value of Rotation Direction.
	 */
	public String getRotationDirection()
	{
		Object objValue = getValue(0x0018,0x1140);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets the effective angular range of the scan data in degrees. The value shall be
	 * positive. Required if a sequence Item is present.
	 * @param strScanArc String value of Scan Arc.
	 */
	public void setScanArc(String strScanArc)
	{
		/* Accept the Scan Arc 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,0x1143, strScanArc,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0018,0x1143,DicomConstants.DCM_DT_DS, strScanArc);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves effective angular range of the scan data in degrees.
	 * @return String - value of Scan Arc.
	 */
	public String getScanArc()
	{
		Object objValue = getValue(0x0018,0x1143);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets nominal acquisition time per angular position, in msec.
	 * @param strActualFrameDuration String value of Actual Frame Duration.
	 */
	public void setActualFrameDuration(String strActualFrameDuration)
	{
		/* Accept the Actual Frame Duration 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0018,0x1242, strActualFrameDuration,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0018,0x1242,DicomConstants.DCM_DT_IS, strActualFrameDuration);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves nominal acquisition time per angular position, in msec.
	 * @return String - value of Actual Frame Duration.
	 */
	public String getActualFrameDuration()
	{
		Object objValue = getValue(0x0018,0x1242);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets Radial distance of the detector from the center of rotation, in mm. It shall
	 * have a single value which is an average value for this rotation, or it shall have one
	 * value per angular view.
	 * @param arrStrRadialPosition String array of Radial Position.
	 */
	public void setRadialPosition(String[] arrStrRadialPosition)
	{
		/* Accept the Radial Position 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0018,0x1142, arrStrRadialPosition,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0018,0x1142,DicomConstants.DCM_DT_DS, arrStrRadialPosition);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves radial distance of the detector from the center of rotation, in mm.
	 * @return String[] - String array of Radial Position.
	 */
	public String[] getRadialPosition()
	{
		Object objValue = getValue(0x0018,0x1142);
		if(objValue != null)
			return (String[])objValue;
		return null;
	}

	/**
	 * Sets Distance in mm from transmission source to the detector face. Required if Image
	 * Type (0008,0008), Value 4, is TRANSMISSION and a sequence Item is present.
	 * @param arrStrRadialPosition String array of Distance from Source to Detector.
	 */
	public void setDistanceSourceToDetector(String[] arrStrRadialPosition)
	{
		/* Accept the Distance Source to Detector in String Array 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)	
			objIDataElement = new ImplicitDE(0x0018,0x1110, arrStrRadialPosition,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0018,0x1110,DicomConstants.DCM_DT_DS, arrStrRadialPosition);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves distance in mm from transmission source to the detector face.
	 * @return String - array of Distance from Source to Detector.
	 */
	public String[] getDistanceSourceToDetector()
	{
		Object objValue = getValue(0x0018,0x1110);
		if(objValue != null)
			return (String[])objValue;
		return null;
	}

	/**
	 * Sets number of angular views in this rotation. Required if a sequence Item is present.
	 * @param shNumberOfFramesInRotation short value of  Number Of Frames in Rotation.
	 */
	public void setNumberOfFramesInRotation(short shNumberOfFramesInRotation)
	{
		/* Accept the Number Of Frames In Rotation in String 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(0x0054, 0x0053, shNumberOfFramesInRotation,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0054, 0x0053,DicomConstants.DCM_DT_US, shNumberOfFramesInRotation);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Number of angular views in this rotation.
	 * @return short - short value of Number Of Frames in Rotation.
	 */
	public short getNumberOfFramesInRotation()
	{
		Object objValue = getValue(0x0054, 0x0053);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets location of the patient table (or gantry relative to the table) in mm.The range and
	 * values of this element are determined by the manufacturer.
	 * @param strTableTraverse String value of Table Traverse.
	 */
	public void setTableTraverse(String strTableTraverse)
	{
		/* Accept the Number Of Frames In Rotation in String 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(0x0018,0x1131, strTableTraverse,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0018,0x1131,DicomConstants.DCM_DT_DS, strTableTraverse);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves location of the patient table (or gantry relative to the table) in mm.
	 * @return String - value of Table Traverse.
	 */
	public String getTableTraverse()
	{
		Object objValue = getValue(0x0018,0x1131);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets the distance in mm of the top of the patient table to the center of rotation. Table
	 * height below the center of rotation has a positive value.
	 * @param strTableHeight String value of Table Height.
	 */
	public void setTableHeight(String strTableHeight)
	{
		/* Accept the Table Height 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,0x1130, strTableHeight,objIDictionaryReader);
		else
			objIDataElement = new ExplicitDE(0x0018,0x1130,DicomConstants.DCM_DT_DS, strTableHeight);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves distance in mm of the top of the patient table to the center of rotation.
	 * @return String - value of Table Height.
	 */
	public String getTableHeight()
	{
		Object objValue = getValue(0x0018,0x1130);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
}
