/*******************************************************************************
 *  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.exceptions.ConditionFailedException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidItemException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidMacroException;
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 attributes of {@link BlockSequenceItem}.
 */
public class BlockSequenceItem extends Item  
{
	


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

	/**
	 * This constructor creates the item and internal code sequence macro with default TransferSyntax 
	 */
	BlockSequenceItem()
	{
		super();
	}

	/**
	 * This constructor creates the item and internal code sequence macro with specified TS
	 * @param objTransferSyntax specifies the DICOM Standard defined TransfeSyntax 
	 */
	BlockSequenceItem(ITransferSyntax objITransferSyntax)
	{
		super(objITransferSyntax);
	}

	/**
	 * This constructor creates the item and internal code sequence macro with default TransferSyntax 
	 * and default DictionaryReader
	 * @param objTransferSyntax specifies the DICOM Standard defined TransfeSyntax
	 * @param objDictionaryReader specifies the DICOM Dictionary reader to be used 
	 */
	BlockSequenceItem(ITransferSyntax objTransferSyntax, IDictionaryReader objDictionaryReader)
	{
		super(objTransferSyntax,objDictionaryReader);
	}

	/**
	 * Validates all the attributes in {@link BlockSequenceItem} 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
		{
			super.validateForModule();

			
			// 300A,00F8 conditional element with mandatory like condition.
			if(!contains(0x300A,0x00F8))
				throw new MandatoryMissingException("300A,00F8");
			
			// 300A,00FC conditional element with mandatory like condition.
			if(!contains(0x300A,0x00FC))
				throw new MandatoryMissingException("300A,00FC");
			
		}
		catch( MandatoryMissingException mme)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(mme.getMessage());
			}
			throw new InvalidItemException(this.getClass().getSimpleName(),mme);
		}
		catch( InvalidMacroException ime)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ime.getMessage());
			}
			throw new InvalidItemException(this.getClass().getSimpleName(),ime);
		}
		catch( ConditionFailedException ce)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(ce.getMessage());
			}
			throw new InvalidItemException(this.getClass().getSimpleName(),ce); 
		}
		return true;
	}

	/**
	 * Sets user-supplied identifier for block tray.
	 * @param strBlockTrayID -String value of Block Tray ID.
	 */
	public void setBlockTrayID(String strBlockTrayID)
	{
		/* Accept the Block Tray 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(0x300A, 0x00F5, strBlockTrayID,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x300A, 0x00F5,DicomConstants.DCM_DT_SH, strBlockTrayID);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves user-supplied identifier for block tray.
	 * @return String - value of Block Tray ID.
	 */
	public String getBlockTrayID()
	{
		Object objValue = getValue(0x300A, 0x00F5);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets radiation Source to attachment edge of block tray assembly (mm). Required if Block Sequence (300A,00F4) is sent.
	 * @param strSourceToBlockTrayDistance -String value of Source to Block Tray Distance.
	 */
	public void setSourceToBlockTrayDistance(String strSourceToBlockTrayDistance)
	{
		/* Accept the Source to Block Tray Distance 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(0x300A, 0x00F6, strSourceToBlockTrayDistance,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x300A, 0x00F6,DicomConstants.DCM_DT_DS, strSourceToBlockTrayDistance);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves radiation Source to attachment edge of block tray assembly (mm). Required if Block Sequence (300A,00F4) is sent.
	 * @return String - value of Source to Block Tray Distance.
	 */
	public String getSourceToBlockTrayDistance()
	{
		Object objValue = getValue(0x300A, 0x00F6);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets type of block. Required if Block Sequence (300A,00F4) is sent.
	 * Enumerated Values:
	 * 1) SHIELDING = blocking material is inside contour.
	 * 2) APERTURE = blocking material is outside contour.
	 * @param strBlockType -String value of Source to Block Type.
	 */
	public void setBlockType(String strBlockType)
	{
		/* Accept the Block Type 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(0x300A, 0x00F8, strBlockType,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x300A, 0x00F8,DicomConstants.DCM_DT_CS, strBlockType);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves type of block.
	 * @return String value of Source to Block Type.
	 */
	public String getBlockType()
	{
		Object objValue = getValue(0x300A, 0x00F8);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets presence or otherwise of geometrical divergence. Required if Block Sequence (300A,00F4) is sent.
	 * Enumerated Values:
	 * 1) PRESENT = block edges are shaped for beam divergence.
	 * 2) ABSENT = block edges are not shaped for beam divergence.
	 * @param strBlockDivergence -String value of Block Divergence.
	 */
	public void setBlockDivergence(String strBlockDivergence)
	{
		/* Accept the Block Divergence 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(0x300A, 0x00F8, strBlockDivergence,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x300A, 0x00F8,DicomConstants.DCM_DT_CS, strBlockDivergence);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves presence or otherwise of geometrical divergence.
	 * @return String value of Block Divergence.
	 */
	public String getBlockDivergence()
	{
		Object objValue = getValue(0x300A, 0x00F8);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets which side of the Block Tray the block is mounted.
	 * Enumerated Values:
	 * 1) PATIENT_SIDE = the block is mounted on the side of the Block Tray which is towards the patient.
	 * 2) SOURCE_SIDE = the block is mounted on the side of the Block Tray which is towards the radiation source.
	 * @param strBlockMountingPosition -String value of Block Mounting Position.
	 */
	public void setBlockMountingPosition(String strBlockMountingPosition)
	{
		/* Accept the Block Mounting Position 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(0x300A, 0x00FB, strBlockMountingPosition,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x300A, 0x00FB,DicomConstants.DCM_DT_CS, strBlockMountingPosition);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves which side of the Block Tray the block is mounted.
	 * @return String value of Block Mounting Position.
	 */
	public String getBlockMountingPosition()
	{
		Object objValue = getValue(0x300A, 0x00FB);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets identification number of the Block. The value of Block Number (300A,00FC) shall
	 * be unique within the Beam in which it is created. Required if Block Sequence (300A,00F4) is sent.
	 * @param strBlockNumber -String value of Block Number.
	 */
	public void setBlockNumber(String strBlockNumber)
	{
		/* Accept the Block Number 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(0x300A, 0x00FC, strBlockNumber,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x300A, 0x00FC,DicomConstants.DCM_DT_IS, strBlockNumber);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves identification number of the Block.
	 * @return String - value of Block Number.
	 */
	public String getBlockNumber()
	{
		Object objValue = getValue(0x300A, 0x00FC);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets user-defined name for block.
	 * @param strBlockName -String value of Block Name.
	 */
	public void setBlockName(String strBlockName)
	{
		/* Accept the Block Name in String format of type LO.
		 * 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(0x300A, 0x00FE, strBlockName,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x300A, 0x00FE,DicomConstants.DCM_DT_LO, strBlockName);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves user-defined name for block.
	 * @return String - value of Block Name.
	 */
	public String getBlockName()
	{
		Object objValue = getValue(0x300A, 0x00FE);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets user-supplied identifier for material used to manufacture Block. Required if Block Sequence (300A,00F4) is sent.
	 * @param strMaterialID -String value of Material ID.
	 */
	public void setMaterialID(String strMaterialID)
	{
		/* Accept the Material 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(0x300A, 0x00E1, strMaterialID,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x300A, 0x00E1,DicomConstants.DCM_DT_SH, strMaterialID);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves user-defined name for block.
	 * @return String - value of Material ID.
	 */
	public String getMaterialID()
	{
		Object objValue = getValue(0x300A, 0x00E1);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets thickness of block (in mm) parallel to radiation beam axis.
	 * @param strBlockThickness -String value of Block Thickness.
	 */
	public void setBlockThickness(String strBlockThickness)
	{
		/* Accept the Block Thickness 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(0x300A, 0x0100, strBlockThickness,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x300A, 0x0100,DicomConstants.DCM_DT_DS, strBlockThickness);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves thickness of block (in mm) parallel to radiation beam axis.
	 * @return String - value of Block Thickness.
	 */
	public String getBlockThickness()
	{
		Object objValue = getValue(0x300A, 0x0100);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets number of (x,y) pairs defining the block edge. Required if Block Sequence (300A,00F4) is sent.
	 * @param strBlockNumberOfPoints- String value of Block Number of Points.
	 */
	public void setBlockNumberOfPoints(String strBlockNumberOfPoints)
	{
		/* Accept the Block Number of Points 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(0x300A, 0x0104, strBlockNumberOfPoints,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x300A, 0x0104,DicomConstants.DCM_DT_IS, strBlockNumberOfPoints);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves number of (x,y) pairs defining the block edge.
	 * @return String - value of Block Number of Points.
	 */
	public String getBlockNumberOfPoints()
	{
		Object objValue = getValue(0x300A, 0x0104);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Sets a data stream of (x,y) pairs which comprise the block edge. The number of pairs shall
	 * be equal to Block Number of Points (300A,0104), and the vertices shall be
	 * interpreted as a closed polygon. Coordinates are projected onto the machine isocentric plane 
	 * in the IEC BEAM LIMITING DEVICE coordinate system (mm). Required if Block Sequence
	 * (300A,00F4) is sent.
	 * @param arrStrBlockData -String value of Block Data.
	 */	
	public void setBlockData(String[] arrStrBlockData)
	{
		/* Accept the Block Data value in String Array format of type DS.
		 * 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
		 */
		IDataElement objIDataElement = null;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
		{	
			objIDataElement = new ImplicitDE(0x300A, 0x0106,arrStrBlockData,objIDictionaryReader);
		}
		else
		{
			objIDataElement = new ExplicitDE(0x300A, 0x0106, DicomConstants.DCM_DT_DS,arrStrBlockData);
		}
		if(objIDataElement != null)
			addDataElement(objIDataElement);
	}

	/**
	 * Retrieves a data stream of (x,y) pairs which comprise the block edge.
	 * @return arrStrOperatorNames - String value of Block Data.
	 */
	public String[] getBlockData()
	{
		Object objValue = getValue(0x300A, 0x0106);
		if(objValue != null)
			return (String[])objValue;
		return null;
	}

	/**
	 * Sets An identifier for the accessory intended to be read by a device such as a bar-code reader.
	 * @param strAccessoryCode -String value of Accessory Code.
	 */
	public void setAccessoryCode(String strAccessoryCode)
	{
		/* Accept the Block Number of Points in String format of type LO.
		 * 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(0x300A,0x00F9, strAccessoryCode,getDictionaryReader());
		else
			objIDataElement = new ExplicitDE(0x300A,0x00F9,DicomConstants.DCM_DT_LO, strAccessoryCode);

		addDataElement(objIDataElement);
	}

	/**
	 * Retrieves Accessory Code.
	 * @return String - value of Accessory Code.
	 */
	public String getAccessoryCode()
	{
		Object objValue = getValue(0x300A,0x00F9);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
}

