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

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


import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IItem;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.enums.EnumCommandField;
import cdac.medinfo.sdk.dcm30_04.enums.EnumMetaSOPClassUID;
import cdac.medinfo.sdk.dcm30_04.enums.EnumSOPClassUIDs;
import cdac.medinfo.sdk.dcm30_04.exceptions.ConditionFailedException;
import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidDataSetException;
import cdac.medinfo.sdk.dcm30_04.exceptions.MandatoryMissingException;
import cdac.medinfo.sdk.dcm30_04.services.association.AssociateRQ;
import cdac.medinfo.sdk.dcm30_04.services.association.DefaultAssociation;
import cdac.medinfo.sdk.dcm30_04.services.association.RQPresContext;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumActionTypeID;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.ICommandSet;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.DicomMessage;
import cdac.medinfo.sdk.dcm30_04.services.naction.commons.NActionRQ;
import cdac.medinfo.sdk.dcm30_04.services.naction.scu.NActionSCU;
import cdac.medinfo.sdk.dcm30_04.services.ncreate.commons.NCreateRQ;
import cdac.medinfo.sdk.dcm30_04.services.ncreate.scu.NCreateSCU;
import cdac.medinfo.sdk.dcm30_04.services.ndelete.commons.NDeleteRQ;
import cdac.medinfo.sdk.dcm30_04.services.ndelete.scu.NDeleteSCU;
import cdac.medinfo.sdk.dcm30_04.services.nget.commons.NGetRQ;
import cdac.medinfo.sdk.dcm30_04.services.nget.scu.NGetSCU;
import cdac.medinfo.sdk.dcm30_04.services.nset.commons.NSetRQ;
import cdac.medinfo.sdk.dcm30_04.services.nset.scu.NSetSCU;
import cdac.medinfo.sdk.dcm30_04.services.scu.commons.SCU;
import cdac.medinfo.sdk.dcm30_04.services.scu.commons.SCUSession;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConfig;
import cdac.medinfo.sdk.dcm30_04.utils.DicomLogger;

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;

/**
 * Print SCU works as a SCU for Print Management Service Class.
 * Print Management Service class includes  meta SOP classes and some optional SOP Class.
 * The Meta SOP Class and the Optional SOP Class Supported by PrintSCU is
 * Basic GrayScale Print Management Meta SOP Class -
 *  	This Meta SOP class support following SOP classes
 *  	1) Basic Film Session SOP Class :- This class supports following Services N-Create,N-Set,N-Delete,N-Action services.
 *  	2) Basic Film Box SOP Class :- This class supports following Services N-Create,N-Set,N-Delete,N-Action services.
 *  	3) Basic GrayScale Image Box SOP Class :- This class supports following Services N-Set services.
 *  	4) Printer SOP Class :- This class supports following Services N-Get and N-Event Report services.
 *  
 * Basic Color Print Management Meta SOP Class
 * 		This Meta SOP class support following SOP classes
 * 		1)Basic Film Session SOP Class :- This class supports following Services N-Create,N-Set,N-Delete,N-Action services.
 * 		2)Basic Film Box SOP Class :- This class supports following Services N-Create,N-Set,N-Delete,N-Action services.
 * 		3)Basic Color Image Box SOP Class :- This class supports following Services N-Set services.
 * 		4)Printer SOP Class :- This class supports following Services N-Get and N-Event Report services.
 * 
 * Pull Print Meta SOP Class 
 * 		This Meta SOP class support following SOP classes
 * 		1)Pull Print Request SOP Class :- This class supports following Services N-Create , N-Action and N-Delete services.
 * 		2)Printer SOP Class :- This class supports following Services N-Get and N-Event Report services.
 * 
 * Following are the option SOP Class supported by Print Management Service Class with Basic Print Management SOP 
 * 		1)Basic Annotation Box SOP Class :- This class supports following Services N-Set services.
 * 		2)Print Job SOP Class :- This class supports following Services N-Get and N-Event Report services.
 * 		3)Basic print Image Overlay Box SOP Class.
 * 		4)Presentation LUT Sop Class :- This class supports following Services N-Create and N-Delete services.
 * 		5)Printer Configuration Retrieval SOP Class.
 * 		
 *  Following are the option SOP Class supported by Print Management Service Class with Pull Stored Print Management SOP
 *  	1) Print Job SOP Class :- This class supports following Services N-Get and N-Event Report services.
 *  	2) Presentation LUT Sop Class :- This class supports following Services N-Create and N-Delete services.
 *  	3)Printer Configuration Retrieval SOP Class.
 * Print_SCU is responsible to send the requests of supported N-Services and maintains the received response.
 */
public class PrintSCU extends SCU
{
	/**
	 * The IP and port to which user connects.
	 * @param strIP String value of IP to which user connects.
	 * @param port  Port to which user connects.
	 * @throws IOException Signals IO Exception if IO opeation fails.
	 */
	public PrintSCU(String strIP, int port) throws IOException
	{
		super(new InetSocketAddress(strIP,port));
	}

