/*******************************************************************************
 *  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.EnumEndingRespiratoryPhase;
import cdac.medinfo.sdk.dcm30_04.enums.EnumRespiratoryMotionCompensation;
import cdac.medinfo.sdk.dcm30_04.enums.EnumRespiratoryTriggerType;
import cdac.medinfo.sdk.dcm30_04.enums.EnumStartingRespiratoryPhase;
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 methods to validate, set and get the attributes ofRespiratory Synchronization Sequence .
 */

public class RespiratorySynchronizationSequenceItem extends Item  
{
	 

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;


		/**
		 * This constructor creates the item and internal code sequence macro with default TransferSyntax 
		 */
		RespiratorySynchronizationSequenceItem()
		{
			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
		 */
		RespiratorySynchronizationSequenceItem(ITransferSyntax objITransferSyntax)
		{
			super(objITransferSyntax);
		}

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

		/**
		 * Measured interval time in ms from maximum respiration peak to the nextpeak for the respiratory cycle in which this frame occurs.
		 * @param dblRespiratoryIntervalTime Double value of coordinates
		 */
		public void setRespiratoryIntervalTime(double dblRespiratoryIntervalTime)
		{
			/*Accept the Respiratory Interval Time 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(0x0020,0x9254, dblRespiratoryIntervalTime,getDictionaryReader());
			else
				objIDataElement = new ExplicitDE(0x0020,0x9254,DicomConstants.DCM_DT_FD, dblRespiratoryIntervalTime);

			addDataElement(objIDataElement);
		}
		/**
		 * Retrieves the Minimal value of Chemical Shift Frequency in ppm.
		 * @return double - double value of ChemicalShiftsMinimumIntegrationLimitOnppm
		 */
		public double getRespiratoryIntervalTime()
		{
			Object objValue = getValue(0x0020,0x9254);
			if(objValue != null)
				return Double.parseDouble(objValue.toString());
			return DicomConstants.DCM_NO_VALUE;
		}

		/**
		 * The nominal time relative to the preceding respiratory inspiration maximumdivided by the nominal respiratory interval multiplied by 100.
		 * Required if used as a dimension index, may be present otherwise.
		 * @param fPresentationPixelMagnificationRatio Float value of the Ratio of displayed pixels to source pixels
		 */
		public void setNominalPercentageOfRespiratoryPhase( float fNominalPercentageOfRespiratoryPhase)
		{
			/*
			 * Accept the NominalPercentageOfRespiratoryPhase 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(0x0020,0x9245, fNominalPercentageOfRespiratoryPhase,getDictionaryReader());
			else
				objIDataElement = new ExplicitDE(0x0020,0x9245,DicomConstants.DCM_DT_FL, fNominalPercentageOfRespiratoryPhase);

			addDataElement(objIDataElement);
		}
		/**
		 * Retrieves the Nominal Percentage Of Respiratory Phase.
		 * @return float - Float value of the Ratio of displayed pixels to source pixels
		 */
		public float getNominalPercentageOfRespiratoryPhase()
		{
			Object objValue = getValue(0x0020,0x9245);
			if(objValue != null)
				return Float.parseFloat(objValue.toString());
			return DicomConstants.DCM_NO_VALUE;
		}
		/**
		 * The nominal time in ms from the beginning of the respiratory interval tothe value of Frame Reference DateTime (0018,9151).
		 * @param dblNominalRespiratoryTriggerDelayTime Double value of coordinates
		 */
		public void setNominalRespiratoryTriggerDelayTime(double dblNominalRespiratoryTriggerDelayTime)
		{
			/*Accept the Nominal Respiratory Trigger Delay Time 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(0x0020,0x9255, dblNominalRespiratoryTriggerDelayTime,getDictionaryReader());
			else
				objIDataElement = new ExplicitDE(0x0020,0x9255,DicomConstants.DCM_DT_FD, dblNominalRespiratoryTriggerDelayTime);

			addDataElement(objIDataElement);
		}
		/**
		 * Retrieves the Nominal Respiratory Trigger Delay Time.
		 * @return double - double value of NominalRespiratoryTriggerDelayTime
		 */
		public double getNominalRespiratoryTriggerDelayTime()
		{
			Object objValue = getValue(0x0020,0x9255);
			if(objValue != null)
				return Double.parseDouble(objValue.toString());
			return DicomConstants.DCM_NO_VALUE;
		}
		/**
		 *The actual time in ms from the beginning of the respiratory interval to thevalue of Frame Reference DateTime (0018,9151).
		 * @param dblActualRespiratoryTriggerDelayTime Double value of coordinates
		 */
		public void setActualRespiratoryTriggerDelayTime(double dblActualRespiratoryTriggerDelayTime)
		{
			/*Accept the Actual Respiratory Trigger Delay Time 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(0x0020,0x9257, dblActualRespiratoryTriggerDelayTime,getDictionaryReader());
			else
				objIDataElement = new ExplicitDE(0x0020,0x9257,DicomConstants.DCM_DT_FD, dblActualRespiratoryTriggerDelayTime);

			addDataElement(objIDataElement);
		}
		/**
		 * Retrieves the Nominal Respiratory Trigger Delay Time.
		 * @return double - double value of NominalRespiratoryTriggerDelayTime
		 */
		public double getActualRespiratoryTriggerDelayTime()
		{
			Object objValue = getValue(0x0020,0x9257);
			if(objValue != null)
				return Double.parseDouble(objValue.toString());
			return DicomConstants.DCM_NO_VALUE;
		}
		/**
		 * Nominal amplitude of the respiratory signal at which the acquisition of datafor this frame begins, in percent of the nominal maximum value (whichrepresents maximum inspiration).
		 * @param fStartingRespiratoryAmplitude Float value of Starting Respiratory Amplitude.
		 */
		public void setStartingRespiratoryAmplitude( float fStartingRespiratoryAmplitude)
		{
			/*
			 * Accept the Starting Respiratory Amplitude 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(0x0020,0x9246, fStartingRespiratoryAmplitude,getDictionaryReader());
			else
				objIDataElement = new ExplicitDE(0x0020,0x9246,DicomConstants.DCM_DT_FL, fStartingRespiratoryAmplitude);

			addDataElement(objIDataElement);
		}
		/**
		 * Retrieves the Starting Respiratory Amplitude.
		 * @return float - Float value of the Ratio of displayed pixels to source pixels
		 */
		public float getStartingRespiratoryAmplitude()
		{
			Object objValue = getValue(0x0020,0x9246);
			if(objValue != null)
				return Float.parseFloat(objValue.toString());
			return DicomConstants.DCM_NO_VALUE;
		}

		/**
		 * The phase of respiration at which the Starting Respiratory Amplitude(0020,9246) was measured.
		 *Enumerated Values:
		 *INSPIRATION
		 *MAXIMUM
		 *EXPIRATION
	  	 *MINIMUM
		 * Required if Starting Respiratory Amplitude (0020,9246) is present.
		 * @param enumStartingRespiratoryPhase enum value of Starting Respiratory Phase.
		 */
		public void setStartingRespiratoryPhase(EnumStartingRespiratoryPhase enumStartingRespiratoryPhase)
		{
			/* Accept the Starting Respiratory Amplitude 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(0x0020,0x9247, enumStartingRespiratoryPhase.getValue(),getDictionaryReader());
			else
				objIDataElement = new ExplicitDE(0x0020,0x9247,DicomConstants.DCM_DT_CS, enumStartingRespiratoryPhase.getValue());

			addDataElement(objIDataElement);


		}

		/**
		 * Return type of Starting Respiratory Phase. 
		 * @return String - value of Setup Device Type.
		 */
		public String getStartingRespiratoryPhase()
		{
			Object objValue = getValue(0x0020,0x9247);
			if(objValue != null)
				return objValue.toString();
			return null;
		}
		/**
		 * Nominal amplitude of the respiratory signal at which the acquisition of datafor this frame begins, in percent of the nominal maximum value (whichrepresents maximum inspiration).
		 * @param fEndingRespiratoryAmplitude Float value of Ending Respiratory Amplitude.
		 */
		public void setEndingRespiratoryAmplitude( float fEndingRespiratoryAmplitude)
		{
			/*
			 * Accept the Ending Respiratory Amplitude 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(0x0020,0x9248, fEndingRespiratoryAmplitude,getDictionaryReader());
			else
				objIDataElement = new ExplicitDE(0x0020,0x9248,DicomConstants.DCM_DT_FL, fEndingRespiratoryAmplitude);

			addDataElement(objIDataElement);
		}
		/**
		 * Retrieves the Starting Respiratory Amplitude.
		 * @return float - Float value of the Ratio of displayed pixels to source pixels
		 */
		public float getEndingRespiratoryAmplitude()
		{
			Object objValue = getValue(0x0020,0x9248);
			if(objValue != null)
				return Float.parseFloat(objValue.toString());
			return DicomConstants.DCM_NO_VALUE;
		}

		/**
		 * The phase of respiration at which the Ending Respiratory Amplitude(0020,9248) was measured.
		 *Enumerated Values:
		 *INSPIRATION
		 *MAXIMUM
		 *EXPIRATION
	  	 *MINIMUM
		 * Required if Starting Respiratory Amplitude (0020,9246) is present.
		 * @param enumEndingRespiratoryPhase enum value of Starting Respiratory Phase.
		 */
		public void setEndingRespiratoryPhase(EnumEndingRespiratoryPhase enumEndingRespiratoryPhase)
		{
			/* Accept the Starting Respiratory Amplitude 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(0x0020,0x9249, enumEndingRespiratoryPhase.getValue(),getDictionaryReader());
			else
				objIDataElement = new ExplicitDE(0x0020,0x9249,DicomConstants.DCM_DT_CS, enumEndingRespiratoryPhase.getValue());

			addDataElement(objIDataElement);


		}

		/**
		 * Return type of Ending Respiratory Phase. 
		 * @return String - value of Setup Device Type.
		 */
		public String getEndingRespiratoryPhase()
		{
			Object objValue = getValue(0x0020,0x9249);
			if(objValue != null)
				return objValue.toString();
			return null;
		}
		/**
		 * Validates all the attributes in CalculatedDoseReferenceSequenceItem  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(0x0020,0x9245))
					throw new MandatoryMissingException("0020,9245");
				if((!getDataForTag(0x0018, 0x9170).getValue().equals(EnumRespiratoryMotionCompensation.NONE)
						||!getDataForTag(0x0018, 0x9170).getValue().equals(EnumRespiratoryMotionCompensation.REALTIME))
						&&((!contains(0x0020,0x9250))
						||(getDataForTag(0x0020,0x9250).getValue().equals(EnumRespiratoryTriggerType.TIME))
						||(getDataForTag(0x0020,0x9250).getValue().equals(EnumRespiratoryTriggerType.BOTH))))
				if(!contains(0x0020,0x9254))
					throw new ConditionFailedException("value of conditional Element (0020,9254) required if (0018,9170)equals other than NONE or REALTIME and (0020,9250) is absent or has a value of TIME or BOTH.") ;
				if((getDataForTag(0x0020,0x9250).getValue().equals(EnumRespiratoryTriggerType.TIME))
						||(getDataForTag(0x0020,0x9250).getValue().equals(EnumRespiratoryTriggerType.BOTH)))
					if(!contains(0x0020,0x9257))
						throw new ConditionFailedException("value of conditional Element (0020,9257) required if (0020,9250) is TIME or BOTH.") ;
				if((getDataForTag(0x0020,0x9250).getValue().equals(EnumRespiratoryTriggerType.AMPLITUDE))
						||(getDataForTag(0x0020,0x9250).getValue().equals(EnumRespiratoryTriggerType.BOTH)))
					if(!contains(0x0020,0x9246))
						throw new ConditionFailedException("value of conditional Element (0020,9246) required if (0020,9250) is AMPLITUDE or BOTH.") ;
				if(!contains(0x0020,0x9246))
					if(!contains(0x0020,0x9247))
						throw new ConditionFailedException("value of conditional Element (0020,9247) required if (0020,9246) is present") ;
				if((getDataForTag(0x0020,0x9250).getValue().equals(EnumRespiratoryTriggerType.AMPLITUDE))
						||(getDataForTag(0x0020,0x9250).getValue().equals(EnumRespiratoryTriggerType.BOTH)))
					if(!contains(0x0020,0x9248))
						throw new ConditionFailedException("value of conditional Element (0020,9248) required if (0020,9250) is AMPLITUDE or BOTH.") ;
				if(!contains(0x0020,0x9248))
					if(!contains(0x0020,0x9249))
						throw new ConditionFailedException("value of conditional Element (0020,9249) required if (0020,9248) is present") ;
				}
			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;
		}
}
