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

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


import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.enums.EnumCommandField;
import cdac.medinfo.sdk.dcm30_04.enums.EnumSOPClassUIDs;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidDataElementException;
import cdac.medinfo.sdk.dcm30_04.services.association.AgreedAssociation;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumImplOpsStatus;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.ICommandElement;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.ICommandSet;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.IPrinterHadler;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.SourceException;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.CommandElement;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.CommandSet;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.DicomMessage;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.IDataSource;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.IQueryModel;
import cdac.medinfo.sdk.dcm30_04.services.print.dbhelper.Print_DBAgent;
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.ICollectionIterator;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.ResourceBundleWrapper;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.StandardMethods;

/**
 * PrintDataSourceImpl is the default implementation for DataSource implementation for Print Management Service Class.<br>
 * This implementation provides the creation of Stored print IOD and HardCopy Grayscale Image IOD.<br>
 * If PrintHandler is added on this then receiveDataSetForPrint() method of PrintHandler is called with the datasets
 * contianing Stored Print IOD and HardCopyGrayScale Image IOD.
 */
public class PrintDataSourceImpl implements IDataSource 
{
	private Print_DBAgent objPrint_DBAgent;
	private IPrinterHadler objIPrinterHandler;
	private AgreedAssociation objAgreedAssocaition;
	private PrinterConfiguration objPrinterConfiguration;

	/**
	 * This is default Constructor for PrintDataSourceImpl.
	 */
	public PrintDataSourceImpl() {
		super();
	}
	
	/**
	 * Instantiates a new data source impl.
	 * @param strConnectionString the str connection string
	 * @param strDriverName the str driver name
	 * @throws SQLException the SQL exception
	 * @throws IllegalAccessException the illegal access exception
	 * @throws InstantiationException the instantiation exception
	 * @throws ClassNotFoundException the class not found exception
	 */
	public PrintDataSourceImpl(String strConnectionString, String strDriverName) throws SQLException, IllegalAccessException,InstantiationException,ClassNotFoundException
	{
		objPrint_DBAgent = Print_DBAgent.createInstance(strConnectionString,strDriverName);
	}
	/**
	 * Unimplemented method
	 */
	public short find(DicomMessage objDicomMessage, ISingleCollection<IDataSet> arg1)
	{
		return EnumImplOpsStatus.FAILURE.getValue();
	}
	/**
	 * Unimplemented method
	 */
	public short find(IQueryModel arg0, IQueryModel arg1) 
	{
		return EnumImplOpsStatus.FAILURE.getValue();
	}

