/*******************************************************************************
 *  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.DicomV3Factory;
import cdac.medinfo.sdk.dcm30_04.baselibs.ReferencedDoseSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.ReferencedRTPlanSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.ReferencedStructureSetSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.Tag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomValue;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.enums.EnumRTPlanGeometry;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPlanIntent;

import cdac.medinfo.sdk.dcm30_04.exceptions.ConditionFailedException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidItemException;
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 attributes for RT General Plan Module.
 */

public class RTGeneralPlanModule extends Module  
{


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



	/**
	 * Instantiates a new rT general plan module.
	 * 
	 * @param objIDataSet the obj i data set
	 */
	public RTGeneralPlanModule(IDataSet objIDataSet)
	{
		super(objIDataSet);
	}

	static
	{
		objSingleCollection = new SingleCollection<ITag>();
		objSingleCollection.add(new Tag(0x0008,0x1070));
		objSingleCollection.add(new Tag(0x0020,0x0013));
		objSingleCollection.add(new Tag(0x300A,0x0002));
		objSingleCollection.add(new Tag(0x300A,0x0003));
		objSingleCollection.add(new Tag(0x300A,0x0004));
		objSingleCollection.add(new Tag(0x300A,0x0006));
		objSingleCollection.add(new Tag(0x300A,0x0007));
		objSingleCollection.add(new Tag(0x300A,0x0009));
		objSingleCollection.add(new Tag(0x300A,0x000A));
		objSingleCollection.add(new Tag(0x300A,0x000B));
		objSingleCollection.add(new Tag(0x300A,0x000C));
		objSingleCollection.add(new Tag(0x300C,0x0002));
		objSingleCollection.add(new Tag(0x300C,0x0060));
		objSingleCollection.add(new Tag(0x300C,0x0080));
	}

	/**
	 * 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(0x300A,0x0002))
				throw new MandatoryMissingException("300A,0002");
			if(!isPresent(0x0008,0x1070))
				throw new MandatoryMissingException("0008,1070");
			if(!isPresent(0x300A,0x0006))
				throw new MandatoryMissingException("300A,0006");
			if(!isPresent(0x300A,0x0007))
				throw new MandatoryMissingException("300A,0007");
			if(!isPresent(0x300A,0x000C))
				throw new MandatoryMissingException("300A,000C");
			if(EnumRTPlanGeometry.PATIENT.getValue().equals(getRTPlanGeometry()) && !isPresent(0x300C,0x0060))
				throw new ConditionFailedException("300C,0060 is required if value of conditional element RT Plan Geometry(300A,000C) is PATIENT");
			if(isPresent(0x300C,0x0060))
				getReferencedStructureSetSequence().validateForModule();
			if(isPresent(0x300C,0x0080))
				getReferencedDoseSequence().validateForModule();
			if(isPresent(0x300C,0x0002))
				getReferencedRTPlanSequence().validateForModule();

		}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);

		}
		catch(InvalidItemException iie)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(iie.getMessage());

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

		}
		return true;
	}

	/**
	 * Sets user-defined label for treatment plan.
	 * 
	 * @param strRTPlanLabel - String value of RT Plan Label.
	 */
	public void setRTPlanLabel(String strRTPlanLabel)
	{
		/*Accept RT Plan Label 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 Hash Map
		 */
		addDataElement(0x300A, 0x0002, DicomConstants.DCM_DT_SH, strRTPlanLabel);
	}

	/**
	 * Retrieves user-defined label for treatment plan.
	 * 
	 * @return - String value of RT Plan Label.
	 */
	public String getRTPlanLabel()
	{
		 Object objValue = getValue(0x300A,0x0002);
   if(objValue!=null)
      return objValue.toString();
   return null;

	}

	/**
	 * Sets user-defined Name for treatment plan.
	 * 
	 * @param strRTPlanName the str rt plan name
	 */
	public void setRTPlanName(String strRTPlanName)
	{
		/*Accept RT Plan Name 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 Hash Map
		 */
		addDataElement(0x300A, 0x0003, DicomConstants.DCM_DT_LO, strRTPlanName);
	}

	/**
	 * Retrieves user-defined Name for treatment plan.
	 * 
	 * @return - String value of RT Plan Name.
	 */
	public String getRTPlanName()
	{
		 Object objValue = getValue(0x300A,0x0003);
   if(objValue!=null)
      return objValue.toString();
   return null;

	}

	/**
	 * Sets user-defined Description for treatment plan.
	 * 
	 * @param strRTPlanDescription - String value of RT Plan Description.
	 */
	public void setRTPlanDescription(String strRTPlanDescription)
	{
		/*Accept RT Plan Description 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 Hash Map
		 */
		addDataElement(0x300A, 0x0004, DicomConstants.DCM_DT_ST, strRTPlanDescription);
	}

	/**
	 * Retrieves user-defined Description for treatment plan.
	 * 
	 * @return - String value of RT Plan Description.
	 */
	public String getRTPlanDescription()
	{
		 Object objValue = getValue(0x300A,0x0004);
   if(objValue!=null)
      return objValue.toString();
   return null;

	}

