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

import java.io.IOException;
import java.util.Locale;

import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomStream;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDictionaryReader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITransferSyntax;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.ClinicalTrialSeriesModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.EnhancedGeneralEquipmentModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.GeneralEquipmentModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.GeneralOphthalmicRefractiveMeasurementsModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.GeneralSeriesModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.GeneralStudyModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.IntraocularLensCalculationsModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.IntraocularLensCalculationsSeriesModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.NonImageIOD;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.PatientModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.PatientStudyModule;
import cdac.medinfo.sdk.dcm30_04.dicommodel.modules.SOPCommonModule;
import cdac.medinfo.sdk.dcm30_04.enums.EnumModuleNames;
import cdac.medinfo.sdk.dcm30_04.enums.EnumSOPClassUIDs;

import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidIODException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidModuleException;
import cdac.medinfo.sdk.dcm30_04.exceptions.ParseException;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConfig;
import cdac.medinfo.sdk.dcm30_04.utils.DicomLogger;
import cdac.medinfo.sdk.dcm30_04.utils.ResourceBundleWrapper;
/**
 * The Intraocular Lens Calculations IOD is used to encode calculations performed by ophthalmic axial measurements devices or bystandalone software. Data input to these calculations comes both from the devices and from other sources.
 * @author saloni
 *
 */
public class IntraocularLensCalculationsIOD extends NonImageIOD 
{

	/**
	 * The Constant AUTOREFRACTION_MEASUREMENTS_IOD.
	 */
	public static final String INTRAOCULAR_LENS_CALCULATIONS_IOD = "Intraocular Lens Calculations IOD";

	/**
	 * The obj patient module.
	 */
	PatientModule objPatientModule  = null ;                   

	/**
	 * The obj general study module.
	 */
	GeneralStudyModule objGeneralStudyModule = null;

	/**
	 * The obj patient study module.
	 */
	PatientStudyModule	objPatientStudyModule = null;

	/**
	 * The obj general series module.
	 */
	GeneralSeriesModule objGeneralSeriesModule = null;
	
	/**
	 * The obj clinical trial series module.
	 */
	ClinicalTrialSeriesModule objClinicalTrialSeriesModule = null;
	
	/**
	 * The obj Intraocular Lens Calculations Series module.
	 */
	IntraocularLensCalculationsSeriesModule objIntraocularLensCalculationsSeriesModule = null;

	/**
	 * The obj general equipment module.
	 */
	GeneralEquipmentModule	objGeneralEquipmentModule = null;
	
	/**
	 * The obj enhanced general equipment module.
	 */
	EnhancedGeneralEquipmentModule	objEnhancedGeneralEquipmentModule = null;
	
	/**
	 * The obj Intraocular Lens Calculations module.
	 */
	IntraocularLensCalculationsModule	objIntraocularLensCalculationsModule = null;
	
	/**
	 * The obj General Ophthalmic Refractive Measurements module.
	 */
	GeneralOphthalmicRefractiveMeasurementsModule	objGeneralOphthalmicRefractiveMeasurementsModule = null;
	
	/**
	 * The obj sop common module.
	 */
	SOPCommonModule	objSOPCommonModule = null;

	/**
	 * This constructor initializes the TransferSyntax, Dictionary Reader and data set in its superclass IOD.
	 */
	public IntraocularLensCalculationsIOD()
	{
		super();
	}

	/**
	 * This constructor initializes the TransferSyntax  in its superclass IOD.
	 * 
	 * @param objITransferSyntax_ - specifies the DICOM Standard defined TransfeSyntax.
	 */
	public IntraocularLensCalculationsIOD(ITransferSyntax objITransferSyntax_)
	{
		super(objITransferSyntax_);
	}

	/**
	 * This constructor initializes the  DictionaryReader
	 * in its superclass IOD.
	 * 
	 * @param objIDictionaryReader_ - specifies the DICOM Dictionary reader to be used .
	 */
	public IntraocularLensCalculationsIOD(IDictionaryReader objIDictionaryReader_)
	{
		super(objIDictionaryReader_);
	}

	/**
	 * This constructor accepts the DataSet from the user   in its superclass IOD.
	 * 
	 * @param objIDataSet_ - specifies the data set to be set in the IOD.
	 */
	public IntraocularLensCalculationsIOD(IDataSet objIDataSet_)
	{
		super(objIDataSet_);
	}