	/**
	 * Depending SOP Instance UID  finds related DataSets and creates Stored Print IOD and HardCopy Grayscale Image or
	 * HardCopyColor Image IOD. After creation of these IODs receiveDataSetForPrint() of PrintHandler is called 
	 * with the DataSets created.  
	 * @param objIDataSet The data set containg identifiers.
	 * @param objRstDataSetCollection the obj rst data set collection
	 * @return short - shows status value which will be used in generation of response
	 * 					Refer EnumImplOpsStatus for suppported response status values.
	 */
	public short retrieve(DicomMessage objDicomMessage, ISingleCollection<IDataSet> objRstDatasetList)
	{
		String strSOPClassUID = null;
		String strSOPInstanceUID = null;
		try
		{
			if(objDicomMessage != null)
			{
				EnumCommandField enumRequestType = objDicomMessage.getCommandType();
				ICommandSet objCommandSet = objDicomMessage.getCommandSet();
				if(enumRequestType.equals(EnumCommandField.N_ACTION_RQ) || enumRequestType.equals(EnumCommandField.N_GET_RQ))
				{
					strSOPClassUID = (String)objCommandSet.getValue(0x0000,0x0003);
					strSOPInstanceUID = (String)objCommandSet.getValue(0x0000,0x1001);
				}
				EnumSOPClassUIDs enumSOPClassUIDs = StandardMethods.getSOPClassUID(strSOPClassUID);
				if(enumSOPClassUIDs == null)
				{
					if(DicomConfig.createInstance().isLoggingOn())
					{
						DicomLogger objDicomLogger = DicomLogger.getLogger();
						objDicomLogger.log(ResourceBundleWrapper.getValue("exceptions","UnknownSOPClassUID",new Locale(DicomConfig.createInstance().getLocale()))+ strSOPClassUID);
					}
					return EnumImplOpsStatus.FAILURE.getValue();
				}
				switch(enumSOPClassUIDs)
				{
				case BASICFILMSESSIONIOD :
				{
					BasicFilmSessionSourceImpl objBasicFilmSessionImpl = new BasicFilmSessionSourceImpl();
					ISingleCollection<IDataSet> objDataSetCollection = new SingleCollection<IDataSet>();
					short shStatus = objBasicFilmSessionImpl.retrieveBasicFilmSessionSOPInstance(objPrint_DBAgent, objDicomMessage, objDataSetCollection, strSOPInstanceUID);
					if(shStatus == EnumImplOpsStatus.SUCCESS.getValue())
					{
						if(objIPrinterHandler != null )
						{
							objIPrinterHandler.receiveDataSetForPrint(objDataSetCollection);
						}
						else
						{
							if(DicomConfig.createInstance().isLoggingOn())
							{
								DicomLogger objDicomLogger = DicomLogger.getLogger();
								objDicomLogger.log(ResourceBundleWrapper.getValue("status", "Print.NoPrintHandlerSpecified", new Locale(DicomConfig.createInstance().getLocale())));
							}
						}
						if(objAgreedAssocaition != null && objAgreedAssocaition.isSOPClassUIDPresent(EnumSOPClassUIDs.PRINTQUEUEMANAGEMENTIOD.getValue()))
						{
							IDataSet objIDataSet = objBasicFilmSessionImpl.createPrintJob(objPrint_DBAgent,DicomConstants.DCM_PRINT_QUEUE_MANAGEMENT_SOP_INSTANCE,objPrinterConfiguration);
							objRstDatasetList.add(objIDataSet);
						}
					}
					return shStatus;
				}
				case BASICFILMBOXIOD :
				{
					BasicFilmBoxImpl objBasicFilmBoxImpl = new BasicFilmBoxImpl();
					ISingleCollection<IDataSet> objDataSetCollection = new SingleCollection<IDataSet>();
					short shStatus = objBasicFilmBoxImpl.retrieveBasicFilmBoxSOPInstance(objPrint_DBAgent, objDicomMessage, objDataSetCollection, strSOPInstanceUID);
					if(shStatus == EnumImplOpsStatus.SUCCESS.getValue())
					{
						if(objIPrinterHandler != null)
						{
							objIPrinterHandler.receiveDataSetForPrint(objDataSetCollection);
						}
						else
						{
							if(DicomConfig.createInstance().isLoggingOn())
							{
								DicomLogger objDicomLogger = DicomLogger.getLogger();
								objDicomLogger.log(ResourceBundleWrapper.getValue("status", "Print.NoPrintHandlerSpecified", new Locale(DicomConfig.createInstance().getLocale())));
							}
						}
						if(objAgreedAssocaition != null && objAgreedAssocaition.isSOPClassUIDPresent(EnumSOPClassUIDs.PRINTQUEUEMANAGEMENTIOD.getValue()))
						{
							IDataSet objIDataSet = objBasicFilmBoxImpl.createPrintJob(objPrint_DBAgent,DicomConstants.DCM_PRINT_QUEUE_MANAGEMENT_SOP_INSTANCE,objPrinterConfiguration);
							objRstDatasetList.add(objIDataSet);
						}
					}
					return shStatus;
				}
				case PRINTQUEUEMANAGEMENTIOD :
				{
					PrintQueueMangSourceImpl objPrintQueueMangSourceImpl = new PrintQueueMangSourceImpl();
					return objPrintQueueMangSourceImpl.retrievePrintQueueSOPInstance(objPrint_DBAgent, objDicomMessage, objRstDatasetList, strSOPInstanceUID);
				}

				case PRINTERCONFIGURATIONRETRIEVAL :
				{
					if(objPrinterConfiguration != null)
					{
						return objPrinterConfiguration.retrieve(objDicomMessage, objRstDatasetList);
					}
					else
					{
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger =DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("exceptions","Print.PrinterConfigurationNotSet", new Locale(DicomConfig.createInstance().getLocale())));
						}
						return EnumImplOpsStatus.FAILURE.getValue();
					}
				}
				case PRINTERIOD :
				{
					if(objPrinterConfiguration != null)
					{
						return objPrinterConfiguration.retrieve(objDicomMessage, objRstDatasetList);
					}
					else
					{
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger =DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("exceptions","Print.PrinterConfigurationNotSet", new Locale(DicomConfig.createInstance().getLocale())));
						}
						return EnumImplOpsStatus.FAILURE.getValue();
					}
				}
				case PRINTJOBIOD :
				{
					PrintJobImpl objPrintJobImpl = new PrintJobImpl();
					return objPrintJobImpl.retrievePrintJobSOPInstance(objPrint_DBAgent, objDicomMessage, objRstDatasetList, strSOPInstanceUID);
				}
				default :
				{
					if(DicomConfig.createInstance().isLoggingOn())
					{
						DicomLogger objDicomLogger =DicomLogger.getLogger();
						objDicomLogger.log(ResourceBundleWrapper.getValue("exceptions","ServiceRequestNotSupported", new Locale(DicomConfig.createInstance().getLocale())));
					}
					return EnumImplOpsStatus.FAILURE.getValue();
				}
				}
			}
		}
		catch(IOException ioe)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger =DicomLogger.getLogger();
				objDicomLogger.log(ioe.getMessage());
			}
			throw new SourceException(ResourceBundleWrapper.getValue("exceptions", "IOException", new Locale(DicomConfig.createInstance().getLocale())), ioe);
		}
		catch(SQLException sql)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger =DicomLogger.getLogger();
				objDicomLogger.log(sql.getMessage());
			}
			throw new SourceException(ResourceBundleWrapper.getValue("exceptions", "SQLException", new Locale(DicomConfig.createInstance().getLocale())), sql);
		}
		catch (InvalidDataElementException ide)
		{
			if (DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(ide.getMessage());
			}
		}
		return EnumImplOpsStatus.FAILURE.getValue();
	}

	/**
	 * This method adds PrintHandler in DataSourImpl.
	 * The implementor of IPrinterHadler gets the Stored Print IOD and the HardCopy Grayscale or Color IOD
	 * which then can be used to print the image information.
	 * When N-Action request for Print Management Service arrives at SCP , it then creates the Stored Print IOD and
	 * the HardCopy grayscale Image IOD and then receiveDataSetForPrint Function of Print handler Class is called.
	 * To receive the Stored Print and HardCopy Grayscale or Color Image information , IPrintHandler should be 
	 * added to PrintDataSourceImpl for receiving the datasets.
	 * @param objIPrinterHander
	 */
	public void addPrinterHandler(IPrinterHadler objIPrinterHander)
	{
		this.objIPrinterHandler = objIPrinterHander;
	}

	/**
	 * This function sets the Agreed Association on Print Data Source Impl.
	 * @param objAgreedAssocaition instance of Agreed Association.
	 */
	public void setAgreedAssociation(AgreedAssociation objAgreedAssocaition)
	{
		this.objAgreedAssocaition = objAgreedAssocaition;
	}

	/**
	 * This function sets the Printer Configuration instance on Print Data Source Impl.
	 * This instance contains all the information related to the printer like printer name.
	 * @param objPrinterConfiguration instance of Printer Configuration.
	 */
	public void setPrinterConfigurationInfo(PrinterConfiguration objPrinterConfiguration)
	{
		this.objPrinterConfiguration = objPrinterConfiguration;
	}

	@Override
	public short retrieve(IQueryModel objQueryModel, IQueryModel objRstQueryModel) 
	{
		DicomMessage objDicomMessage = new DicomMessage();
		ICommandSet objICommandSet = null;
		if(objQueryModel instanceof NGetImagePrintMangMeta_QueryModel)
		{
			objICommandSet = new CommandSet(); 
			
			NGetImagePrintMangMeta_QueryModel objGetPrintMangMetaQueryModel = (NGetImagePrintMangMeta_QueryModel)objQueryModel;
			
			// set Command field
			ICommandElement objICommandElement = new CommandElement(0x0000,0x0100,EnumCommandField.N_GET_RQ.getValue()); 
			objICommandSet.addCommandElement(objICommandElement);

			// set Requested SOP Instance
			String strReqSOPInsUID = objGetPrintMangMetaQueryModel.getReqSOPInsUID();
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(ResourceBundleWrapper.getValue("status","NGet.InstanceSet",new Locale(DicomConfig.createInstance().getLocale()))+ strReqSOPInsUID);
			}
			if(strReqSOPInsUID == null)
			{
				if(DicomConfig.createInstance().isLoggingOn())
				{
					DicomLogger objDicomLogger =DicomLogger.getLogger();
					objDicomLogger.log(ResourceBundleWrapper.getValue("exceptions","InvalidValue", new Locale(DicomConfig.createInstance().getLocale())) + strReqSOPInsUID);
				}
				return EnumImplOpsStatus.FAILURE_INVALID_ATTRIBUTE_VALUE.getValue();
			}
			ICommandElement objICEReqSOPInst = new CommandElement(0x0000,0x1001,strReqSOPInsUID);
			objICommandSet.addCommandElement(objICEReqSOPInst);
			
			// Set Requested SOP CLass UID
			String strSOPClassUID = objGetPrintMangMetaQueryModel.getEnumSOPClassUIDs().getValue();
			ICommandElement objICEReqSOPClass = new CommandElement(0x0000, 0x0003,strSOPClassUID);
			objICommandSet.addCommandElement(objICEReqSOPClass);
			
//			//Set optional Field - Attribute Identifier List
//			ISingleCollection<ITag> objTagColl = objGetPrintMangMetaQueryModel.getTagCollection();
//			if(objTagColl != null)
//			{
//				ICommandElement objICEAttributeIdentifierList = new CommandElement(0x0000,0x1005,objTagColl);
//				objICommandSet.addCommandElement(objICEAttributeIdentifierList);
//			}
			
			//Set Command Set to DicomMessage
			objDicomMessage.setCommandSet(objICommandSet);
			
			ISingleCollection<IDataSet> objRstDataCollection = new SingleCollection<IDataSet>();
			if(retrieve(objDicomMessage, objRstDataCollection) == EnumImplOpsStatus.SUCCESS.getValue())
			{
				ICollectionIterator<IDataSet> objDataSetColl = objRstDataCollection.iterator();
				while(objDataSetColl.hasNext())
				{
					IDataSet objRstDataSet = objDataSetColl.next();
					objRstQueryModel.decode(objRstDataSet);
				}
				return EnumImplOpsStatus.SUCCESS.getValue();
			}
			else
				return EnumImplOpsStatus.FAILURE.getValue();	
		}
		else 
			return EnumImplOpsStatus.FAILURE.getValue();
	}
}
