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

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.IQueryModel;
import cdac.medinfo.sdk.dcm30_04.services.javadbhelper.DicomImage;
import cdac.medinfo.sdk.dcm30_04.services.javadbhelper.Patient;
import cdac.medinfo.sdk.dcm30_04.services.javadbhelper.Series;
import cdac.medinfo.sdk.dcm30_04.services.javadbhelper.Study;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;

/**
 * This class provides implementation of DataBase Connection and processing of queries on DataBase.
 * It's a singleton class.
 */
public class DCMDBAgent  
{

	DBQuery objDBQuery = null;
	private static String dbURL = null;
	private static String emdriver = null;
	private static Connection objcon = null;
	private static DCMDBAgent objDCMDBAgent = null;
	private static Object mutex = new Object();

	/**
	 * Default Private Constructor
	 */
	private DCMDBAgent(String strConnectionString, String strDriverName)throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException
	{
		emdriver = new String(strDriverName);
		dbURL = new String(strConnectionString);
	{
		// System.out.println("Loading the driver...");
	}
		Class.forName(emdriver).newInstance();
	{
		// System.out.println("Getting  database connection...");
	}
		objcon = DriverManager.getConnection(dbURL);
	{
		// System.out.println("Connection established");
	}

		objDBQuery = new DBQuery();
		objDBQuery.setConnection(objcon);

	}

	/**
	 * Creates instance of DBAgent.
	 * @return DCMDBAgent object of DCMDBAgent
	 * @throws SQLException Signals if SQL Exception occurs.
	 */
	public static DCMDBAgent createInstance(String strConnectionString, String strDriverName)throws SQLException,ClassNotFoundException, InstantiationException, IllegalAccessException
	{
		synchronized (mutex) 
		{
			if(objDCMDBAgent == null)
				objDCMDBAgent = new DCMDBAgent(strConnectionString,strDriverName);
		}
		return objDCMDBAgent;
	}

	/**
	 * Close data base connection.
	 */
	public void close() throws SQLException
	{
		objcon.close();
	}

	/**
	 * inserts a record of Patient
	 * @param objPatient object of Patient.
	 * @param strStoragePath path where file dump is to be stored.
	 * @throws SQLException Signals if SQL Exception occurs.
	 */
	public void insertPatientInfo(Patient objPatient,String strStoragePath)throws SQLException
	{
		if(objPatient != null)
		{
			objcon.setAutoCommit(false);
			objDBQuery.insertPatientInfo(objPatient);

			if(objPatient.getStudyList() != null && !objPatient.getStudyList().isEmpty())
			{
				Study objStudy = objPatient.getStudyList().elementAt(0);
				insertStudyInfo(objStudy,objPatient.getPatientID(),strStoragePath);
			}
		}
	}

	/**
	 * inserts a record of Series
	 * @param objSeries object of Series.
	 * @param strStoragePath path where file dump is to be stored.
	 * @throws SQLException Signals if SQL Exception occurs.
	 */
	private void insertSeriesInfo(Series objSeries,String strPatientID,String strStudyInsUID,String strStoragePath)throws SQLException
	{
		if(objSeries != null)
		{
			objDBQuery.insertSeriesInfo(objSeries,strPatientID,strStudyInsUID);

			if(objSeries.getDicomImageList() != null && !objSeries.getDicomImageList().isEmpty())
			{
				DicomImage objDicomImage = objSeries.getDicomImageList().elementAt(0);
				insertDicomImageInfo(objDicomImage,strPatientID,strStudyInsUID,objSeries.getSeriesInstanceUID(),strStoragePath);
			}
		}
	}

	/**
	 * inserts a record of Study
	 * @param objStudy object of Study.
	 * @param strStoragePath path where file dump is to be stored.
	 */
	private void insertStudyInfo(Study objStudy,String strPatientID,String strStoragePath)throws SQLException
	{
		if(objStudy != null)
		{
			objDBQuery.insertStudyInfo(objStudy,strPatientID);

			if(objStudy.getSeriesList() != null && !objStudy.getSeriesList().isEmpty())
			{
				Series objSeries = objStudy.getSeriesList().elementAt(0);
				insertSeriesInfo(objSeries,strPatientID,objStudy.getStudyInstanceUID(),strStoragePath);
			}
		}
	}

	/**
	 * inserts a record of Info related to a DicomImage
	 * @param objDicomImage object of DicomImage.
	 * @param strStoragePath path where file dump is to be stored.
	 */
	private void insertDicomImageInfo(DicomImage objDicomImage,String strPatientID,String strStudyInsUID,String strSeriesInsUID,String strStoragePath)throws SQLException
	{
		if(objDicomImage != null)
		{
			objDBQuery.insertDicomImageInfo(objDicomImage,strPatientID,strStudyInsUID,strSeriesInsUID,strStoragePath);
			objcon.commit();
			objcon.setAutoCommit(true);
		}
	}

	/**
	 * Retrieves collection of PatientInfo.
	 * @return ISingleCollection<Patient> Collection of Patient.
	 * @throws SQLException Signals if SQL Exception occurs.
	 */
	public ISingleCollection<Patient> getPatientInfo()throws SQLException
	{
		return objDBQuery.getPatientInfo();
	}

	/**
	 * Retrieves collection of SeriesInfo.
	 * @return ISingleCollection<Series> Collection of Series.
	 * @throws SQLException Signals if SQL Exception occurs.
	 */
	public ISingleCollection<Series> getSeriesInfo()throws SQLException
	{
		return objDBQuery.getSeriesInfo();
	}

	/**
	 * Retrieves collection of StudyInfo.
	 * @return ISingleCollection<Study> Collection of Study.
	 * @throws SQLException Signals if SQL Exception occurs.
	 */
	public ISingleCollection<Study> getStudyInfo()throws SQLException
	{
		return objDBQuery.getStudyInfo();
	}

	/**
	 * Retrieves collection of DicomImage.
	 * @return ISingleCollection<DicomImage> Collection of DicomImage.
	 * @throws SQLException Signals if SQL Exception occurs.
	 */
	public ISingleCollection<DicomImage> getDicomImageInfo()throws SQLException
	{
		return objDBQuery.getDicomImageInfo();
	}

	/**
	 * This method populates resultant CServices_QueryModel according to the given find parameter in CServices_QueryModel.
	 * @param objQueryModel object of CServices_QueryModel.
	 * @param objRstQueryModel object of resultant CServices_QueryModel 
	 * @return boolean true if matches are found.
	 * 				   false if no match is found.
	 */
	public boolean find(IQueryModel objQueryModel, IQueryModel objRstQueryModel) throws SQLException
	{
		return objDBQuery.find(objQueryModel, objRstQueryModel);
	}

	/**
	 * Retrieves  collection of dicom files path according to the given find parameter in CServices_QueryModel.
	 * @param objQueryModel object of CServices_QueryModel.
	 * @return ISingleCollection<String>  collection of dicom files path.
	 */
	public ISingleCollection<String> retrive(IQueryModel objQueryModel) throws SQLException
	{
		return objDBQuery.retrieve(objQueryModel);
	}
}
