/*******************************************************************************
 *  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.Tag;
import cdac.medinfo.sdk.dcm30_04.baselibs.VisualAcuityBothEyesOpenSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.VisualAcuityLeftEyeSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.VisualAcuityRightEyeSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.VisualAcuityTypeCodeSequence;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.enums.EnumBackgroundColor;
import cdac.medinfo.sdk.dcm30_04.enums.EnumOptotype;
import cdac.medinfo.sdk.dcm30_04.enums.EnumOptotypePresentation;

import cdac.medinfo.sdk.dcm30_04.enums.EnumViewingDistanceType;
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 describes attributes related to Visual Acuity Measurements Module.
*/
public class VisualAcuityMeasurementsModule extends Module  
{
	/**
	 * The obj single collection.
	 */
	public static ISingleCollection<ITag> objSingleCollection = null;


	/**
	 * Creates Clinical Trial Series Module with default initialization.
	 * 
	 * @param objIDataSet the obj i data set
	 */
	public VisualAcuityMeasurementsModule(IDataSet objIDataSet)
	{
		super(objIDataSet);
	}

	static
	{
		objSingleCollection = new SingleCollection<ITag>();
		objSingleCollection.add(new Tag(0x0046,0x0125));
		objSingleCollection.add(new Tag(0x0046,0x0121));
		objSingleCollection.add(new Tag(0x0046,0x0092));
		objSingleCollection.add(new Tag(0x0046,0x0094));
		objSingleCollection.add(new Tag(0x0046,0x0139));
		objSingleCollection.add(new Tag(0x0046,0x0095));
		objSingleCollection.add(new Tag(0x0046,0x0122));
		objSingleCollection.add(new Tag(0x0046,0x0123));
		objSingleCollection.add(new Tag(0x0046,0x0124));
	}