	/**
	 * This constructor initializes the TransferSyntax and DictionaryReader in its super class IOD.
	 * 
	 * @param objITransferSyntax_ specifies the DICOM Standard defined TransfeSyntax.
	 * @param objIDictionaryReader_ specifies the DICOM Dictionary reader to be used .
	 */
	public IntraocularLensCalculationsIOD(ITransferSyntax objITransferSyntax_,IDictionaryReader objIDictionaryReader_)
	{
		super(objITransferSyntax_,objIDictionaryReader_);
	}

	/**
	 * Creates IntraocularLensCalculationsIOD IOD from a DICOM file containing IntraocularLensCalculationsIOD DICOM data.
	 * @param strFileName DICOM File with absolute path.
	 * @throws IOException Exception caused due to wrong I/O operations. 
	 * @throws ParseException signals if some parse exceptions are occurred.
	 * @throws InvalidIODException signals if some IOD exceptions are occurred.
	 */
	public IntraocularLensCalculationsIOD(String strFileName)throws IOException,InvalidIODException
	{
		super(strFileName);
		try
		{
			if(objIDataSet != null)
			{
				String strSOPClassUID = objIDataSet.getSOPClassUID();
				if(strSOPClassUID != null)
				{
					if(!strSOPClassUID.equals(EnumSOPClassUIDs.INTRAOCULARLENSCALCULATIONSIOD.getValue()))
					{
						throw new InvalidIODException(ResourceBundleWrapper.getValue("exceptions", "InvalidIOD.FileNotMatched", new Locale(DicomConfig.createInstance().getLocale())) + INTRAOCULAR_LENS_CALCULATIONS_IOD);
					}
				}
				strSOPClassUID = null;
			}
		}
		catch(InvalidIODException iie)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger.getLogger().log(iie.getMessage());
			}
			throw iie;
		}
	}


	/**
	 * Retrieves pre-initialized instance of Patient Module. Creates a new instance
	 * if no pre-existing module instance is available.If previously created instance is
	 * present then returns the same module instance.
	 * 
	 * @return PatientModule - instance of {@link PatientModule}.
	 */
	public PatientModule getPatientModule() 
	{
		if(objPatientModule == null)
			objPatientModule = new PatientModule(objIDataSet);

		return objPatientModule;
	}

	/**
	 * Retrieves pre-initialized instance of General Study Module. Creates a new instance
	 * if no pre-existing module instance is available.If previously created instance is
	 * present then returns the same module instance.
	 * 
	 * @return GeneralStudyModule - instance of {@link GeneralStudyModule}.
	 */
	public GeneralStudyModule getGeneralStudyModule() 
	{
		if(objGeneralStudyModule == null)
		{
			objGeneralStudyModule = new GeneralStudyModule(objIDataSet);
			return objGeneralStudyModule;
		}
		return objGeneralStudyModule;
	}

	/**
	 * Retrieves pre-initialized instance of Patient Study Module. Creates a new instance
	 * if no pre-existing module instance is available.If previously created instance is
	 * present then returns the same module instance.
	 * 
	 * @return PatientStudyModule - instance of {@link PatientStudyModule}.
	 */
	public PatientStudyModule getPatientStudyModule() 
	{
		if(objPatientStudyModule == null)
		{
			objPatientStudyModule = new PatientStudyModule(objIDataSet);
			return objPatientStudyModule;
		}
		return objPatientStudyModule;
	}

	/**
	 * Retrieves pre-initialized instance of General Series Module. Creates a new instance
	 * if no pre-existing module instance is available.If previously created instance is
	 * present then returns the same module instance.
	 * 
	 * @return GeneralSeriesModule - instance of {@link GeneralSeriesModule}.
	 */
	public GeneralSeriesModule getGeneralSeriesModule() 
	{
		if(objGeneralSeriesModule == null)
		{
			objGeneralSeriesModule = new GeneralSeriesModule(objIDataSet);
			return objGeneralSeriesModule;
		}
		return objGeneralSeriesModule;
	}
	
	/**
	 * Retrieves pre-initialized instance of Clinical Trial Series Module. Creates a new instance
	 * if no pre-existing module instance is available.If previously created instance is
	 * present then returns the same module instance.
	 * 
	 * @return ClinicalTrialSeriesModule - instance of {@link ClinicalTrialSeriesModule}.
	 */
	public ClinicalTrialSeriesModule getClinicalTrialSeriesModule() 
	{
		if(objClinicalTrialSeriesModule == null)
		{
			objClinicalTrialSeriesModule = new ClinicalTrialSeriesModule(objIDataSet);
			return objClinicalTrialSeriesModule;
		}
		return objClinicalTrialSeriesModule;
	}
	
	/**
	 * Retrieves pre-initialized instance of Intraocular Lens Calculations Series Module. Creates a new instance
	 * if no pre-existing module instance is available.If previously created instance is
	 * present then returns the same module instance.
	 * 
	 * @return IntraocularLensCalculationsSeriesModule - instance of {@link IntraocularLensCalculationsSeriesModule}.
	 */
	public IntraocularLensCalculationsSeriesModule getIntraocularLensCalculationsSeriesModule() 
	{
		if(objIntraocularLensCalculationsSeriesModule == null)
		{
			objIntraocularLensCalculationsSeriesModule = new IntraocularLensCalculationsSeriesModule(objIDataSet);
			return objIntraocularLensCalculationsSeriesModule;
		}
		return objIntraocularLensCalculationsSeriesModule;
	}

	/**
	 * Retrieves pre-initialized instance of General Equipment Module. Creates a new instance
	 * if no pre-existing module instance is available.If previously created instance is
	 * present then returns the same module instance.
	 * 
	 * @return GeneralEquipmentModule - instance of {@link GeneralEquipmentModule}.
	 */
	public GeneralEquipmentModule getGeneralEquipmentModule() 
	{
		if(objGeneralEquipmentModule == null)
		{
			objGeneralEquipmentModule = new GeneralEquipmentModule(objIDataSet);
			return objGeneralEquipmentModule;
		}
		return objGeneralEquipmentModule;
	}
	
	/**
	 * Retrieves pre-initialized instance of Enhanced General Equipment Module. Creates a new instance
	 * if no pre-existing module instance is available.If previously created instance is
	 * present then returns the same module instance.
	 * 
	 * @return EnhancedGeneralEquipmentModule - instance of {@link EnhancedGeneralEquipmentModule}.
	 */
	public EnhancedGeneralEquipmentModule getEnhancedGeneralEquipmentModule() 
	{
		if(objEnhancedGeneralEquipmentModule == null)
		{
			objEnhancedGeneralEquipmentModule = new EnhancedGeneralEquipmentModule(objIDataSet);
			return objEnhancedGeneralEquipmentModule;
		}
		return objEnhancedGeneralEquipmentModule;
	}
	
	/**
	 * Retrieves pre-initialized instance of Intraocular Lens Calculations Module. Creates a new instance
	 * if no pre-existing module instance is available.If previously created instance is
	 * present then returns the same module instance.
	 * 
	 * @return IntraocularLensCalculationsModule - instance of {@link IntraocularLensCalculationsModule}.
	 */
	public IntraocularLensCalculationsModule getIntraocularLensCalculationsModule() 
	{
		if(objIntraocularLensCalculationsModule == null)
		{
			objIntraocularLensCalculationsModule = new IntraocularLensCalculationsModule(objIDataSet);
			return objIntraocularLensCalculationsModule;
		}
		return objIntraocularLensCalculationsModule;
	}
	
	/**
	 * Retrieves pre-initialized instance of General Ophthalmic Refractive Measurements Module. Creates a new instance
	 * if no pre-existing module instance is available.If previously created instance is
	 * present then returns the same module instance.
	 * 
	 * @return GeneralOphthalmicRefractiveMeasurementsModule - instance of {@link GeneralOphthalmicRefractiveMeasurementsModule}.
	 */
	public GeneralOphthalmicRefractiveMeasurementsModule getGeneralOphthalmicRefractiveMeasurementsModule() 
	{
		if(objGeneralOphthalmicRefractiveMeasurementsModule == null)
		{
			objGeneralOphthalmicRefractiveMeasurementsModule = new GeneralOphthalmicRefractiveMeasurementsModule(objIDataSet);
			return objGeneralOphthalmicRefractiveMeasurementsModule;
		}
		return objGeneralOphthalmicRefractiveMeasurementsModule;
	}
	
	/**
	 * Retrieves pre-initialized instance of SOP Common Module. Creates a new instance
	 * if no pre-existing module instance is available.If previously created instance is
	 * present then returns the same module instance.
	 * 
	 * @return SOPCommonModule - instance of {@link SOPCommonModule}.
	 */
	public SOPCommonModule getSOPCommonModule() 
	{
		if(objSOPCommonModule == null)
		{
			objSOPCommonModule = new SOPCommonModule(objIDataSet);
			return objSOPCommonModule;
		}
		return objSOPCommonModule;
	}

	/**
	 * This method validates Non-Image IOD according to the Module Table given in The DICOM Standard.
	 * The validate method fails if one of the mandatory modules are absent or any of the
	 * modules are invalid. The validate method also checks for conditional modules.
	 * 
	 * @return boolean - status of validation as success or failure
	 * 
	 * @throws InvalidIODException -  throws when the IOD is invalid.
	 */
	public boolean validate() throws InvalidIODException
	{
		try{

			super.validate();	


			/*Validate the mandatory elements*/
			getPatientModule().validateModule();
			getGeneralStudyModule().validateModule();
			getGeneralSeriesModule().validateModule();
			getIntraocularLensCalculationsSeriesModule().validateModule();
			getGeneralEquipmentModule().validateModule();
			getEnhancedGeneralEquipmentModule().validateModule();
			getIntraocularLensCalculationsModule().validateModule();
			getGeneralOphthalmicRefractiveMeasurementsModule().validateModule();
			getSOPCommonModule().validateModule();


			/* Validating AUTOREFRACTION MEASUREMENTS IOD Content Constraints */

			/*Validate optional modules*/

			if(isModulePresent(PatientStudyModule.objSingleCollection,objIDataSet))
				getPatientStudyModule().validateModule();
			if(isModulePresent(ClinicalTrialSeriesModule.objSingleCollection,objIDataSet))
				getClinicalTrialSeriesModule().validateModule();

		}catch(InvalidModuleException ime)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(ime.getMessage());
			
				throw new InvalidIODException(INTRAOCULAR_LENS_CALCULATIONS_IOD,ime);
		}
		return true;
	}

	/**
	 *  Dumps the Name of IOD,Module and corresponding Attributes of Module.
	 *  @param objIDicomStream - the Stream on which the Data is to be written.
	 *  @throws IOException - Exception is thrown indicating runtime failure of writing operation.
	 */
	public void dumpDICOMInfo(IDicomStream objIDicomStream) throws IOException
	{
		objIDicomStream.writeString(INTRAOCULAR_LENS_CALCULATIONS_IOD + "\n");
		super.dumpDICOMInfo(objIDicomStream);

		objIDicomStream.writeString("\t" + getPatientModule().getClass().getSimpleName() + "\n");
		getPatientModule().dumpDICOMInfo(objIDicomStream);

		objIDicomStream.writeString("\t" + getGeneralStudyModule().getClass().getSimpleName() + "\n");
		getGeneralStudyModule().dumpDICOMInfo(objIDicomStream);

		objIDicomStream.writeString("\t" + getPatientStudyModule().getClass().getSimpleName() + "\n");
		getPatientStudyModule().dumpDICOMInfo(objIDicomStream);

		objIDicomStream.writeString("\t" + getGeneralSeriesModule().getClass().getSimpleName() + "\n");
		getGeneralSeriesModule().dumpDICOMInfo(objIDicomStream);
		
		objIDicomStream.writeString("\t" + getClinicalTrialSeriesModule().getClass().getSimpleName() + "\n");
		getClinicalTrialSeriesModule().dumpDICOMInfo(objIDicomStream);
		
		objIDicomStream.writeString("\t" + getIntraocularLensCalculationsSeriesModule().getClass().getSimpleName() + "\n");
		getIntraocularLensCalculationsSeriesModule().dumpDICOMInfo(objIDicomStream);

		objIDicomStream.writeString("\t" + getGeneralEquipmentModule().getClass().getSimpleName() + "\n");
		getGeneralEquipmentModule().dumpDICOMInfo(objIDicomStream);
		
		objIDicomStream.writeString("\t" + getEnhancedGeneralEquipmentModule().getClass().getSimpleName() + "\n");
		getEnhancedGeneralEquipmentModule().dumpDICOMInfo(objIDicomStream);
		
		objIDicomStream.writeString("\t" + getIntraocularLensCalculationsModule().getClass().getSimpleName() + "\n");
		getIntraocularLensCalculationsModule().dumpDICOMInfo(objIDicomStream);
		
		objIDicomStream.writeString("\t" + getGeneralOphthalmicRefractiveMeasurementsModule().getClass().getSimpleName() + "\n");
		getGeneralOphthalmicRefractiveMeasurementsModule().dumpDICOMInfo(objIDicomStream);

		objIDicomStream.writeString("\t" + getSOPCommonModule().getClass().getSimpleName() + "\n");
		getSOPCommonModule().dumpDICOMInfo(objIDicomStream);
	}

	/**
	 * Checks whether the Module is present in the IOD or not.
	 * @param strModuleName String value of module name 
	 * @return boolean - true if the module is present in the IOD, else false is returned.
	 */
	public boolean isModulePresent(String strModuleName)
	{
		if(!super.isModulePresent(strModuleName))
		{
			if(strModuleName == null || strModuleName.equals(""))
				return false;
			if(strModuleName.equalsIgnoreCase(EnumModuleNames.PATIENT_MODULE.getValue()) && isModulePresent(PatientModule.objSingleCollection))
				return true;
			else if(strModuleName.equalsIgnoreCase(EnumModuleNames.GENERAL_STUDY_MODULE.getValue()) && isModulePresent(GeneralStudyModule.objSingleCollection))
				return true;
			else if(strModuleName.equalsIgnoreCase(EnumModuleNames.PATIENT_STUDY_MODULE.getValue()) && isModulePresent(PatientStudyModule.objSingleCollection))
				return true;
			else if(strModuleName.equalsIgnoreCase(EnumModuleNames.GENERAL_SERIES_MODULE.getValue()) && isModulePresent(GeneralSeriesModule.objSingleCollection))
				return true;
			else if(strModuleName.equalsIgnoreCase(EnumModuleNames.CLINICAL_TRIAL_SERIES_MODULE.getValue()) && isModulePresent(ClinicalTrialSeriesModule.objSingleCollection))
				return true;
			else if(strModuleName.equalsIgnoreCase(EnumModuleNames.INTRAOCULAR_LENS_CALCULATIONS_SERIES_MODULE.getValue()) && isModulePresent(IntraocularLensCalculationsSeriesModule.objSingleCollection))
				return true;
			else if(strModuleName.equalsIgnoreCase(EnumModuleNames.GENERAL_EQUIPMENT_MODULE.getValue()) && isModulePresent(GeneralEquipmentModule.objSingleCollection))
				return true;
			else if(strModuleName.equalsIgnoreCase(EnumModuleNames.ENHANCED_GENERAL_EQUIPMENT_MODULE.getValue()) && isModulePresent(EnhancedGeneralEquipmentModule.objSingleCollection))
				return true;
			else if(strModuleName.equalsIgnoreCase(EnumModuleNames.INTRAOCULAR_LENS_CALCULATIONS_MODULE.getValue()) && isModulePresent(IntraocularLensCalculationsModule.objSingleCollection))
				return true;
			else if(strModuleName.equalsIgnoreCase(EnumModuleNames.GENERAL_OPHTHALMIC_REFRACTIVE_MEASUREMENTS_MODULE.getValue()) && isModulePresent(GeneralOphthalmicRefractiveMeasurementsModule.objSingleCollection))
				return true;
			else if(strModuleName.equalsIgnoreCase(EnumModuleNames.SOP_COMMON_MODULE.getValue()) && isModulePresent(SOPCommonModule.objSingleCollection))
				return true;
			else
			{
				if(DicomConfig.createInstance().isLoggingOn())
				{
					DicomLogger objDicomLogger = DicomLogger.getLogger();
					objDicomLogger.log(this.getClass().getName() + " : " +ResourceBundleWrapper.getValue("status","ModuleNotPresent",new Locale(DicomConfig.createInstance().getLocale())) + strModuleName);
				}
				return false;
			}
		}
		return true;
	}
}
