/*******************************************************************************
 *  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.dicommodel.modules;



import cdac.medinfo.sdk.dcm30_04.baselibs.Tag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPositionerMotion;

import cdac.medinfo.sdk.dcm30_04.exceptions.ConditionFailedException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidModuleException;
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;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;

// TODO: Auto-generated Javadoc
/**
 \* This module contains IOD Attributes that describe a c-arm positioner typically used in acquiring
 * X-Ray Angiographic Images.
 */
public class XAPositionerModule extends Module  
{


	/**
	 * The obj single collection.
	 */
	public static ISingleCollection<ITag> objSingleCollection = null;


	/**
	 * Instantiates a new xA positioner module.
	 * 
	 * @param objIDataSet the obj i data set
	 */
	public XAPositionerModule(IDataSet objIDataSet)
	{
		super(objIDataSet);
	}

	static
	{
		objSingleCollection = new SingleCollection<ITag>();
		objSingleCollection.add(new Tag(0x0018,0x1110));
		objSingleCollection.add(new Tag(0x0018,0x1111));
		objSingleCollection.add(new Tag(0x0018,0x1114));
		objSingleCollection.add(new Tag(0x0018,0x1500));
		objSingleCollection.add(new Tag(0x0018,0x1510));
		objSingleCollection.add(new Tag(0x0018,0x1511));
		objSingleCollection.add(new Tag(0x0018,0x1520));
		objSingleCollection.add(new Tag(0x0018,0x1521));
		objSingleCollection.add(new Tag(0x0018,0x1530));
		objSingleCollection.add(new Tag(0x0018,0x1531));
	}

