/*******************************************************************************
 *  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.IItem;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITransferSyntax;
import cdac.medinfo.sdk.dcm30_04.enums.EnumCardiacCyclePosition;
import cdac.medinfo.sdk.dcm30_04.enums.EnumFrameType;
import cdac.medinfo.sdk.dcm30_04.enums.EnumRespiratoryCyclePosition;
import cdac.medinfo.sdk.dcm30_04.exceptions.ConditionFailedException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidItemException;
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.ICollectionIterator;


/***
* This item class contains methods to validate,set and get the attributes in {@link FrameContentSequence }.
 */

public class FrameContentSequenceItem extends Item
{
	

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

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

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


	/**
	 * Validates all the attributes in FrameContentSequenceItem that are present in the DataSet
	 * @return boolean - Success -true, Failure - false
	 * @throws InvalidItemException throws InvalidItemException If Conditional element fails.
	 */
	public boolean validateForModule()  throws InvalidItemException
	{
		try
		{
			super.validateForModule();
			/*
			 * Validation Rules for Conditonal Elements
			 */
			if(getValue(0x0008,0x9007) != null)
			{
				String strFrameType = (String)getValue(0x0008,0x9007);
				if((strFrameType == EnumFrameType.Value1.ORIGINAL.toString()) && !contains(0x0018,0x9151))
					throw new ConditionFailedException("0018,9151");
				if((strFrameType == EnumFrameType.Value1.ORIGINAL.toString()) && !contains(0x0018,0x9074))
					throw new ConditionFailedException("0018,9074");
				if((strFrameType == EnumFrameType.Value1.ORIGINAL.toString()) && !contains(0x0018,0x9220))
					throw new ConditionFailedException("0018,9220");
			}
			
			if(contains(0x0020,0x9222))
			{
				DimensionIndexSequence objDimensionIndexSequence = (DimensionIndexSequence)getValue(0x0020,0x9222);
				ICollectionIterator<IItem> objCollectionIterator = objDimensionIndexSequence.iterator();
				if(!objCollectionIterator.hasNext())
					throw new ConditionFailedException("0020,9157");
			}
			if(contains(0x0020,0x9056) && !contains(0x0020,0x9057))
			{
				throw new ConditionFailedException("0020,9057");
			}
		}
		catch( ConditionFailedException cfe)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(cfe.getMessage());
			}
			throw new InvalidItemException(this.getClass().getSimpleName(),cfe);
		}
		return true;
	}

	/**
	 * Sets Frame Acquisition Number.Uniquely identifies Frame Acquisition Number(0020,9156) in Frame Content Sequence(0020,9111).
	 * @param shFrameAcquisitionNumber Unsigned Short value of Frame Acquisition Number.
	 */
	public void setFrameAcquisitionNumber(short shFrameAcquisitionNumber)
	{
		/*Accept the FrameAcquisitionNumber in Unsigned 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)	
			objIDataElement = new ImplicitDE(0x0020,0x9156, shFrameAcquisitionNumber,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0020,0x9156,DicomConstants.DCM_DT_US, shFrameAcquisitionNumber);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Control Point Index.
	 * @return String - value of Control Point Index.
	 */
	public short getFrameAcquisitionNumber()
	{
		Object objValue = getValue(0x300A,0x0112);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}


	/**
	 * Sets Frame Reference Datetime.Uniquely identifies Frame Reference Datetime(0018,9151) in Frame Content Sequence(0020,9111).
	 * @param strFrameReferenceDatetime String value of Frame Reference Datetime.
	 */
	public void setFrameReferenceDatetime(String strFrameReferenceDatetime)
	{
		/*Accept the FrameReferenceDatetime in String format 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0018,0x9151, strFrameReferenceDatetime,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x9151,DicomConstants.DCM_DT_DT, strFrameReferenceDatetime);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Frame Reference Datetime.
	 * @return String - value of Frame Reference Datetime.
	 */
	public String getFrameReferenceDatetime()
	{
		Object objValue = getValue(0x0018,0x9151);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets Frame Acquisition Datetime.Uniquely identifies Frame Acquisition Datetime(0018,9074) in Frame Content Sequence(0020,9111).
	 * @param strFrameAcquisitionDatetime String value of Frame Acquisition Datetime.
	 */
	public void setFrameAcquisitionDatetime(String strFrameAcquisitionDatetime)
	{
		/*Accept the FrameAcquisitionDatetime in String format 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(0x0018,0x9074, strFrameAcquisitionDatetime,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x9074,DicomConstants.DCM_DT_DT, strFrameAcquisitionDatetime);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Frame Acquisition Datetime.
	 * @return String - value of Frame Acquisition Datetime.
	 */
	public String getFrameAcquisitionDatetime()
	{
		Object objValue = getValue(0x0018,0x9074);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	
	/**
	 * Sets Frame Acquisition Duration.Uniquely identifies Frame Acquisition Duration(0018,9220) in Frame Content Sequence(0020,9111).
	 * @param flFrameAcquisitionDuration double value of Frame Acquisition Duration.
	 */
	public void setFrameAcquisitionDuration(double flFrameAcquisitionDuration)
	{
		/*Accept the FrameAcquisitionDuration in String 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(0x0018,0x9220, flFrameAcquisitionDuration,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x9220,DicomConstants.DCM_DT_FD, flFrameAcquisitionDuration);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Frame Acquisition Duration.
	 * @return String - value of Frame Acquisition Duration.
	 */
	public double getFrameAcquisitionDuration()
	{
		Object objValue = getValue(0x0018,0x9220);
		if(objValue != null)
			return Double.parseDouble(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	
	/**
	 * Sets Cardiac Cycle Position.Uniquely identifies Cardiac Cycle Position(0018,9220) in Frame Content Sequence(0020,9111).
	 * @param enumCardiacCyclePosition Enum value of Cardiac Cycle Position.
	 */
	public void setCardiacCyclePosition(EnumCardiacCyclePosition enumCardiacCyclePosition)
	{
		/*Accept the CardiacCyclePosition 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(0x0018,0x9236, enumCardiacCyclePosition,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x9236,DicomConstants.DCM_DT_CS, enumCardiacCyclePosition);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Cardiac Cycle Position.
	 * @return String - value of Cardiac Cycle Position.
	 */
	public String getCardiacCyclePosition()
	{
		Object objValue = getValue(0x0018,0x9236);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	
	/**
	 * Sets Respiratory Cycle Position.Uniquely identifies Respiratory Cycle Position(0018,9214) in Frame Content Sequence(0020,9111).
	 * @param enumRespiratoryCyclePosition enum value of Respiratory Cycle Position.
	 */
	public void setRespiratoryCyclePosition(EnumRespiratoryCyclePosition enumRespiratoryCyclePosition)
	{
		/*Accept the RespiratoryCyclePosition 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(0x0018,0x9214, enumRespiratoryCyclePosition,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x9214,DicomConstants.DCM_DT_CS, enumRespiratoryCyclePosition);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Respiratory Cycle Position.
	 * @return String - value of Respiratory Cycle Position.
	 */
	public String getRespiratoryCyclePosition()
	{
		Object objValue = getValue(0x0018,0x9214);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	
	/**
	 * Sets Dimension Index Values.Uniquely identifies Dimension Index Values(0020,9157) in Frame Content Sequence(0020,9111).
	 * @param intDimensionIndexValues int array value of Dimension Index Values.
	 */
	public void setDimensionIndexValues(int[] intDimensionIndexValues)
	{
		/*Accept the Dimension Index Values in String format of type UL.
		 * 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,0x9157, intDimensionIndexValues,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x9157,DicomConstants.DCM_DT_UL, intDimensionIndexValues);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Dimension Index Values.
	 * @return int[] - value of Dimension Index Values.
	 */
	public int[] getDimensionIndexValues()
	{
		Object objValue = getValue(0x0018,0x9157);
		if(objValue != null)
			return (int[])objValue;
		return null;
	}

	
	/**
	 * Sets Temporal Position Index.Uniquely identifies Temporal Position Index(0020,9128) in Frame Content Sequence(0020,9111).
	 * @param intTemporalPositionIndex string value of Temporal Position Index.
	 */
	public void setTemporalPositionIndex(int intTemporalPositionIndex)
	{
		/*Accept the Temporal Position Index in String format of type UL.
		 * 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,0x9128, intTemporalPositionIndex,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x9128,DicomConstants.DCM_DT_UL, intTemporalPositionIndex);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Temporal Position Index.
	 * @return String - value of Temporal Position Index.
	 */
	public int getTemporalPositionIndex()
	{
		Object objValue = getValue(0x0018,0x9128);
		if(objValue != null)
			return Integer.parseInt(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	
	/**
	 * Sets Stack ID.Uniquely identifies Stack ID(0020,9128) in Frame Content Sequence(0020,9056).
	 * @param shStackID string value of Stack ID.
	 */
	public void setStackID(short shStackID)
	{
		/*Accept the Stack ID in String format of type SH.
		 * 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,0x9056, shStackID,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x9056,DicomConstants.DCM_DT_SH, shStackID);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Stack ID.
	 * @return String - value of Stack ID.
	 */
	public short getStackID()
	{
		Object objValue = getValue(0x0018,0x9056);
		if(objValue != null)
			return Short.parseShort(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}
	
	/**
	 * Sets In-Stack Position Number.Uniquely identifies In-Stack Position Number(0020,9057) in Frame Content Sequence(0020,9111).
	 * @param intIn-StackPositionNumber string value of In-Stack Position Number.
	 */
	public void setInStackPositionNumber(int intInStackPositionNumber)
	{
		/*Accept the In-Stack Position Number in String format of type UL.
		 * 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,0x9057, intInStackPositionNumber,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0018,0x9057,DicomConstants.DCM_DT_UL, intInStackPositionNumber);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves In-Stack Position Number.
	 * @return String - value of In-Stack Position Number.
	 */
	public int getInStackPositionNumber()
	{
		Object objValue = getValue(0x0018,0x9057);
		if(objValue != null)
			return Integer.parseInt(objValue.toString());
		return DicomConstants.DCM_NO_VALUE;
	}

	/**
	 * Sets Frame Comments.Uniquely identifies Frame Comments(0020,9158) in Frame Content Sequence(0020,9111).
	 * @param strFrameComments string value of Frame Comments.
	 */
	public void setFrameComments(String strFrameComments)
	{
		/*Accept the FrameComments in String format of type LT.
		 * 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,0x9158, strFrameComments,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x0020,0x9158,DicomConstants.DCM_DT_LT, strFrameComments);

		addDataElement(objIDataElement);
	}
	/**
	 * Retrieves Frame Comments.
	 * @return String - value of Frame Comments.
	 */
	public String getFrameComments()
	{
		Object objValue = getValue(0x0020,0x9158);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
}