	/**
	 * Sets a number that identifies this image.
	 * 
	 * @param strInstanceNumber - String value of Instance Number.
	 */
	public void setInstanceNumber(String strInstanceNumber)
	{
		/* Accept Instance Numberin 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
		 */
		addDataElement(0x0020, 0x0013, DicomConstants.DCM_DT_IS, strInstanceNumber);
	}

	/**
	 * Retrieves instance number identifying this particular instance of the object.
	 * 
	 * @return - String value of instance number.
	 */
	public String getInstanceNumber()
	{
		Object objectValue = getValue(0x0020, 0x0013);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Sets the name of operator administering treatment session.
	 * 
	 * @param arrStrOperatorNames - String value of Name(s) of the operator(s).
	 */	
	public void setOperatorNames(String[] arrStrOperatorNames)
	{
		/*Accept the Operator Names value in String Array format of type PN.
		 * 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
		 */
		addDataElement(0x0008, 0x1070, DicomConstants.DCM_DT_PN, arrStrOperatorNames);
	}

	/**
	 * Retrieves the name of operator administering treatment session.
	 * 
	 * @return  arrStrOperatorNames - String value of Name(s) of the operator(s).
	 */
	public String[] getOperatorNames()
	{
		IDataElement objIDataElement =  objIDataSet.getDataForTag(0x0008, 0x1070);
		if(objIDataElement == null)
			return null;
		IDicomValue objIDicomValue = objIDataElement.getDicomValue();
		if(objIDicomValue == null)
			return null;
		if(objIDicomValue.getValue()==null)
			return null;
		return (String[])objIDicomValue.getValue();

		//return (String[])(objIDataSet.getDataForTag(0x0008, 0x1070)).getDicomValue().getValue();
	}

	/**
	 * Sets date treatment plan was last modified.
	 * 
	 * @param strRTPlanDate - String value of RT Plan Date.
	 */
	public void setRTPlanDate(String strRTPlanDate)
	{
		/*Accept RT Plan Date String format of type DA.
		 * 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(0x300A, 0x0006, DicomConstants.DCM_DT_DA, strRTPlanDate);
	}

	/**
	 * Retrieves date treatment plan was last modified.
	 * 
	 * @return - String value of RT Plan Date.
	 */
	public String getRTPlanDate()
	{
		 Object objValue = getValue(0x300A,0x0006);
   if(objValue!=null)
      return objValue.toString();
   return null;

	}

	/**
	 * Sets time treatment plan was last modified.
	 * 
	 * @param strRTPlanTime - String value of RT Plan Time.
	 */
	public void setRTPlanTime(String strRTPlanTime)
	{
		/*Accept RT Plan Time String format of type TM.
		 * 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(0x300A, 0x0007, DicomConstants.DCM_DT_TM, strRTPlanTime);
	}

	/**
	 * Retrieves time treatment plan was last modified.
	 * 
	 * @return - String value of RT Plan Time.
	 */
	public String getRTPlanTime()
	{
		 Object objValue = getValue(0x300A,0x0007);
   if(objValue!=null)
      return objValue.toString();
   return null;

	}

	/**
	 * Sets the planned treatment protocols.
	 * 
	 * @param arrStrTreatmentProtocols the arr str treatment protocols
	 */	
	public void setTreatmentProtocols(String[] arrStrTreatmentProtocols)
	{
		/* Accept the Treatment Protocols value in String Array format of type LO.
		 * 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
		 */
		addDataElement(0x300A, 0x0009, DicomConstants.DCM_DT_LO, arrStrTreatmentProtocols);
	}

	/**
	 * Retrieves planned treatment protocols.
	 * 
	 * @return  arrStrOperatorNames - String value of Treatment Protocols.
	 */
	public String[] getTreatmentProtocols()
	{
		 Object objValue = getValue(0x300A,0x0009);
   if(objValue!=null)
      return (String[])objValue;
   return null;

	}

	/**
	 * Sets intent of this course of treatment.
	 * Defined Terms:
	 * 1) CURATIVE.
	 * 2) PALLIATIVE.
	 * 3) PROPHYLACTIC.
	 * 4) VERIFICATION.
	 * 
	 * @param enumPlanIntent the enum treatment intent
	 */
	public void setPlanIntent(EnumPlanIntent enumPlanIntent)
	{
		/*Accept Plan Intent 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
		 */
		addDataElement(0x300A, 0x000A, DicomConstants.DCM_DT_CS, enumPlanIntent.getValue());
	}

	/**
	 * Retrieves time treatment plan was last modified.
	 * 
	 * @return - String value of Treatment Intent.
	 */
	public String getPlanIntent()
	{
		 Object objValue = getValue(0x300A,0x000A);
   if(objValue!=null)
      return objValue.toString();
   return null;

	}

	/**
	 * Sets the planned treatment Sites.
	 * 
	 * @param arrStrTreatmentSites the arr str treatment sites
	 */	
	public void setTreatmentSites(String[] arrStrTreatmentSites)
	{
		/* Accept the Treatment Protocols value in String Array format of type LO.
		 * 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
		 */
		addDataElement(0x300A, 0x000B, DicomConstants.DCM_DT_LO, arrStrTreatmentSites);
	}

	/**
	 * Retrieves planned treatment Sites.
	 * 
	 * @return  arrStrOperatorNames - String value of Treatment Sites.
	 */
	public String[] getTreatmentSites()
	{
		 Object objValue = getValue(0x300A,0x000B);
   if(objValue!=null)
      return (String[])objValue;
   return null;

	}

	/**
	 * Sets whether RT Plan is based on patient or treatment device geometry.
	 * Defined Terms:
	 * 1) PATIENT = RT Structure Set exists,
	 * 2) TREATMENT_DEVICE = RT Structure Set does not exist.
	 * 
	 * @param enumRTPlanGeometry the enum rt plan geometry
	 */
	public void setRTPlanGeometry(EnumRTPlanGeometry enumRTPlanGeometry)
	{
		/*Accept RT Plan Geometry 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
		 */
		addDataElement(0x300A, 0x000C, DicomConstants.DCM_DT_CS, enumRTPlanGeometry.getValue());
	}

	/**
	 * Retrieves whether RT Plan is based on patient or treatment device geometry.
	 * 
	 * @return - String value of RT Plan Geometry.
	 */
	public String getRTPlanGeometry()
	{
		 Object objValue = getValue(0x300A,0x000C);
   if(objValue!=null)
      return objValue.toString();
   return null;

	}

	/**
	 * Retrieves sequence of one Class/Instance pair describing instance of RT Structure Set on which the RT Plan is based.
	 * 
	 * @return - instance of {@link ReferencedStructureSetSequence}.
	 */
	public ReferencedStructureSetSequence getReferencedStructureSetSequence()
	{
		ReferencedStructureSetSequence objReferencedStructureSetSequence = (ReferencedStructureSetSequence)getDicomValue(0x300C,0x0060);
		if(objReferencedStructureSetSequence == null)
		{
			/*
			 * If the sequence object is not present in the DataSet, a new sequence object is created and
			 * the TransferSyntax and DictionaryReader is set into it as it is set in the Module. This ensures that 
			 * the DataElements getting added in the DataSet follow the same TransferSyntax and use the same
			 * DictionaryReader object as that of the module.
			 */
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			objReferencedStructureSetSequence = (ReferencedStructureSetSequence)objDicomV3Factory.createSequence(0x300C,0x0060, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x300C,0x0060, DicomConstants.DCM_DT_SQ, objReferencedStructureSetSequence.getValue());
		}
		return objReferencedStructureSetSequence;
	}

	/**
	 * Retrieves sequence of related SOP Class/Instance pairs describing related instances of RT Dose (for grids and
	 * named/unnamed point doses).
	 * 
	 * @return - instance of {@link ReferencedDoseSequence}.
	 */
	public ReferencedDoseSequence getReferencedDoseSequence()
	{
		ReferencedDoseSequence objReferencedDoseSequence = (ReferencedDoseSequence)getDicomValue(0x300C, 0x0080);
		if(objReferencedDoseSequence == null)
		{
			/*
			 * If the sequence object is not present in the DataSet, a new sequence object is created and
			 * the TransferSyntax and DictionaryReader is set into it as it is set in the Module. This ensures that 
			 * the DataElements getting added in the DataSet follow the same TransferSyntax and use the same
			 * DictionaryReader object as that of the module.
			 */
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			objReferencedDoseSequence = (ReferencedDoseSequence)objDicomV3Factory.createSequence(0x300C, 0x0080, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x300C, 0x0080, DicomConstants.DCM_DT_SQ, objReferencedDoseSequence.getValue());
		}
		return objReferencedDoseSequence;
	}

	/**
	 * Retrieves a sequence which provides reference to a RT Plan SOP Class/Instance pair.
	 * 
	 * @return - instance of Referenced RT Plan Sequence.
	 */
	public ReferencedRTPlanSequence getReferencedRTPlanSequence()
	{
		ReferencedRTPlanSequence objReferencedRTPlanSequence = (ReferencedRTPlanSequence)getDicomValue(0x300C,0002);
		if(objReferencedRTPlanSequence == null)
		{
			/*
			 * If the sequence object is not present in the DataSet, a new sequence object is created and
			 * the TransferSyntax and DictionaryReader is set into it as it is set in the Module. This ensures that 
			 * the DataElements getting added in the DataSet follow the same TransferSyntax and use the same
			 * DictionaryReader object as that of the module.
			 */
			DicomV3Factory objDicomV3Factory = DicomV3Factory.createInstance();
			objReferencedRTPlanSequence = (ReferencedRTPlanSequence)objDicomV3Factory.createSequence(0x300C,0002, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x300C,0002, DicomConstants.DCM_DT_SQ, objReferencedRTPlanSequence.getValue());
		}
		return objReferencedRTPlanSequence;
	}

	/**
	 * 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;
	}
}