	/**
	 * The InetAddress and port to which user connects.
	 * @param addr InetAddress to which user connects.
	 * @throws IOException Signals IO Exception if IO opeation fails.
	 */
	public PrintSCU(InetSocketAddress addr) throws IOException
	{
		super(addr);
	}

	/**
	 * Instantiates a new Print_SCU on the SCU session provided by user.
	 * @param objSCUSession the object of SCU session on which  Print_SCU is to be initiated.
	 */
	public PrintSCU(SCUSession objSCUSession) 
	{
		super(objSCUSession);
	}

	/**
	 * This method creates associaition request according to the DataSet collection provided by the user and the Default association.
	 * Then it will perform the requested operation on the data set provided by the user, release the association and close the connection.
	 * @param strcallingAETitle value of Calling AE Title
	 * @param strCalledAETitle value of Called AE Title
	 * @param enumMetaSOPClassUID Meta Sop Class UID for which association for print mangement service is to be loaded.
	 * @param enumOptionalPrintSOPClassUIDs Option SOP Class UID s for which association is to be established with the Meta SOP Class provided.
	 * @param objEnumCommandField Enum Represents Element Command Field i.e. the type of service.
	 * @param enumSOPClassUIDs Affected SOP Class UID in the Command Set.
	 * @param strSOPInstanceUID Affected SOP Instance UID in the command Set.
	 * @param objIDataSet instance of dataset which is to be sent.
	 * @param objITagCollection list of requested attributes
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public void send(String strcallingAETitle,String strCalledAETitle,EnumMetaSOPClassUID enumMetaSOPClassUID,EnumSOPClassUIDs[] enumOptionalPrintSOPClassUIDs, EnumCommandField objEnumCommandField ,EnumSOPClassUIDs enumSOPClassUIDs, String strSOPInstanceUID, IDataSet objIDataSet,ISingleCollection<ITag> objITagCollection) throws IOException
	{
		DefaultAssociation objDefaultAssociation = null;
		objDefaultAssociation = new DefaultAssociation(strcallingAETitle);
		objDefaultAssociation.loadAssociation(enumOptionalPrintSOPClassUIDs);
		RQPresContext objRQPresContext = new RQPresContext();
		objRQPresContext.setAbstractSyntaxName(enumMetaSOPClassUID.getValue());
		ISingleCollection<String> objSingleCollection = new SingleCollection<String>();
		objSingleCollection.add(objIDataSet.getTransferSyntax().getTransferSyntaxUID());
		objRQPresContext.setTSCollection(objSingleCollection);
		objDefaultAssociation.addPresContext(objRQPresContext);
		AssociateRQ objAssociateRQ = objDefaultAssociation.getAssociationRQ(strCalledAETitle);
		send(objAssociateRQ,objEnumCommandField,enumSOPClassUIDs,strSOPInstanceUID,objIDataSet,objITagCollection);
	}

	/**
	 * Sends the available datasets to the SCP. While sending the datsets, if the connection is not made to the
	 * destination SCP, then the SCU first creates the connection. If the association is not created with the
	 * destination SCP, then the SCU first establishes the association and then sends the datasets.
	 * Note:
	 * The SCU will not close the connection, if already created connection is given to the SCU in the form of SCUSession.
	 * The SCU will neither release the association nor close the connection, if the association is already established
	 * with the destination SCP through SCUSession. User has to explicitly release the association and close the connection
	 * after completion of send process of Print SCU.
	 * @param objAssociateRQ The association request i.e. to be sent to SCP.
	 * @param objEnumCommandField  Enum Represents Element Command Field i.e. the type of service.
	 * @param enumSOPClassUIDs Affected SOP Class UID in the Command Set.
	 * @param strSOPInstanceUID Affected SOP Instance UID in the command Set.
	 * @param objIDataSet instance of dataset which is to be sent.
	 * @param objITagCollection list of requested attributes
	 * @throws IOException  Signals that an I/O exception has occurred.
	 */
	public void send(AssociateRQ objAssociateRQ,EnumCommandField objEnumCommandField, EnumSOPClassUIDs enumSOPClassUIDs, String strSOPInstanceUID,IDataSet objIDataSet,ISingleCollection<ITag> objITagCollection) throws IOException
	{
		if(objSCUSession != null)
		{
			sendRQ( objAssociateRQ, objEnumCommandField,enumSOPClassUIDs, strSOPInstanceUID, objIDataSet,objITagCollection);
		}
		else
		{
			objSCUSession = new SCUSession();
			objSCUSession.start(objInetSocketAddress);

			objSCUSession.setMessageListener(this);

			sendRQ( objAssociateRQ, objEnumCommandField, enumSOPClassUIDs,strSOPInstanceUID, objIDataSet,objITagCollection);

			if(!objSCUSession.getAssociationStatus())
			{
				if(objSCUSession.close())
					objSCUSession = null;
			}
		}
	}