	/**
	 * 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 true, if validate module
	 * 
	 * @throws InvalidModuleException - If validation of Module fails
	 */
	public  boolean validateModule() throws InvalidModuleException
	{

		try
		{			/*
		 * Validation Rules for Mandatory Elements
		 */
			if(!isPresent(0x0046,0x0125))
				throw new MandatoryMissingException("0046,0125");
			if(!isPresent(0x0046,0x0121))
				throw new MandatoryMissingException("0046,0121");
			if(!isPresent(0x0046,0x0092))
				throw new MandatoryMissingException("0046,0092");
			if(!isPresent(0x0046,0x0094))
				throw new MandatoryMissingException("0046,0094");
			if(!isPresent(0x0046,0x0095))
				throw new MandatoryMissingException("0046,0095");
			
			if(isPresent(0x0046,0x0094) && (getOptotype().equalsIgnoreCase(EnumOptotype.LETTERS.getValue()) || getOptotype().equalsIgnoreCase(EnumOptotype.NUMBERS.getValue()) || getOptotype().equalsIgnoreCase(EnumOptotype.PICTURES.getValue())) )
				if(!isPresent(0x0046,0x0139))
					throw new ConditionFailedException("0x0046,0x0139");
		}
		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 Viewing Distance Type.
	 * The viewing distance conditions under which a patient's vision was measured.
	 * Enumerated Values:
	 * 1) DISTANCE
	 * 2) NEAR
	 * 3) INTERMEDIATE
	 * 4) OTHER
	 * 
	 * @param enumViewingDistanceType the enum Viewing Distance Type
	 */
	public void setViewingDistanceType(EnumViewingDistanceType  enumViewingDistanceType)
	{
		/* Accept Viewing Distance Type 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
		 */
		addDataElement(0x0046, 0x0125, DicomConstants.DCM_DT_CS, enumViewingDistanceType.getValue());
	}

	/**
	 * Retrieves Viewing Distance Type.
	 * 
	 * @return String - String value of Viewing Distance Type.
	 */ 
	public String getViewingDistanceType()
	{
		Object objValue = getValue(0x0046,0x0125);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	
	/**
	 * This method provides the pre-initialized object of Visual Acuity Type Code Sequence.
	 * 
	 * @return - object of Visual Acuity Type Code Sequence. If the module contains the sequence object
	 * it returns the same otherwise it creates the sequence adds to the module with proper initialization
	 * and then returns the object of sequence
	 */
	public VisualAcuityTypeCodeSequence getVisualAcuityTypeCodeSequence()
	{
		VisualAcuityTypeCodeSequence objVisualAcuityTypeCodeSequence = (VisualAcuityTypeCodeSequence)getDicomValue(0x0046, 0x0121);
		if(objVisualAcuityTypeCodeSequence == 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();
			objVisualAcuityTypeCodeSequence = (VisualAcuityTypeCodeSequence)objDicomV3Factory.createSequence(0x0046, 0x0121, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0046, 0x0121, DicomConstants.DCM_DT_SQ, objVisualAcuityTypeCodeSequence.getValue());
		}
		return objVisualAcuityTypeCodeSequence;
	}
	
	/**
	 * Sets Background Color.
	 * The color of the background upon which optotypes are displayed for measurements of visual acuity.
	 * Enumerated Values:
	 * 1) RED
	 * 2) GREEN
	 * 3) WHITE
	 * 4) REDGREENSPLIT
	 * 
	 * @param enumBackgroundColor the enum Background Color
	 */
	public void setBackgroundColor(EnumBackgroundColor  enumBackgroundColor)
	{
		/* Accept Background Color 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
		 */
		addDataElement(0x0046, 0x0092, DicomConstants.DCM_DT_CS, enumBackgroundColor.getValue());
	}

	/**
	 * Retrieves Background Color.
	 * 
	 * @return String - String value of Background Color.
	 */ 
	public String getBackgroundColor()
	{
		Object objValue = getValue(0x0046,0x0092);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	
	/**
	 * Sets Optotype.
	 * The standardized test type (standard object of regard) used inmeasurements of visual acuity.
	 * Enumerated Values:
	 * 1) LETTERS
	 * 2) NUMBERS
	 * 3) PICTURES
	 * 4) TUMBLING E
	 * 5) LANDOLT C
	 * 
	 * @param enumOptotype the enum Optotype
	 */
	public void setOptotype(EnumOptotype  enumOptotype)
	{
		/* Accept Optotype 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
		 */
		addDataElement(0x0046, 0x0094, DicomConstants.DCM_DT_CS, enumOptotype.getValue());
	}

	/**
	 * Retrieves Optotype.
	 * 
	 * @return String - String value of Optotype.
	 */ 
	public String getOptotype()
	{
		Object objValue = getValue(0x0046,0x0094);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	
	/**
	 * Sets Optotype Detailed Definition.
	 * 
	 * @param strOptotypeDetailedDefinition String value of Optotype Detailed Definition.
	 */
	public void setOptotypeDetailedDefinition(String strOptotypeDetailedDefinition)
	{
		/* Accept Optotype Detailed Definition 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 Hash Map
		 */
		addDataElement(0x0046, 0x0139, DicomConstants.DCM_DT_LO, strOptotypeDetailedDefinition);
	}

	/**
	 * Retrieves Optotype Detailed Definition.
	 * 
	 * @return String - String value of Optotype Detailed Definition.
	 */
	public String getOptotypeDetailedDefinition()
	{
		Object objValue = getValue(0x0046,0x0139);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	
	/**
	 * Sets Optotype Presentation.
	 * Specifies whether single or multiple optotypes were presented.
	 * Enumerated Values:
	 * 1) SINGLE
	 * 2) MULTIPLE
	 * 
	 * @param enumOptotypePresentation the enum Optotype Presentation
	 */
	public void setOptotypePresentation(EnumOptotypePresentation  enumOptotypePresentation)
	{
		/* Accept Optotype Presentation 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
		 */
		addDataElement(0x0046, 0x0095, DicomConstants.DCM_DT_CS, enumOptotypePresentation.getValue());
	}

	/**
	 * Retrieves Optotype Presentation.
	 * 
	 * @return String - String value of Optotype Presentation.
	 */ 
	public String getOptotypePresentation()
	{
		Object objValue = getValue(0x0046,0x0095);
		if(objValue != null)
			return objValue.toString();
		return null;
	}
	
	/**
	 * This method provides the pre-initialized object of Visual Acuity Right Eye Sequence.
	 * 
	 * @return - object of Visual Acuity Right Eye Sequence. If the module contains the sequence object
	 * it returns the same otherwise it creates the sequence adds to the module with proper initialization
	 * and then returns the object of sequence
	 */
	public VisualAcuityRightEyeSequence getVisualAcuityRightEyeSequence()
	{
		VisualAcuityRightEyeSequence objVisualAcuityRightEyeSequence = (VisualAcuityRightEyeSequence)getDicomValue(0x0046, 0x0122);
		if(objVisualAcuityRightEyeSequence == 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();
			objVisualAcuityRightEyeSequence = (VisualAcuityRightEyeSequence)objDicomV3Factory.createSequence(0x0046, 0x0122, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0046, 0x0122, DicomConstants.DCM_DT_SQ, objVisualAcuityRightEyeSequence.getValue());
		}
		return objVisualAcuityRightEyeSequence;
	}
	
	/**
	 * This method provides the pre-initialized object of Visual Acuity Left Eye Sequence.
	 * 
	 * @return - object of Visual Acuity Left Eye Sequence. If the module contains the sequence object
	 * it returns the same otherwise it creates the sequence adds to the module with proper initialization
	 * and then returns the object of sequence
	 */
	public VisualAcuityLeftEyeSequence getVisualAcuityLeftEyeSequence()
	{
		VisualAcuityLeftEyeSequence objVisualAcuityLeftEyeSequence = (VisualAcuityLeftEyeSequence)getDicomValue(0x0046, 0x0123);
		if(objVisualAcuityLeftEyeSequence == 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();
			objVisualAcuityLeftEyeSequence = (VisualAcuityLeftEyeSequence)objDicomV3Factory.createSequence(0x0046, 0x0123, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0046, 0x0123, DicomConstants.DCM_DT_SQ, objVisualAcuityLeftEyeSequence.getValue());
		}
		return objVisualAcuityLeftEyeSequence;
	}
	
	/**
	 * This method provides the pre-initialized object of Visual Acuity Both Eyes Open Sequence.
	 * 
	 * @return - object of Visual Acuity Both Eyes Open Sequence. If the module contains the sequence object
	 * it returns the same otherwise it creates the sequence adds to the module with proper initialization
	 * and then returns the object of sequence
	 */
	public VisualAcuityBothEyesOpenSequence getVisualAcuityBothEyesOpenSequence()
	{
		VisualAcuityBothEyesOpenSequence objVisualAcuityBothEyesOpenSequence = (VisualAcuityBothEyesOpenSequence)getDicomValue(0x0046, 0x0124);
		if(objVisualAcuityBothEyesOpenSequence == 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();
			objVisualAcuityBothEyesOpenSequence = (VisualAcuityBothEyesOpenSequence)objDicomV3Factory.createSequence(0x0046, 0x0124, objITransferSyntax, objIDictionaryReader);
			
			// This will add Data Element of SQ to the DataSet.
			addDataElement(0x0046, 0x0124, DicomConstants.DCM_DT_SQ, objVisualAcuityBothEyesOpenSequence.getValue());
		}
		return objVisualAcuityBothEyesOpenSequence;
	}

	
	/**
	 * This method returns the collection of keys representing the DataElements that belong to this module.
	 * 
	 * @return Collection of Tags - returns the collection containing the tags
	 */
	public ISingleCollection<ITag> getVectorOfKeys()
	{
		return objSingleCollection;
	}
}