	/**
	 * This method validates each Attribute in the Module according to the Type
	 * of the Attribute.Attributes are of 5 types.
	 * Type 1,Type 2 are Mandatory:
	 * Mandatory Attributes have to present in the Module.
	 * Type 1C,2C are Conditional:
	 * Conditional Attributes' presence depend on a condition.
	 * If the condition is satisfied the Attribute has to be present.
	 * Type 3 are Optional
	 * Optional Attributes can be added as and when required.
	 * 
	 * @return boolean - returns validation status as success or failure
	 * 
	 * @throws InvalidModuleException - If validation of Module fails
	 */
	public  boolean validateModule() throws InvalidModuleException
	{

		try
		{			
			if(!isPresent(0x0018,0x1510))
				throw new MandatoryMissingException("0018,1510");
			if(!isPresent(0x0018,0x1511))
				throw new MandatoryMissingException("0018,1511");
			else
			{
				String strValue = null;
				if(isPresent(0x0018,0x1500))
					strValue = getPositionerMotion();
				if(strValue != null)
				{
					if(strValue.equalsIgnoreCase(EnumPositionerMotion.DYNAMIC.getValue()) && !isPresent(0x0018,0x1520))
						throw new ConditionFailedException("0018,1520 Required if Positioner Motion is DYNAMIC.");
					if(strValue.equalsIgnoreCase(EnumPositionerMotion.DYNAMIC.getValue()) && !isPresent(0x0018,0x1521))
						throw new ConditionFailedException("0018,1521 Required if Positioner Motion is DYNAMIC.");
				}
			}
		}
		catch(MandatoryMissingException mme)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(mme.getMessage());

			
				throw new InvalidModuleException(this.getClass().getSimpleName(),mme);

		}
		catch(ConditionFailedException cfe)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(cfe.getMessage());

			
				throw new InvalidModuleException(this.getClass().getSimpleName(),cfe);

		}
		return true;
	}

	/**
	 * Sets Distance in mm from source to isocenter.
	 * 
	 * @param strDistanceSourceToPatient the str distance source to patient
	 */
	public void setDistanceSourceToPatient(String strDistanceSourceToPatient)
	{
		/*Accept Distance in mm from source to isocenter 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 Hash Map
		 */
		addDataElement(0x0018, 0x1111, DicomConstants.DCM_DT_DS, strDistanceSourceToPatient);
	}

	/**
	 * Return Distance in mm from source to isocenter.
	 * 
	 * @return String - String value of Distance Source to Patient
	 */
	public String getDistanceSourceToPatient()
	{Object objectValue = getValue(0x0018,0x1111);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Sets Distance in mm from source to detector.
	 * 
	 * @param strDistanceSourceToDetector the str distance source to detector
	 */
	public void setDistanceSourceToDetector(String strDistanceSourceToDetector)
	{
		/*Accept the Distance Source to Detector 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
		 */
		addDataElement(0x0018,0x1110, DicomConstants.DCM_DT_DS, strDistanceSourceToDetector);
	}

	/**
	 * Return Distance in mm from source to detector.
	 * 
	 * @return String - String value of Distance Source to detector
	 */
	public String getDistanceSourceToDetector()
	{Object objectValue = getValue(0x0018,0x1110);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Sets Ratio of Source Image Receptor Distance (SID) over Source Object Distance (SOD).
	 * 
	 * @param strEstimatedRadiographicMagnificationFactor the str estimated radiographic magnification factor
	 */
	public void setEstimatedRadiographicMagnificationFactor(String strEstimatedRadiographicMagnificationFactor)
	{
		/* Accept Estimated Radiographic Magnification Factor 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 Hash Map
		 */
		addDataElement(0x0018, 0x1114, DicomConstants.DCM_DT_DS, strEstimatedRadiographicMagnificationFactor);
	}

	/**
	 * Return Ratio of Source Image Receptor Distance (SID) over Source Object Distance (SOD).
	 * 
	 * @return String - String value of Estimated Radiographic Magnification Factor
	 */
	public String getEstimatedRadiographicMagnificationFactor()
	{Object objectValue = getValue(0x0018,0x1114);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Sets value that is used to describe the activity of the imaging devices. Defined terms: DYNAMIC, STATIC.
	 * Required if Multi-frame data.
	 * 
	 * @param enumPositionerMotion enum value of Positioner Motion
	 */
	public void setPositionerMotion(EnumPositionerMotion enumPositionerMotion)
	{
		/* Accept Positioner Motion 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 Hash Map
		 */
		String strPositionerMotion = enumPositionerMotion.getValue();
		addDataElement(0x0018, 0x1500, DicomConstants.DCM_DT_CS, strPositionerMotion);
	}

	/**
	 * Return the activity of the imaging devices.
	 * 
	 * @return String - String value of Positioner Motion
	 */
	public String getPositionerMotion()
	{
		Object objectValue = getValue(0x0018,0x1500);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Sets position of the X-Ray Image Intensifier about the patient from the RAO to LAO
	 * direction where movement from RAO to vertical is positive.
	 * 
	 * @param strPositionerPrimaryAngle the str positioner primary angle
	 */
	public void setPositionerPrimaryAngle(String strPositionerPrimaryAngle)
	{
		/* Accept Positioner Primary 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 Hash Map
		 */
		addDataElement(0x0018, 0x1510, DicomConstants.DCM_DT_DS, strPositionerPrimaryAngle);
	}

	/**
	 * Return position of the X-Ray Image Intensifier about the patient from the RAO to LAO
	 * direction where movement from RAO to vertical is positive.
	 * 
	 * @return String - String value of Positioner Primary Angle
	 */
	public String getPositionerPrimaryAngle()
	{Object objectValue = getValue(0x0018,0x1510);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Sets position of the X-Ray Image Intensifier about the patient from the CAU to CRA
	 * direction where movement from CAU to vertical is positive.
	 * 
	 * @param strPositionerSecondaryAngle the str positioner secondary angle
	 */
	public void setPositionerSecondaryAngle(String strPositionerSecondaryAngle)
	{
		/* Accept Positioner Secondary 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 Hash Map
		 */
		addDataElement(0x0018, 0x1511, DicomConstants.DCM_DT_DS, strPositionerSecondaryAngle);
	}

	/**
	 * Return position of the X-Ray Image Intensifier about the patient from the CAU to CRA
	 * direction where movement from CAU to vertical is positive.
	 * 
	 * @return String - String value of Positioner Secondary Angle
	 */
	public String getPositionerSecondaryAngle()
	{Object objectValue = getValue(0x0018,0x1511);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Sets Incremental change in primary positioner angle for each frame.
	 * Required if Positioner Motion is DYNAMIC.
	 * 
	 * @param arrStrPositionerPrimaryAngleIncrement the arr str positioner primary angle increment
	 */
	public void setPositionerPrimaryAngleIncrement(String[] arrStrPositionerPrimaryAngleIncrement)
	{
		/*Accept Positioner Primary Angle Increment 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 Hash Map
		 */
		addDataElement(0x0018,0x1520, DicomConstants.DCM_DT_DS, arrStrPositionerPrimaryAngleIncrement);
	}

	/**
	 * Return Incremental change in primary positioner angle for each frame.
	 * 
	 * @return String[] - String array of Positioner Primary Angle Increment
	 */
	public String[] getPositionerPrimaryAngleIncrement()
	{
		Object objectValue = getValue(0x0018, 0x1520);
		if(objectValue!=null)
			return (String[])objectValue;
		return null;
	}

	/**
	 * Sets Incremental change in secondary positioner angle for each frame.
	 * Required if Positioner Motion is DYNAMIC.
	 * 
	 * @param arrStrPositionerSecondaryAngleIncrement the arr str positioner secondary angle increment
	 */
	public void setPositionerSecondaryAngleIncrement(String[] arrStrPositionerSecondaryAngleIncrement)
	{
		/* Accept Positioner Secondary Angle Increment 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 Hash Map
		 */
		addDataElement(0x0018,0x1521, DicomConstants.DCM_DT_DS, arrStrPositionerSecondaryAngleIncrement);
	}

	/**
	 * Return Incremental change in primary positioner angle for each frame.
	 * 
	 * @return String[] - String array of Positioner Secondary Angle Increment
	 */
	public String[] getPositionerSecondaryAngleIncrement()
	{
		Object objectValue = getValue(0x0018, 0x1521);
		if(objectValue!=null)
			return (String[])objectValue;
		return null;
	}

	/**
	 * Sets angle of the X-Ray beam in the row direction in degrees relative to the normal
	 * to the detector plane. Positive values indicate that the X-Ray beam is tilted
	 * towards higher numbered columns. Negative values indicate that the X-Ray
	 * beam is tilted towards lower numbered columns.
	 * 
	 * @param strDetectorPrimaryAngle the str detector primary angle
	 */
	public void setDetectorPrimaryAngle(String strDetectorPrimaryAngle)
	{
		/* Accept Detector Primary 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 Hash Map
		 */
		addDataElement(0x0018, 0x1530, DicomConstants.DCM_DT_DS, strDetectorPrimaryAngle);
	}

	/**
	 * Return position of the X-Ray Image Intensifier about the patient from the RAO to LAO
	 * direction where movement from RAO to vertical is positive.
	 * 
	 * @return String - String value of Positioner Primary Angle
	 */
	public String getDetectorPrimaryAngle()
	{Object objectValue = getValue(0x0018,0x1530);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Sets Angle of the X-Ray beam in the column direction in degrees relative to the normal
	 * to the detector plane. Positive values indicate that the X-Ray beam is tilted
	 * towards lower numbered rows. Negative values indicate that the X-Ray beam is
	 * tilted towards higher numbered rows.
	 * 
	 * @param strDetectorSecondaryAngle the str detector secondary angle
	 */
	public void setDetectorSecondaryAngle(String strDetectorSecondaryAngle)
	{
		/* Accept Detector Secondary 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 Hash Map
		 */
		addDataElement(0x0018, 0x1531, DicomConstants.DCM_DT_DS, strDetectorSecondaryAngle);
	}

	/**
	 * Return Angle of the X-Ray beam in the column direction in degrees relative to the normal
	 * to the detector plane.
	 * 
	 * @return String - String value of Detector Secondary Angle
	 */
	public String getDetectorSecondaryAngle()
	{Object objectValue = getValue(0x0018,0x1531);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/*	
	 * This method is used by the Module Iterator to iterate through the DataSet and return only
	 * those elements that belong to the respective Module class whose getVectorOfKeys is called.
	 */
	/**
	 * This method returns the vector of keys representing the DataElements
	 * that belong to this module.
	 * 
	 * @return vector of Tags - returns the vector containing the collection of tags
	 */
	public ISingleCollection<ITag> getVectorOfKeys()
	{
		return objSingleCollection;
	}

}