	/*
	 * Send rq.
	 * @param objAssociateRQ the obj associate rq
	 * @param strSOPClasUID  SOP Class UID
	 * @param strSOPInstanceUID SOP Instance UID.
	 * @param objDataSetCollection the obj data set collection
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	private void sendRQ(AssociateRQ objAssociateRQ,EnumCommandField objEnumCommandField,EnumSOPClassUIDs enumSOPClassUIDs, String strSOPInstanceUID,IDataSet objIDataSet,ISingleCollection<ITag> objITagCollection) throws IOException
	{
		boolean associationStatusForSession = objSCUSession.getAssociationStatus();
		if(!associationStatusForSession)
		{
			objSCUSession.associate(objAssociateRQ);
		}
		if(objEnumCommandField == EnumCommandField.N_CREATE_RQ)
		{
			NCreateRQ objNCreateRQ = NCreateRQ.getDefaultRQ(enumSOPClassUIDs.getValue(), strSOPInstanceUID, objIDataSet);
			sendMessage(objNCreateRQ);
		}
		else if (objEnumCommandField == EnumCommandField.N_SET_RQ)
		{
			NSetRQ objNSetRQ = NSetRQ.getDefaultRQ(enumSOPClassUIDs.getValue(), strSOPInstanceUID, objIDataSet);
			sendMessage(objNSetRQ);
		}
		else if (objEnumCommandField == EnumCommandField.N_GET_RQ)
		{
			NGetRQ objNGetRQ = NGetRQ.getDefaultRQ(enumSOPClassUIDs.getValue(), strSOPInstanceUID, objITagCollection);
			sendMessage(objNGetRQ);
		}
		else if (objEnumCommandField == EnumCommandField.N_DELETE_RQ)
		{
			NDeleteRQ objNDeleteRQ = NDeleteRQ.getDefaultRQ(enumSOPClassUIDs.getValue(), strSOPInstanceUID);
			sendMessage(objNDeleteRQ);
		}
		else if (objEnumCommandField == EnumCommandField.N_ACTION_RQ)
		{
			NActionRQ objNDeleteRQ = NActionRQ.getDefaultRQ(enumSOPClassUIDs.getValue(), strSOPInstanceUID,EnumActionTypeID.PRINT_ACTION,objIDataSet);
			sendMessage(objNDeleteRQ);
		}

		if(!associationStatusForSession)
		{
			objSCUSession.releaseAssociation();
		}
	}

	/**
	 * This method sends the Request for Print Service Mangement Service.
	 * If the Service is supported by Print management service and is supported in association then
	 * it is send to the Service Provider and this function returns true. If the message cannot be sent to the Serive Provide (SCP)
	 * then this function returns false. Logging is done if logging is enables in SDK. 
	 * @param objDicomMessage  instance of Dicom Message containing Request for Print Management Service..
	 * @return true, if send message
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public boolean sendMessage(DicomMessage objDicomMessage) throws IOException 
	{
		/* at the time of sending message the SCU should register itself as message listener to SCU session.
		 * because if mutiple request are send through the SCU session then when response is recieved which
		 * SCU should be notified. If Message listener is set at time of sending message then in case of sync mode 
		 * the response is recived to the proper SCU.
		 */
		associateStatus = objSCUSession.getAssociationStatus();
		objSCUSession.setMessageListener(this);
		boolean isConnected = objSCUSession.connectionState();
		if(isConnected)
		{
			if(associateStatus)
			{
				String strSOPClassUID = null;
				IDataSet objIDataSet = objDicomMessage.getDataSet();
				ICommandSet objICommandSet = objDicomMessage.getCommandSet();
				EnumCommandField enumRequestType = objDicomMessage.getCommandType();
				if(enumRequestType == EnumCommandField.N_SET_RQ || enumRequestType == EnumCommandField.N_DELETE_RQ || enumRequestType == EnumCommandField.N_ACTION_RQ || enumRequestType == EnumCommandField.N_GET_RQ)
					strSOPClassUID = (String)objICommandSet.getValue(0x0000,0x0003);
				else
					strSOPClassUID = (String)objICommandSet.getValue(0x0000,0x0002);

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

				switch(enumSOPClassUIDs)
				{
				case BASICFILMSESSIONIOD :
					switch(enumRequestType) 
					{
					case N_CREATE_RQ :
						if(validateNCreateRQ(enumSOPClassUIDs,objIDataSet))
						{
							NCreateSCU objNCreateSCU = new NCreateSCU(objSCUSession);
							objNCreateSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNCreateSCU.sendMessage(objDicomMessage);
							return status;
						}
					case N_SET_RQ :
						if(validateNSetRQ(enumSOPClassUIDs,objIDataSet))
						{
							NSetSCU objNSetSCU = new NSetSCU(objSCUSession);
							objNSetSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNSetSCU.sendMessage(objDicomMessage);
							return status;
						}
					case N_DELETE_RQ :
					{
						NDeleteSCU objNDeleteSCU = new NDeleteSCU(objSCUSession);
						objNDeleteSCU.setDIMSEResponse(objDIMSERSPCollection);
						boolean status = objNDeleteSCU.sendMessage(objDicomMessage);
						return status;
					}
					case N_ACTION_RQ :
						NActionRQ objNActionRQ = new NActionRQ(objDicomMessage);
						if(validateNActionRQ(enumSOPClassUIDs,objIDataSet,objNActionRQ))
						{
							NActionSCU objNActionSCU = new NActionSCU(objSCUSession);
							objNActionSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNActionSCU.sendMessage(objDicomMessage);
							return status;
						}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				case BASICFILMBOXIOD :
					switch(enumRequestType)
					{
					case N_CREATE_RQ :
						if(validateNCreateRQ(enumSOPClassUIDs,objIDataSet))
						{
							NCreateSCU objNCreateSCU = new NCreateSCU(objSCUSession);
							objNCreateSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNCreateSCU.sendMessage(objDicomMessage);
							return status;
						}
					case N_SET_RQ :
						if(validateNSetRQ(enumSOPClassUIDs,objIDataSet))
						{
							NSetSCU objNSetSCU = new NSetSCU(objSCUSession);
							objNSetSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNSetSCU.sendMessage(objDicomMessage);
							return status;
						}
					case N_DELETE_RQ :
					{
						NDeleteSCU objNDeleteSCU = new NDeleteSCU(objSCUSession);
						objNDeleteSCU.setDIMSEResponse(objDIMSERSPCollection);
						boolean status = objNDeleteSCU.sendMessage(objDicomMessage);
						return status;
					}
					case N_ACTION_RQ :
						NActionRQ objNActionRQ = new NActionRQ(objDicomMessage);
						if(validateNActionRQ(enumSOPClassUIDs,objIDataSet,objNActionRQ))
						{
							NActionSCU objNActionSCU = new NActionSCU(objSCUSession);
							objNActionSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNActionSCU.sendMessage(objDicomMessage);
							return status;
						}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				case BASICGRAYSCALEIMAGEBOX :
					switch(enumRequestType)
					{
					case N_SET_RQ:
						if(validateNSetRQ(enumSOPClassUIDs,objIDataSet))
						{
							NSetSCU objNSetSCU = new NSetSCU(objSCUSession);
							objNSetSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNSetSCU.sendMessage(objDicomMessage);
							return status;
						}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				case BASICCOLORIMAGEBOX :
					switch(enumRequestType)
					{
					case N_SET_RQ:
						if(validateNSetRQ(enumSOPClassUIDs,objIDataSet))
						{
							NSetSCU objNSetSCU = new NSetSCU(objSCUSession);
							objNSetSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNSetSCU.sendMessage(objDicomMessage);
							return status;
						}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				case PRINTERIOD :
					switch(enumRequestType)
					{
					case N_GET_RQ :
						if(validateNGetRQ(enumSOPClassUIDs,objIDataSet))
						{
							NGetSCU objNGetSCU = new NGetSCU(objSCUSession);
							objNGetSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNGetSCU.sendMessage(objDicomMessage);
							return status;
						}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				case BASICANNOTATIONBOX :
					switch(enumRequestType)
					{
					case N_SET_RQ:
						if(validateNSetRQ(enumSOPClassUIDs,objIDataSet))
						{
							NSetSCU objNSetSCU = new NSetSCU(objSCUSession);
							objNSetSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNSetSCU.sendMessage(objDicomMessage);
							return status;
						}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				case PRINTJOBIOD :
					switch(enumRequestType)
					{
					case N_GET_RQ :
						if(validateNGetRQ(enumSOPClassUIDs,objIDataSet))
						{
							NGetSCU objNGetSCU = new NGetSCU(objSCUSession);
							objNGetSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNGetSCU.sendMessage(objDicomMessage);
							return status;
						}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				case BASICPRINTIMAGEOVERLAYBOXIOD :
					switch(enumRequestType)
					{
					case N_CREATE_RQ:
						if(validateNCreateRQ(enumSOPClassUIDs,objIDataSet))
						{
							NCreateSCU objNCreateSCU = new NCreateSCU(objSCUSession);
							objNCreateSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNCreateSCU.sendMessage(objDicomMessage);
							return status;
						}
					case N_SET_RQ :
						if(validateNSetRQ(enumSOPClassUIDs,objIDataSet))
						{
							NSetSCU objNSetSCU = new NSetSCU(objSCUSession);
							objNSetSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNSetSCU.sendMessage(objDicomMessage);
							return status;
						}
					case N_DELETE_RQ:
					{
						NDeleteSCU objNDeleteSCU = new NDeleteSCU(objSCUSession);
						objNDeleteSCU.setDIMSEResponse(objDIMSERSPCollection);
						boolean status = objNDeleteSCU.sendMessage(objDicomMessage);
						return status;
					}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				case PRESENTATIONLUTIOD :
					switch(enumRequestType)
					{
					case N_CREATE_RQ:
						if(validateNCreateRQ(enumSOPClassUIDs,objIDataSet))
						{
							NCreateSCU objNCreateSCU = new NCreateSCU(objSCUSession);
							objNCreateSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNCreateSCU.sendMessage(objDicomMessage);
							return status;
						}
					case N_DELETE_RQ:
					{
						NDeleteSCU objNDeleteSCU = new NDeleteSCU(objSCUSession);
						objNDeleteSCU.setDIMSEResponse(objDIMSERSPCollection);
						boolean status = objNDeleteSCU.sendMessage(objDicomMessage);
						return status;
					}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				case PRINTERCONFIGURATIONRETRIEVAL :
					switch(enumRequestType)
					{
					case N_GET_RQ :
						if(validateNGetRQ(enumSOPClassUIDs,objIDataSet))
						{
							NGetSCU objNGetSCU = new NGetSCU(objSCUSession);
							objNGetSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNGetSCU.sendMessage(objDicomMessage);
							return status;
						}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				case PULLPRINTREQUESTIOD :
					switch(enumRequestType)
					{
					case N_CREATE_RQ:
						if(validateNCreateRQ(enumSOPClassUIDs,objIDataSet))
						{
							NCreateSCU objNCreateSCU = new NCreateSCU(objSCUSession);
							objNCreateSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNCreateSCU.sendMessage(objDicomMessage);
							return status;
						}
					case N_DELETE_RQ:
					{
						NDeleteSCU objNDeleteSCU = new NDeleteSCU(objSCUSession);
						objNDeleteSCU.setDIMSEResponse(objDIMSERSPCollection);
						boolean status = objNDeleteSCU.sendMessage(objDicomMessage);
						return status;
					}
					case N_ACTION_RQ :
						NActionRQ objNActionRQ = new NActionRQ(objDicomMessage);
						if(validateNActionRQ(enumSOPClassUIDs,objIDataSet,objNActionRQ))
						{
							NActionSCU objNActionSCU = new NActionSCU(objSCUSession);
							objNActionSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNActionSCU.sendMessage(objDicomMessage);
							return status;
						}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				case PRINTQUEUEMANAGEMENTIOD :
					switch(enumRequestType)
					{
					case N_GET_RQ:
						if(validateNGetRQ(enumSOPClassUIDs,objIDataSet))
						{
							NGetSCU objNGetSCU = new NGetSCU(objSCUSession);
							objNGetSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNGetSCU.sendMessage(objDicomMessage);
							return status;
						}
					case N_ACTION_RQ :
						NActionRQ objNActionRQ = new NActionRQ(objDicomMessage);
						if(validateNActionRQ(enumSOPClassUIDs,objIDataSet,objNActionRQ))
						{
							NActionSCU objNActionSCU = new NActionSCU(objSCUSession);
							objNActionSCU.setDIMSEResponse(objDIMSERSPCollection);
							boolean status = objNActionSCU.sendMessage(objDicomMessage);
							return status;
						}
					default :
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning","ServiceRequestNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ enumRequestType.toString());
						}
					}
				default :
					if(DicomConfig.createInstance().isLoggingOn())
					{
						DicomLogger objDicomLogger = DicomLogger.getLogger();
						objDicomLogger.log(ResourceBundleWrapper.getValue("exceptions","SOPClassUIDNotSupported",new Locale(DicomConfig.createInstance().getLocale()))+ strSOPClassUID);
					}
				}
			}
			else
			{
				if(DicomConfig.createInstance().isLoggingOn())
				{
					DicomLogger objDicomLogger = DicomLogger.getLogger();
					objDicomLogger.log(ResourceBundleWrapper.getValue("exceptions","Association.AssociationDoesNotExist",new Locale(DicomConfig.createInstance().getLocale())));
				}
			}
		}
		else
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(ResourceBundleWrapper.getValue("exceptions","SessionInvalidated",new Locale(DicomConfig.createInstance().getLocale())));
			}
		}
		return false;
	}

	/**
	 * This function validates the N-Create Data Set of the SOP Class UID specified.
	 * @param enumSOPClassUIDs SOP class UID for which DataSet needs to be validated for N-Create RQ.
	 * @param objIDataSet instance of dataset which is to be validated.
	 * @return  boolean - true if the dataset is validated successfully. Else return false.
	 * @throws InvalidDataSetException Signals if dataset validation fails.
	 */
	@SuppressWarnings("unchecked")
	public boolean validateNCreateRQ(EnumSOPClassUIDs enumSOPClassUIDs, IDataSet objIDataSet) throws InvalidDataSetException
	{
		if(enumSOPClassUIDs == EnumSOPClassUIDs.BASICFILMBOXIOD)
		{
			if(!objIDataSet.isPresent(0x2010, 0x0010))
				throw new MandatoryMissingException("2010,0010");
			if(!objIDataSet.isPresent(0x2010,0x0500))
				throw new MandatoryMissingException("2010,0500");
			else
			{
				ISingleCollection<IItem> objReferencedFilmSessionSequenceList = (ISingleCollection<IItem>)objIDataSet.getValue(0x2010,0x0500);
				for(IItem item : objReferencedFilmSessionSequenceList)
				{
					if(!item.contains(0x0008, 0x1150))
						throw new MandatoryMissingException("0008,1150");
					if(!item.contains(0x0008, 0x1155))
						throw new MandatoryMissingException("0008,1155");
				}
			}
			return true;
		}
		if(enumSOPClassUIDs == EnumSOPClassUIDs.PRESENTATIONLUTIOD)
		{
			if(!objIDataSet.isPresent(0x2050, 0x0020) && !objIDataSet.isPresent(0x2050, 0x0010))
				throw new ConditionFailedException("2050,0010 required if 2050,0020 is not present");
			if(objIDataSet.isPresent(0x2050, 0x0010))
			{
				ISingleCollection<IItem> objPressentationLUTSequenceList = (ISingleCollection<IItem>)objIDataSet.getValue(0x2050, 0x0010);

				for(IItem item : objPressentationLUTSequenceList)
				{
					if(!item.contains(0x0028, 0x3002))
						throw new MandatoryMissingException("0028,3002");
					if(!item.contains(0x0028, 0x3006))
						throw new MandatoryMissingException("0028,3006");
				}
			}
			if(!objIDataSet.isPresent(0x2050, 0x0010) && !objIDataSet.isPresent(0x2050,0x0020))
				throw new MandatoryMissingException("2050,0020 is Required if 2050,0010 is not present");
		}
		if(enumSOPClassUIDs == EnumSOPClassUIDs.PULLPRINTREQUESTIOD)
		{
			if(!objIDataSet.isPresent(0x2000,0x0510))
				throw new MandatoryMissingException("2000,0510");
			else
			{
				ISingleCollection<IItem> objReferencedStoredPrintSequenceList = (ISingleCollection<IItem>)objIDataSet.getValue(0x2000,0x0510);
				for(IItem item : objReferencedStoredPrintSequenceList)
				{
					if(!item.contains(0x0008, 0x0054))
						throw new MandatoryMissingException("0008,0054");
					if(!item.contains(0x0008, 0x1150))
						throw new MandatoryMissingException("0x0008,1150");
					if(!item.contains(0x0008, 0x1155))
						throw new MandatoryMissingException("0x0008,1155");
					if(!item.contains(0x0020, 0x000D))
						throw new MandatoryMissingException("0020, 000D");
					if(!item.contains(0x0020, 0x000E))
						throw new MandatoryMissingException("0020, 000E");
				}
			}
		}
		if(enumSOPClassUIDs == EnumSOPClassUIDs.BASICPRINTIMAGEOVERLAYBOXIOD)
		{
			if(!objIDataSet.isPresent(0x2040,0x0020))
				throw new MandatoryMissingException("2040,0020");
			else
			{
				ISingleCollection<IItem> objOverLayPixelDataSequence = (ISingleCollection<IItem>)objIDataSet.getValue(0x2040,0x0020);
				for(IItem item : objOverLayPixelDataSequence)
				{
					if(!item.contains(0x6000, 0x0010))
						throw new MandatoryMissingException("6000,0010");
					if(!item.contains(0x6000, 0x0011))
						throw new MandatoryMissingException("6000,0011");
					if(!item.contains(0x6000, 0x0050))
						throw new MandatoryMissingException("6000,0050");
					if(!item.contains(0x6000, 0x0100))
						throw new MandatoryMissingException("6000,0100");
					if(!item.contains(0x6000, 0x0102))
						throw new MandatoryMissingException("6000,0102");
					if(!item.contains(0x6000, 0x3000))
						throw new MandatoryMissingException("6000,3000");
				}
			}
			if(objIDataSet.isPresent(0x2040, 0x0072) ^ objIDataSet.isPresent(0x2040, 0x0074))
				throw new ConditionFailedException("Either both or none should be present 2040,0072");
		}
		return true;
	}

	/**
	 * This function validates the N-Set Data Set of the SOP Class UID specified.
	 * @param enumSOPClassUIDs SOP class UID for which DataSet needs to be validated for N-Set RQ.
	 * @param objIDataSet instance of dataset which is to be validated.
	 * @return  boolean - true if the dataset is validated successfully. Else return false.
	 * @throws InvalidDataSetException Signals if dataset validation fails.
	 */
	@SuppressWarnings("unchecked")
	public boolean validateNSetRQ(EnumSOPClassUIDs enumSOPClassUIDs,IDataSet objIDataSet) throws InvalidDataSetException
	{
		if(enumSOPClassUIDs == EnumSOPClassUIDs.BASICGRAYSCALEIMAGEBOX)
		{
			if(!objIDataSet.isPresent(0x2020, 0x0010))
				throw new MandatoryMissingException("2020,0010");
			if(!objIDataSet.isPresent(0x2020, 0x0110))
				throw new MandatoryMissingException("2020,0111");
			else
			{
				ISingleCollection<IItem> objBasicGrayScaleImageSequence = (ISingleCollection<IItem>)objIDataSet.getValue(0x2020, 0x0110);
				for(IItem item : objBasicGrayScaleImageSequence)
				{
					if(!item.contains(0x0028, 0x0002))
						throw new MandatoryMissingException("0028,0002");
					if(!item.contains(0x0028, 0x0004))
						throw new MandatoryMissingException("0028,0004");
					if(!item.contains(0x0028, 0x0010))
						throw new MandatoryMissingException("0028,0010");
					if(!item.contains(0x0028, 0x0011))
						throw new MandatoryMissingException("0028,0011");
					if(!item.contains(0x0028, 0x0100))
						throw new MandatoryMissingException("0028,0100");
					if(!item.contains(0x0028, 0x0101))
						throw new MandatoryMissingException("0028,0101");
					if(!item.contains(0x0028, 0x0102))
						throw new MandatoryMissingException("0028,0102");
					if(!item.contains(0x0028, 0x0103))
						throw new MandatoryMissingException("0028,0103");
					if(!item.contains(0x7fe0, 0x0010))
						throw new MandatoryMissingException("7fe0,0010");
				}
			}
			if(objIDataSet.isPresent(0x2020, 0x0130))
			{
				ISingleCollection<IItem> objReferencedImageOverlaySequenceList = (ISingleCollection<IItem>)objIDataSet.getValue(0x2020, 0x0130);
				for(IItem item : objReferencedImageOverlaySequenceList)
				{
					if(!item.contains(0x0008, 0x1150))
						throw new ConditionFailedException("0008,1150");
					if(!item.contains(0x0008, 0x1155))
						throw new ConditionFailedException("0008,1155");
				}
			}
			if(objIDataSet.isPresent(0x2130, 0x00C0))
			{
				ISingleCollection<IItem> objOriginalImageSequenceList = (ISingleCollection<IItem>)objIDataSet.getValue(0x2050, 0x0500);
				for(IItem item : objOriginalImageSequenceList)
				{
					if(!item.contains(0x0020, 0x000D))
						throw new ConditionFailedException("0020,000D");
					if(!item.contains(0x0020, 0x000E))
						throw new ConditionFailedException("0020,000E");
					if(!item.contains(0x0010,0x0020))
						throw new ConditionFailedException("0010,0020");
					if(!item.contains(0x0008,0x1150))
						throw new ConditionFailedException("0008,1150");
					if(!item.contains(0x0008,0x1155))
						throw new ConditionFailedException("0008,1155");
					if(!item.contains(0x0008,0x1160))
						throw new ConditionFailedException("0008,1160");
					if(!item.contains(0x0020,0x0013))
						throw new ConditionFailedException("0020,0013");
				}
			}
		}
		if(enumSOPClassUIDs == EnumSOPClassUIDs.BASICCOLORIMAGEBOX)
		{
			if(!objIDataSet.isPresent(0x2020, 0x0010))
				throw new MandatoryMissingException("2020,0010");
			if(!objIDataSet.isPresent(0x2020, 0x0111))
				throw new MandatoryMissingException("2020,0111");
			else
			{
				ISingleCollection<IItem> objBasicGrayScaleImageSequence = (ISingleCollection<IItem>)objIDataSet.getValue(0x2020, 0x0110);
				for(IItem item : objBasicGrayScaleImageSequence)
				{
					if(!item.contains(0x0028, 0x0002))
						throw new MandatoryMissingException("0028,0002");
					if(!item.contains(0x0028, 0x0004))
						throw new MandatoryMissingException("0028,0004");
					if(!item.contains(0x0028, 0x0006))
						throw new MandatoryMissingException("0028,0006");
					if(!item.contains(0x0028, 0x0010))
						throw new MandatoryMissingException("0028,0010");
					if(!item.contains(0x0028, 0x0011))
						throw new MandatoryMissingException("0028,0011");
					if(!item.contains(0x0028, 0x0100))
						throw new MandatoryMissingException("0028,0100");
					if(!item.contains(0x0028, 0x0101))
						throw new MandatoryMissingException("0028,0101");
					if(!item.contains(0x0028, 0x0102))
						throw new MandatoryMissingException("0028,0102");
					if(!item.contains(0x0028, 0x0103))
						throw new MandatoryMissingException("0028,0103");
					if(!item.contains(0x7fe0, 0x0010))
						throw new MandatoryMissingException("7fe0,0010");
				}
			}
			if(objIDataSet.isPresent(0x2020, 0x0130))
			{
				ISingleCollection<IItem> objReferencedImageOverlaySequenceList = (ISingleCollection<IItem>)objIDataSet.getValue(0x2020, 0x0130);
				for(IItem item : objReferencedImageOverlaySequenceList)
				{
					if(!item.contains(0x0008, 0x1150))
						throw new ConditionFailedException("0008,1150");
					if(!item.contains(0x0008, 0x1155))
						throw new ConditionFailedException("0008,1155");
				}
			}
			if(objIDataSet.isPresent(0x2130, 0x00C0))
			{
				ISingleCollection<IItem> objOriginalImageSequenceList = (ISingleCollection<IItem>)objIDataSet.getValue(0x2050, 0x0500);
				for(IItem item : objOriginalImageSequenceList)
				{
					if(!item.contains(0x0020, 0x000D))
						throw new ConditionFailedException("0020,000D");
					if(!item.contains(0x0020, 0x000E))
						throw new ConditionFailedException("0020,000E");
					if(!item.contains(0x0010,0x0020))
						throw new ConditionFailedException("0010,0020");
					if(!item.contains(0x0008,0x1150))
						throw new ConditionFailedException("0008,1150");
					if(!item.contains(0x0008,0x1155))
						throw new ConditionFailedException("0008,1155");
					if(!item.contains(0x0008,0x1160))
						throw new ConditionFailedException("0008,1160");
					if(!item.contains(0x0020,0x0013))
						throw new ConditionFailedException("0020,0013");
				}
			}
		}
		if(enumSOPClassUIDs == EnumSOPClassUIDs.BASICANNOTATIONBOX)
		{
			if(!objIDataSet.isPresent(0x2030, 0x0010))
				throw new MandatoryMissingException("2020,0010");
		}
		if(enumSOPClassUIDs == EnumSOPClassUIDs.BASICPRINTIMAGEOVERLAYBOXIOD)
		{
			if(objIDataSet.isPresent(0x2040, 0x0072) ^ objIDataSet.isPresent(0x2040, 0x0074))
				throw new ConditionFailedException("Either both or none should be present 2040,0072");
		}
		return true;
	}

	/**
	 * This function validates the N-Action Data Set of the SOP Class UID specified.
	 * @param enumSOPClassUIDs SOP class UID for which DataSet needs to be validated for N-Action RQ.
	 * @param objIDataSet instance of dataset which is to be validated.
	 * @return boolean - true if the dataset is validated successfully. Else return false.
	 * @throws InvalidDataSetException Signals if dataset validation fails.
	 */
	public boolean validateNActionRQ(EnumSOPClassUIDs enumSOPClassUIDs, IDataSet objIDataSet, NActionRQ objNActionRQ) throws InvalidDataSetException
	{
		if(enumSOPClassUIDs.equals(EnumSOPClassUIDs.PRINTQUEUEMANAGEMENTIOD))
		{
			if(objNActionRQ.getActionTypeID() == 1)
			{
				if(!objIDataSet.isPresent(0x2100,0x0010))
					throw new MandatoryMissingException("2100, 0010");
				if(!objIDataSet.isPresent(0x2000, 0x0020))
					throw new MandatoryMissingException("2000, 0020");
				if(!objIDataSet.isPresent(0x2100, 0x0160))
					throw new MandatoryMissingException("2100, 0160");
			}
			else if(objNActionRQ.getActionTypeID() == 2)
			{
				if(!objIDataSet.isPresent(0x2100,0x0010))
					throw new MandatoryMissingException("2100, 0010");
				if(!objIDataSet.isPresent(0x2100, 0x0160))
					throw new MandatoryMissingException("2100, 0160");
			}
		}
		return true;
	}

	/**
	 * This function validates the N-Get Data Set of the SOP Class UID specified.
	 * @param enumSOPClassUIDs SOP class UID for which DataSet needs to be validated for N-Get RQ.
	 * @param objIDataSet instance of dataset which is to be validated.
	 * @return boolean - true if the dataset is validated successfully. Else return false.
	 * @throws InvalidDataSetException Signals if dataset validation fails.
	 */
	public boolean validateNGetRQ(EnumSOPClassUIDs enumSOPClassUIDs,IDataSet objIDataSet) throws InvalidDataSetException
	{
		return true;
	}
}

