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

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.util.Locale;


import cdac.medinfo.sdk.dcm30_04.baselibs.DataSet;
import cdac.medinfo.sdk.dcm30_04.baselibs.DicomV3Factory;
import cdac.medinfo.sdk.dcm30_04.baselibs.FailedSOPSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.ImplicitDE;
import cdac.medinfo.sdk.dcm30_04.baselibs.ReferencedSOPSequence;
import cdac.medinfo.sdk.dcm30_04.baselibs.ReferencedSOPSequenceItem;
import cdac.medinfo.sdk.dcm30_04.baselibs.TransferSyntax;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IItem;
import cdac.medinfo.sdk.dcm30_04.enums.EnumCommandField;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPDUType;
import cdac.medinfo.sdk.dcm30_04.exceptions.DicomException;
import cdac.medinfo.sdk.dcm30_04.services.association.AAbort;
import cdac.medinfo.sdk.dcm30_04.services.association.AReleaseRQorRP;
import cdac.medinfo.sdk.dcm30_04.services.association.AssociateAC;
import cdac.medinfo.sdk.dcm30_04.services.association.AssociateRJ;
import cdac.medinfo.sdk.dcm30_04.services.association.AssociateRQ;
import cdac.medinfo.sdk.dcm30_04.services.association.AssociationNegotiator;
import cdac.medinfo.sdk.dcm30_04.services.association.DefaultAssociation;
import cdac.medinfo.sdk.dcm30_04.services.association.IDIMSEAssociation;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumAbortReason;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumAbortSource;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumDataSink;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumDataSource;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumErrorCode;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumSCEventTypeID;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumSCPType;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumSCUType;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.IEventTypeID;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.ServiceException;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.SinkException;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.SourceException;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.DIMSEResponse;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.DicomMessage;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.IDataSink;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.IDataSource;
import cdac.medinfo.sdk.dcm30_04.services.scu.commons.SCU;
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.IPairedCollection;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.PairedCollection;
import cdac.medinfo.sdk.dcm30_04.utils.ResourceBundleWrapper;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;


/**
 * This class process the user request.
 * This is the default process handler of the SDK.
 */
public abstract class ProcessHandler implements IProcessHandler 
{
	/* The process request. */
	private  final String fProcessRequest ="processRequest";

	/* The data sink. */
	@SuppressWarnings("unused")
	private final String fDataSink = "setDataSink";

	/* The data sink. */
	private final String fDataSinkList = "setDataSinkList";

	/* The data source. */
	private final String fDataSource = "setDataSource";

	/* The data source. */
	private final String fDataSourceList = "setDataSourceList";

	/* The create instance. */
	private final String fCreateInstance = "createInstance";

	/* The add ae title info. */
	private  final String fAddAETitleInfo ="addAETitleInfo";

	private final String fSetStoragePath = "setStoragePath";

	private final String fSendMessage = "send";


	/* The obj enum command field. */
	private ISingleCollection<EnumCommandField> objEnumCommandField = null;

	String strStoragePath ;

	/* The obj supported ae titles. */
	private IPairedCollection<String, String> objSupportedAETitles = new PairedCollection<String, String>();

	/* Modification for TLS C-Move sub operation Task ZRC-5318 */
	//Paired collection containing AE Tile Info and TLS Client Config
	private IPairedCollection<String , Object> objSupportedAETitleCollWithClientConfig = new PairedCollection<String, Object>();
	
	/* Paired collection containing  DataSink*/
	private IPairedCollection<EnumDataSink, IDataSink> objDataSinkPairedCollection = new PairedCollection<EnumDataSink, IDataSink>();

	/* Paired collection containing  DataSource*/
	private IPairedCollection<EnumDataSource, IDataSource> objDataSourcePairedCollection = new PairedCollection<EnumDataSource, IDataSource>();

	private IPairedCollection<String, String> objIPPortCollection = new PairedCollection<String, String>();

	private String strStorageCommitmentPath;

	/**
	 * Add DataSink to Paired Collection 
	 * @param enumDataSink
	 * @param objIDataSink
	 */
	public void addDataSink(EnumDataSink enumDataSink, IDataSink objIDataSink)
	{
		objDataSinkPairedCollection.put(enumDataSink, objIDataSink);
	}

	/**
	 * Add DataSource to Paired Collection 
	 * @param enumDataSource
	 * @param objIDataSink
	 */
	public void addDataSource(EnumDataSource enumDataSource, IDataSource objIDataSource)
	{
		objDataSourcePairedCollection.put(enumDataSource, objIDataSource);
	}

	/**
	 * Returns the object of IDataSource from Paired Collection
	 * @param enumDataSource EnumDataSource
	 * @return object of IDataSource
	 */
	public IDataSource getDataSource(EnumDataSource enumDataSource)
	{
		return objDataSourcePairedCollection.get(enumDataSource);
	}

	/**
	 * Returns the object of IDataSink from Paired Collection
	 * @param enumDataSink EnumDataSink
	 * @return object of IDataSink
	 */
	public IDataSink getDataSink(EnumDataSink enumDataSink)
	{
		return objDataSinkPairedCollection.get(enumDataSink);
	}

	/**
	 * Sets DataSourceList.
	 * @param objDataSourceList collection of DataSource
	 */
	public void setDataSourceList(IPairedCollection<EnumDataSource,IDataSource> objDataSourceList)
	{
		this.objDataSourcePairedCollection = objDataSourceList;
	}

	/**
	 * Retrieves DataSourceList
	 * @return IPairedCollection<EnumDataSource,IDataSource> - collection of DataSource
	 */
	public IPairedCollection<EnumDataSource,IDataSource> getDataSourceList()
	{
		return objDataSourcePairedCollection;
	}

	/**
	 * Sets DataSinkList.
	 * @param objDataSinkList collection of DataSink
	 */
	public void setDataSinkList(IPairedCollection<EnumDataSink,IDataSink> objDataSinkList)
	{
		this.objDataSinkPairedCollection = objDataSinkList;
	}

	/**
	 * Retrieves DataSinkList
	 * @return IPairedCollection<EnumDataSink,IDataSink> - collection of DataSink
	 */
	public IPairedCollection<EnumDataSink,IDataSink> getDataSinkList()
	{
		return objDataSinkPairedCollection;
	}

	/**
	 * Gets the enum command field.
	 * @return the enum command field
	 */
	public ISingleCollection<EnumCommandField> getEnumCommandField() 
	{
		return objEnumCommandField;
	}

	/**
	 * Sets the enum command field.
	 * @param objEnumCommandField the new enum command field
	 */
	public void setEnumCommandField(ISingleCollection<EnumCommandField> objEnumCommandField) 
	{
		this.objEnumCommandField = objEnumCommandField;
	}

	/**
	 * Gets the supported ae titles.
	 * @return the supported ae titles
	 */
	public IPairedCollection<String, String> getSupportedAETitles() 
	{
		return objSupportedAETitles;
	}
	
	/* Modification for TLS C-Move sub operation Task ZRC-5318 */
	/**
	 * Gets the supported AE titles having TLS Client Configuration with it.
	 * @return the supported AE titles
	 */
	public IPairedCollection<String, Object> getSupportedAETitlesWithTLSClientConfig() 
	{
		return objSupportedAETitleCollWithClientConfig;
	}

	/**
	 * Accept connection.
	 * @param objClientSession object of Client Session.
	 */
	public void onConnect(ClientSession objClientSession)
	{
		objClientSession.acceptConnection(true);
	}

	/**
	 * Process association.
	 * @param objClientSession object of Client Session.
	 * @throws IOException  Signals that an I/O exception has occurred.
	 */
	public void onAssociateReceive(ClientSession objClientSession)
	{		
		IDIMSEAssociation objAssociationResponse = null;
		EnumPDUType enumPDUType = null;
		IDIMSEAssociation objIDIMSEAssociateRQ = objClientSession.getDIMSEAssociation();

		if(objIDIMSEAssociateRQ != null)
			enumPDUType = objIDIMSEAssociateRQ.getPDUType();
		else
		{
			// System.out.println("Association PDU is null");
		}

		switch(enumPDUType)
		{
		case ASSOCIATE_RQ:
		{
			boolean associationStatus = objClientSession.getAssociationStatus();
			if(associationStatus)
			{
				if(DicomConfig.createInstance().isLoggingOn())
				{
					DicomLogger objDicomLogger = DicomLogger.getLogger();
					objDicomLogger.log(ResourceBundleWrapper.getValue("exceptions", "Association.UnexpectedAssociationRQ",new Locale(DicomConfig.createInstance().getLocale())));
				}
				/*
				 * If association already exists then abort will be generated
				 */
				AAbort objAAbort = new AAbort();
				objAAbort.setReason(EnumAbortReason.UNEXPECTED_PDU);
				objAAbort.setSource(EnumAbortSource.SERVICE_PROVIDER);

				objClientSession.sendAssociationMessage(objAAbort);
				return;
			}
			AssociateRQ objAssociateRQ = (AssociateRQ)objIDIMSEAssociateRQ;
			DefaultAssociation objDefaultAssociation = objClientSession.getDefaultAssociation();

			//			Negotiate
			AssociationNegotiator objAssNegotiator = new AssociationNegotiator();
			objAssociationResponse = objAssNegotiator.negotiate(objDefaultAssociation, objAssociateRQ);
			objClientSession.setAgreedAssociation(objAssNegotiator.getAgreedAssociation());
			if (objAssociationResponse instanceof AssociateAC) 
				enumPDUType = EnumPDUType.ASSOCIATE_AC;
			if (objAssociationResponse instanceof AssociateRJ) 
				enumPDUType = EnumPDUType.ASSOCIATE_RJ;
			//			Send Response
			objClientSession.sendAssociationMessage(objAssociationResponse);
			break;
		}
		case RELEASE_RQ:
		{
			objAssociationResponse = new AReleaseRQorRP(EnumPDUType.RELEASE_RP);
			//			Send Response
			objClientSession.sendAssociationMessage(objAssociationResponse);
			break;
		}
		case ABORT :
		{
			{
				// System.out.println("Abort has arrived Stop Porcessing -- Association is no longer available");
			}
		}
		}
	}

	/**
	 * Gets automatically invoked when exception occur while processing  data received  
	 * @param objClientSession - object of Client Session.
	 * @param ex - the exception object
	 * @param ErrorCode - the reason of the DicomException
	 */
	public void onException(ClientSession objClientSession,DicomException ex,EnumErrorCode ErrorCode)
	{
		switch(ErrorCode)
		{
		case REMOTE_CONNECTION_CLOSED:
		case PDUREADER_CLOSED:
		case SOCKET_TIMEOUT:
			objClientSession.close();
			break;
		case INVALID_COMMANDSET:
			if(objClientSession.getAssociationStatus())
			{
				AAbort objAAbort = new AAbort();
				objAAbort.setReason(EnumAbortReason.INVALID_PDU_PARAM_VALUE);
				objAAbort.setSource(EnumAbortSource.SERVICE_PROVIDER);
				objClientSession.sendAssociationMessage(objAAbort);
			}
			break;
		case INVALID_PDUTYPE:
			if(objClientSession.getAssociationStatus())
			{
				AAbort objAAbort = new AAbort();
				objAAbort.setReason(EnumAbortReason.INVALID_PDU_PARAM_VALUE);
				objAAbort.setSource(EnumAbortSource.SERVICE_PROVIDER);
				objClientSession.sendAssociationMessage(objAAbort);
			}
			break;
		case INVALID_ASSOCIATION_PRIMITIVE:
			if(objClientSession.getAssociationStatus())
			{
				AAbort objAAbort = new AAbort();
				objAAbort.setReason(EnumAbortReason.INVALID_PDU_PARAM_VALUE);
				objAAbort.setSource(EnumAbortSource.SERVICE_PROVIDER);
				objClientSession.sendAssociationMessage(objAAbort);
			}
			break;
		case AGRRED_PDU_LENGTH_VIOLATED:
			if(objClientSession.getAssociationStatus())
			{
				AAbort objAAbort = new AAbort();
				objAAbort.setReason(EnumAbortReason.INVALID_PDU_PARAM_VALUE);
				objAAbort.setSource(EnumAbortSource.SERVICE_PROVIDER);
				objClientSession.sendAssociationMessage(objAAbort);
			}
			break;
		case ASSOCIATION_NOT_EXISTS:
			break;
		case UNEXPECTED_DIMSE_ASSOCIATION:
			break;
		case UNKNOWN:
			if(objClientSession.getAssociationStatus())
			{
				AAbort objAAbort = new AAbort();
				objAAbort.setReason(EnumAbortReason.INVALID_PDU_PARAM_VALUE);
				objAAbort.setSource(EnumAbortSource.SERVICE_PROVIDER);
				objClientSession.sendAssociationMessage(objAAbort);
			}
			objClientSession.close();
			break;
		case INVALID_DICOM_MESSAGE:
			if(objClientSession.getAssociationStatus())
			{
				AAbort objAAbort = new AAbort();
				objAAbort.setReason(EnumAbortReason.INVALID_PDU_PARAM_VALUE);
				objAAbort.setSource(EnumAbortSource.SERVICE_PROVIDER);
				objClientSession.sendAssociationMessage(objAAbort);
			}
			break; 
		}
	}

	/**
	 * Process service request.
	 * @param objClientSession object of Client Session.
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	@SuppressWarnings("unchecked")
	public void onServiceRequest(ClientSession objClientSession) throws IOException
	{

		String strIP = null;
		String strPort = null ;
		try
		{
			DicomMessage objDicomMessage = objClientSession.getDicomMessage();
			EnumCommandField enumCommandField = objDicomMessage.getCommandType();

			switch(enumCommandField)
			{
			case N_CREATE_RQ:
			{

				SCP objNCreateSCP = instantiateSCP(EnumSCPType.NCREATE_SCP,objClientSession);
				Class cObjectClass = objNCreateSCP.getClass();
				//search for setDataSource method in CGetSCP and invoke it.
				Class cDataSinkList = IPairedCollection.class;
				Method mSetDataSinkList = cObjectClass.getMethod(fDataSinkList, cDataSinkList);
				mSetDataSinkList.invoke(objNCreateSCP,objDataSinkPairedCollection);

				//search for processRequest method in CGetSCP and invoke it.
				Class cDicomMessage = Class.forName(DicomConstants.DICOM_MESSAGE_QUALIFIED_NAME);
				Method mProcessRequest = cObjectClass.getMethod(fProcessRequest, cDicomMessage);
				DIMSEResponse objDResponse = (DIMSEResponse)mProcessRequest.invoke(objNCreateSCP, objClientSession.getDicomMessage());

				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);

				break;

			}
			case N_ACTION_RQ:
			{


				//get N-Action SCP.
				SCP objNActionSCP = instantiateSCP(EnumSCPType.NACTION_SCP,objClientSession);
				Class cObjectClass = objNActionSCP.getClass();

				//search for setDataSourceList method in N-ActionSCP and and invoke it.
				Class cDataSourceList = IPairedCollection.class;
				Method mSetDataSourceList = cObjectClass.getMethod(fDataSourceList, cDataSourceList);
				mSetDataSourceList.invoke(objNActionSCP,objDataSourcePairedCollection);

				//search for setDataSinkList method in N-ActionSCP and and invoke it.
				Class cDataSinkList = IPairedCollection.class;
				Method mSetDataSinkList = cObjectClass.getMethod(fDataSinkList, cDataSinkList);
				mSetDataSinkList.invoke(objNActionSCP,objDataSinkPairedCollection);

				//search processRequest in N-Action SCP and invoke it.
				Class cDicomMessage = Class.forName(DicomConstants.DICOM_MESSAGE_QUALIFIED_NAME);
				Method mProcessRequest = cObjectClass.getMethod(fProcessRequest, cDicomMessage);
				DIMSEResponse objDResponse = (DIMSEResponse)mProcessRequest.invoke(objNActionSCP, objClientSession.getDicomMessage());
				String strCallingAETile = objClientSession.getAgreedAssociation().getCallingAETitle();
				String strCalledAETile = objClientSession.getAgreedAssociation().getCalledAETitle();

				//Send N-Action RSP.
				IDataSet objNActionDataSet = (IDataSet)objDicomMessage.getDataSet().clone();
				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);

				//if the request is of Storage Commitment then retrieve DataSet from Storage Commitment Source IMPL
				//and Store them to provide Storage Commitment using Storage Commitment Source.
				//Then create N-Event Report SCU, create N-Event Report Request, and send it to N-Event Report Server
				if(objDicomMessage.getCommandSet().getValue(0x0000,0x0003).toString().equals(DicomConstants.DCM_STORAGE_COMMITMENT_PUSH_MODEL_SOP_CLASS))
				{
					//get DataSource and DataSink for Storage Commitment.
					IDataSink objIDataSink = objDataSinkPairedCollection.get(EnumDataSink.STORAGE_COMMITMENT_PUSH_MODEL);
					IDataSource objIDataSource = objDataSourcePairedCollection.get(EnumDataSource.STORAGE_COMMITMENT_PUSH_MODEL);

					//get IP and port of Calling AE Title which sends N-Action Request.
					String strIPPort = objIPPortCollection.get(strCallingAETile.trim());
					if(strIPPort != null)
					{
						strIP = strIPPort.substring(0,strIPPort.indexOf(':'));
						strPort = strIPPort.substring(strIPPort.indexOf(':')+1);
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("status", "NEventReportIPPortInformation", new Locale(DicomConfig.createInstance().getLocale()))+ "["+ strIP+","+strPort+"]");
						}
						//create N-Action SCU.
						InetSocketAddress objInetSocketAddress = new InetSocketAddress(strIP, Integer.parseInt(strPort));
						Object objNEventReportSCU = instantiateSCU(EnumSCUType.NEVENTREPORT_SCU,objInetSocketAddress);
						DicomMessage objTempDicomMessage = new DicomMessage();
						objTempDicomMessage.setDataSet(objNActionDataSet);
						Class cSCUClass = objNEventReportSCU.getClass();

						//retrieve the data set and Store them for Storage Commitment.
						IDataSet objIDataSet = retrieveAndStore(objTempDicomMessage, objIDataSource, objIDataSink);

						//Send N-Event Report Request.
						Method mSendMessage = cSCUClass.getMethod(fSendMessage, String.class, String.class,String.class,String.class,IEventTypeID.class,IDataSet.class);
						mSendMessage.invoke(objNEventReportSCU, strCallingAETile, strCalledAETile, DicomConstants.DCM_STORAGE_COMMITMENT_PUSH_MODEL_SOP_CLASS, DicomConstants.DCM_STORAGE_COMMITMENT_PUSH_MODEL_SOP_INSTANCE, EnumSCEventTypeID.STORAGE_COMMITMENT_ACTION_TYPE_ID, objIDataSet);
					}
					else
					{
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger objDicomLogger = DicomLogger.getLogger();
							objDicomLogger.log(ResourceBundleWrapper.getValue("warning", "NEvent.IPPortNotKnown",new Locale(DicomConfig.createInstance().getLocale())) + strCallingAETile);
						}
					}
				}

				break;
			}

			case N_SET_RQ: 
			{

				SCP objNSetSCP = instantiateSCP(EnumSCPType.NSET_SCP,objClientSession);
				Class cObjectClass = objNSetSCP.getClass();
				//search for setDataSource method in CGetSCP and invoke it.
				Class cDataSinkList = IPairedCollection.class;
				Method mSetDataSinkList = cObjectClass.getMethod(fDataSinkList, cDataSinkList);
				mSetDataSinkList.invoke(objNSetSCP,objDataSinkPairedCollection);

				//search for processRequest method in CGetSCP and invoke it.
				Class cDicomMessage = Class.forName(DicomConstants.DICOM_MESSAGE_QUALIFIED_NAME);
				Method mProcessRequest = cObjectClass.getMethod(fProcessRequest, cDicomMessage);
				DIMSEResponse objDResponse = (DIMSEResponse)mProcessRequest.invoke(objNSetSCP, objClientSession.getDicomMessage());

				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);

				break;

			}
			case N_GET_RQ: 
			{

				SCP objNGetSCP = instantiateSCP(EnumSCPType.NGET_SCP,objClientSession);
				Class cObjectClass = objNGetSCP.getClass();
				//search for setDataSource method in CGetSCP and invoke it.
				Class cDataSourceList = IPairedCollection.class;
				Method mSetDataSourceList = cObjectClass.getMethod(fDataSourceList, cDataSourceList);
				mSetDataSourceList.invoke(objNGetSCP,objDataSourcePairedCollection);

				//search for processRequest method in CGetSCP and invoke it.
				Class cDicomMessage = Class.forName(DicomConstants.DICOM_MESSAGE_QUALIFIED_NAME);
				Method mProcessRequest = cObjectClass.getMethod(fProcessRequest, cDicomMessage);
				DIMSEResponse objDResponse = (DIMSEResponse)mProcessRequest.invoke(objNGetSCP, objClientSession.getDicomMessage());

				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);

				break;

			}
			case N_EVENT_REPORT_RQ: 
			{

				SCP objNEventReportSCP = instantiateSCP(EnumSCPType.NEVENTREPORT_SCP,objClientSession);
				Class cObjectClass = objNEventReportSCP.getClass();
				//search for setDataSource method in CGetSCP and invoke it.
				Class cDataSinkList = IPairedCollection.class;
				Method mSetDataSinkList = cObjectClass.getMethod(fDataSinkList, cDataSinkList);
				mSetDataSinkList.invoke(objNEventReportSCP,objDataSinkPairedCollection);

				//search for processRequest method in CGetSCP and invoke it.
				Class cDicomMessage = Class.forName(DicomConstants.DICOM_MESSAGE_QUALIFIED_NAME);
				Method mProcessRequest = cObjectClass.getMethod(fProcessRequest, cDicomMessage);
				DIMSEResponse objDResponse = (DIMSEResponse)mProcessRequest.invoke(objNEventReportSCP, objClientSession.getDicomMessage());

				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);

				break;

			}
			case C_GET_RQ:
			{
				//			Create CSTORE_SCP
				//			get RQ from ClientSession
				//			call processRequest and pass C_STORE_RQ on CSTORE_SCP
				//			receive response from CSTORE_SCP
				//			sendResponse using ClientSession
				IDataSource objDataSource =null;
				SCP objCGetSCP = instantiateSCP(EnumSCPType.CGET_SCP,objClientSession);
				Class cObjectClass = objCGetSCP.getClass();
				//search for setDataSource method in CGetSCP and invoke it.
				Class cDataSource = Class.forName(DicomConstants.DATA_SOURCE_QUALIFIED_NAME);
				Method mSetDataSource = cObjectClass.getMethod(fDataSource, cDataSource);
				if((objDicomMessage.getDataSet().getSOPClassUID())!=null)
				{
					if(objDicomMessage.getDataSet().getSOPClassUID().equals("1.2.840.10008.5.1.4.44.1")
							||objDicomMessage.getDataSet().getSOPClassUID().equals("1.2.840.10008.5.1.4.43.1")
							||objDicomMessage.getDataSet().getSOPClassUID().equals("1.2.840.10008.5.1.4.45.1")

						)
						objDataSource = objDataSourcePairedCollection.get(EnumDataSource.IMPLANTTEMPLATE);
					
					else if(objDicomMessage.getDataSet().getSOPClassUID().equals("1.2.840.10008.5.1.4.38.1"))
						 objDataSource = objDataSourcePairedCollection.get(EnumDataSource.HANGING_PROTOCOL);
					
					else if(objDicomMessage.getDataSet().getSOPClassUID().equals("1.2.840.10008.5.1.4.39.1"))
						 objDataSource = objDataSourcePairedCollection.get(EnumDataSource.COLOR_PALETTE);
				}
				else if(objDicomMessage.getDataSet().isPresent(0x0000, 0x0002))
				{
					 if(objDicomMessage.getDataSet().getDataForTag(0x0000, 0x0002).getValue().toString().equals("1.2.840.10008.5.1.4.1.2.5.3"))
					 {
							objDataSource = objDataSourcePairedCollection.get(EnumDataSource.COMPOSITE_INSTANCE_RETRIEVE_WITHOUT_BULK_DATA);
					 }
					if(objDicomMessage.getDataSet().getDataForTag(0x0000, 0x0002).getValue().toString().equals("1.2.840.10008.5.1.4.1.2.4.3"))
					{
							objDataSource = objDataSourcePairedCollection.get(EnumDataSource.IFLR);
					}
				}
				//IDataSource objDataSource = objDataSourcePairedCollection.get(EnumDataSource.MPPS_DataSource);
				else
				{
					 objDataSource = objDataSourcePairedCollection.get(EnumDataSource.CSERVICES);
				}

				mSetDataSource.invoke(objCGetSCP, objDataSource);

				//search for processRequest method in CGetSCP and invoke it.
				Class cDicomMessage = Class.forName(DicomConstants.DICOM_MESSAGE_QUALIFIED_NAME);
				Method mProcessRequest = cObjectClass.getMethod(fProcessRequest, cDicomMessage);
				DIMSEResponse objDResponse = (DIMSEResponse)mProcessRequest.invoke(objCGetSCP, objClientSession.getDicomMessage());

				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);

				break;
			}
			case C_FIND_RQ:
			{
				//			Create CFIND_SCP
				//			get RQ from ClientSession
				//			call processRequest and pass C_FIND_RQ on CFIND_SCP
				//			receive response from CFIND_SCP
				//			sendResponse using ClientSession


				SCP objCFindSCP = instantiateSCP(EnumSCPType.CFIND_SCP,objClientSession);
				Class cObjectClass = objCFindSCP.getClass();
				//search for setDataSource method in CGetSCP and invoke it.
				Class cDataSourceList = IPairedCollection.class;
				Method mSetDataSourceList = cObjectClass.getMethod(fDataSourceList, cDataSourceList);
				mSetDataSourceList.invoke(objCFindSCP,objDataSourcePairedCollection);

				//search for processRequest method in CFIND_SCP and invoke it.
				Class cDicomMessage = Class.forName(DicomConstants.DICOM_MESSAGE_QUALIFIED_NAME);
				Method mProcessRequest = cObjectClass.getMethod(fProcessRequest, cDicomMessage);
				DIMSEResponse objDResponse = (DIMSEResponse)mProcessRequest.invoke(objCFindSCP, objClientSession.getDicomMessage());

				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);

				break;
			}
			case C_ECHO_RQ:
			{
				//			Create CEcho SCP
				//			get RQ from ClientSession
				//			call processRequest and pass CEchoRQ on CEchoSCP
				//			receive response from CEchoSCP
				//			sendResponse using ClientSession

				DIMSEResponse objDResponse = null;


				SCP objCEchoSCP = instantiateSCP(EnumSCPType.CECHO_SCP,objClientSession);
				Class cObjectClass = objCEchoSCP.getClass();
				//search for processRequest method in CEcho SCP and invoke it.
				Class cDicomMessage = Class.forName(DicomConstants.DICOM_MESSAGE_QUALIFIED_NAME);
				Method mProcessRequest = cObjectClass.getMethod(fProcessRequest, cDicomMessage);
				objDResponse = (DIMSEResponse)mProcessRequest.invoke(objCEchoSCP, objClientSession.getDicomMessage());
				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);

				break;
			}
			case C_MOVE_RQ:
			{
				//			Create CSTORE_SCP
				//			get RQ from ClientSession
				//			call processRequest and pass C_STORE_RQ on CSTORE_SCP
				//			receive response from CSTORE_SCP
				//			sendResponse using ClientSession

				DIMSEResponse objDResponse = null;
				IDataSource objDataSource = null ;

				SCP objCMoveSCP = instantiateSCP(EnumSCPType.CMOVE_SCP,objClientSession);
				Class cObjectClass = objCMoveSCP.getClass();
				//search for setDataSource method in C_MOVE SCP and invoke it.
				Class cDataSource = Class.forName(DicomConstants.DATA_SOURCE_QUALIFIED_NAME);
				Method mSetDataSource = cObjectClass.getMethod(fDataSource, cDataSource);

				if((objDicomMessage.getDataSet().getSOPClassUID())!=null)
				{
					if(objDicomMessage.getDataSet().getSOPClassUID().equals("1.2.840.10008.5.1.4.44.1")
							||objDicomMessage.getDataSet().getSOPClassUID().equals("1.2.840.10008.5.1.4.43.1")
							||objDicomMessage.getDataSet().getSOPClassUID().equals("1.2.840.10008.5.1.4.45.1")

						)
						
						objDataSource = objDataSourcePairedCollection.get(EnumDataSource.IMPLANTTEMPLATE);
					
					else if(objDicomMessage.getDataSet().getSOPClassUID().equals("1.2.840.10008.5.1.4.38.1"))
						 objDataSource = objDataSourcePairedCollection.get(EnumDataSource.HANGING_PROTOCOL);
					
					else if(objDicomMessage.getDataSet().getSOPClassUID().equals("1.2.840.10008.5.1.4.39.1"))
						 objDataSource = objDataSourcePairedCollection.get(EnumDataSource.COLOR_PALETTE);
				}
				else if((objDicomMessage.getDataSet().getDataForTag(0x0000, 0x0002))!=null)
				{
					if(objDicomMessage.getDataSet().getDataForTag(0x0000, 0x0002).getValue().toString().equals("1.2.840.10008.5.1.4.1.2.4.2"))
					{
						objDataSource = objDataSourcePairedCollection.get(EnumDataSource.IFLR);
					}
				}
				else
				{
					 objDataSource = objDataSourcePairedCollection.get(EnumDataSource.CSERVICES);
				}

				mSetDataSource.invoke(objCMoveSCP, objDataSource);

				Object[] objAETitleName = objSupportedAETitles.getKeys();
				for(int i=0; i< objAETitleName.length; i++)
				{
					String strAETitleName = (String)objAETitleName[i];
					String strIPPortInfo = objSupportedAETitles.get(strAETitleName);
					String strIp = strIPPortInfo.substring(0,strIPPortInfo.indexOf(':'));
					int iPort = Integer.parseInt(strIPPortInfo.substring(strIPPortInfo.indexOf(':')+1));
					
					/* Modification for TLS C-Move sub operation Task ZRC-5318 */
					if(objSupportedAETitleCollWithClientConfig.contains(strAETitleName))
					{
						//search addAETitleInfo in C-Move SCP and invoke it.
						Class[] argType = { String.class, String.class,Integer.TYPE ,Object.class};
						Method mAddAETitleInfo = cObjectClass.getMethod(fAddAETitleInfo, argType);
						
						Object objTlsClientConfig = objSupportedAETitleCollWithClientConfig.get(strAETitleName);
						Object[] objParameter = new Object[4];
						objParameter[0] = strAETitleName;
						objParameter[1] = strIp;
						objParameter[2] = iPort;
						objParameter[3] = objTlsClientConfig;
						mAddAETitleInfo.invoke(objCMoveSCP, objParameter);
					}
					else
					{
						//search addAETitleInfo in C-Move SCP and invoke it.
						Class[] argType = { String.class, String.class,Integer.TYPE };
						Method mAddAETitleInfo = cObjectClass.getMethod(fAddAETitleInfo, argType);
						
						Object[] objParameter = new Object[3];
						objParameter[0] = strAETitleName;
						objParameter[1] = strIp;
						objParameter[2] = iPort;
						mAddAETitleInfo.invoke(objCMoveSCP, objParameter);
					}
				}

				//search for processRequest method in C_MOVE SCP and invoke it.
				Class cDicomMessage = Class.forName(DicomConstants.DICOM_MESSAGE_QUALIFIED_NAME);
				Method mProcessRequest = cObjectClass.getMethod(fProcessRequest, cDicomMessage);
				objDResponse = (DIMSEResponse)mProcessRequest.invoke(objCMoveSCP, objClientSession.getDicomMessage());
				{
					// System.out.println("C-Move RSP with success response sent");
				}
				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);

				break;
			}
			case C_STORE_RQ:
			{
				/*
				 * Create CSTORE_SCP get RQ from ClientSession call processRequest and pass C_STORE_RQ on CSTORE_SCP
				 * receive response from CSTORE_SCP sendResponse using ClientSession
				 */
				DIMSEResponse objDResponse = null;


				SCP objCStoreSCP = instantiateSCP(EnumSCPType.CSTORE_SCP,objClientSession);
				Class cObjectClass = objCStoreSCP.getClass();
				//search for setDataSink method in CStoreSCP and invoke it.
				Class cDataSinkList = IPairedCollection.class;
				Method mSetDataSinkList = cObjectClass.getMethod(fDataSinkList, cDataSinkList);
				mSetDataSinkList.invoke(objCStoreSCP,objDataSinkPairedCollection);

				//search setStoragePath in C-Store SCP and invoke it.
				Class[] argType = {String.class};
				Method mSetStoragePath = cObjectClass.getMethod(fSetStoragePath, argType);
				mSetStoragePath.invoke(objCStoreSCP, strStoragePath);

				//search for processRequest method in CSTORE_SCP and invoke it.
				Class cDicomMessage = Class.forName(DicomConstants.DICOM_MESSAGE_QUALIFIED_NAME);
				Method mProcessRequest = cObjectClass.getMethod(fProcessRequest, cDicomMessage);
				objDResponse = (DIMSEResponse)mProcessRequest.invoke(objCStoreSCP, objClientSession.getDicomMessage());
				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);

				break;
			}
			}
		}
		catch(ClassNotFoundException cnfe)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(cnfe);
			}
			onException(objClientSession, new ServiceException(ResourceBundleWrapper.getValue("exceptions", "ClassNotFoundException", new Locale(DicomConfig.createInstance().getLocale())),cnfe), EnumErrorCode.UNKNOWN) ;
		}
		catch(NoSuchMethodException nsme)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(nsme);
			}
			onException(objClientSession,  new ServiceException(ResourceBundleWrapper.getValue("exceptions", "NoSuchMethodException", new Locale(DicomConfig.createInstance().getLocale())),nsme),EnumErrorCode.UNKNOWN);
		}
		catch(IllegalAccessException iae)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(iae);
			}
			onException(objClientSession,  new ServiceException(ResourceBundleWrapper.getValue("exceptions", "IllegalAccessException", new Locale(DicomConfig.createInstance().getLocale())),iae),EnumErrorCode.UNKNOWN);
		}
		catch(InvocationTargetException iae)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				if(iae.getCause().getMessage().equalsIgnoreCase(ResourceBundleWrapper.getValue("exceptions", "ConnectionRefuseMessage",new Locale(DicomConfig.createInstance().getLocale()))));
				{
					objDicomLogger.log(ResourceBundleWrapper.getValue("exceptions", "NEvent.ConnectException",new Locale(DicomConfig.createInstance().getLocale())) + strIP + ":" + strPort);
				}
				objDicomLogger.log(iae);
			}
			onException(objClientSession,  new ServiceException(iae),EnumErrorCode.UNKNOWN);
		}
		catch(InstantiationException ie)
		{
			if(DicomConfig.createInstance().isLoggingOn())
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(ie);
			}
			onException(objClientSession,  new ServiceException(ie),EnumErrorCode.UNKNOWN);
		}
	}

	/**
	 * This function will add the AE Title info for third party.
	 * 
	 * @param strAETitle Name of AE Title.
	 * @param strIP IP where Server is running.
	 * @param iPort Port on which server is running.
	 */
	public void addSupportedAETitles(String strAETitle,String strIP,int iPort)
	{
		if(strAETitle != null && strIP != null)
			objSupportedAETitles.put(strAETitle.trim(), strIP.trim()+":"+iPort);
	}
	
	
	/* Modification for TLS C-Move sub operation Task ZRC-5318 */
	
	/**
	 * This function will add the AE Title info for third party.
	 * @param strAETitle Name of AE Title.
	 * @param strIP IP where Server is running.
	 * @param iPort Port on which server is running.
	 * @param objTlsServerConfig Object of TLSServerConfig
	 */
	public void addSupportedAETitles(String strAETitle,String strIP,int iPort, Object objTlsClientConfig)
	{
		if(objTlsClientConfig == null)
		{
			if(strAETitle != null && strIP != null)
				objSupportedAETitles.put(strAETitle.trim(), strIP.trim()+":"+iPort);
		}
		else
		{
			if(strAETitle != null && strIP != null)
			{
				objSupportedAETitles.put(strAETitle.trim(), strIP.trim()+":"+iPort);
				objSupportedAETitleCollWithClientConfig.put(strAETitle.trim(), objTlsClientConfig);
			}
		}
	}

	/**
	 * Instantiate scp.
	 * 
	 * @param enumClassname the enum classname
	 * @param objClientSession the obj client session
	 * 
	 * @return the sCP
	 * 
	 * @throws ClassNotFoundException the class not found exception
	 * @throws InvocationTargetException the invocation target exception
	 * @throws IllegalAccessException the illegal access exception
	 * @throws NoSuchMethodException the no such method exception
	 */
	@SuppressWarnings("unchecked")
	private SCP instantiateSCP(EnumSCPType enumClassname, ClientSession objClientSession) throws ClassNotFoundException,InvocationTargetException,IllegalAccessException,NoSuchMethodException
	{
		Class cClass= Class.forName(enumClassname.getValue()); //loading SCP class
		// Getting the method to be invoked
		Method method = cClass.getMethod(fCreateInstance, Class.forName(DicomConstants.CLIENT_SESSION_QUALIFIED_NAME));
		//System.out.println(method.toString());
		return (SCP)method.invoke(null,objClientSession);   // calling method and returning object.
	}

	/**
	 * This function sets the Storage Path for C-Store Operation
	 * @param strStoragePath String value of Storage Path.
	 */
	public void setStoragePath(String strStoragePath)
	{
		this.strStoragePath = strStoragePath;
	}

	/**
	 * Closes the Client Session,
	 */
	public void onClose(ClientSession objClientSession)
	{
		objClientSession.close();
	}

	@SuppressWarnings("unchecked")
	/*
	 * This method stores the Data Set and returns N-Event-Report Data Set.
	 */
	private IDataSet retrieveAndStore(DicomMessage objDicomMessage, IDataSource objIDataSource, IDataSink objIDataSink) 
	{
		if(DicomConfig.createInstance().isLoggingOn())
		{
			DicomLogger objDicomLogger = DicomLogger.getLogger();
			objDicomLogger.log(ResourceBundleWrapper.getValue("status","StoragePath",new Locale(DicomConfig.createInstance().getLocale()))+ strStorageCommitmentPath);
		}
		IDataSet objIDataSet = new DataSet();

		/*
		 * Create Instance of Reference SOP Sequence and Failed SOP Sequence,
		 * That are used in N-Event Report Request.
		 */
		ReferencedSOPSequence objRSPReferencedSOPSequence = (ReferencedSOPSequence)DicomV3Factory.createInstance().createSequence(0x0008,0x1199, new TransferSyntax(DicomConstants.TS_DEFAULT_IMPLICIT_VR_LITTLE_ENDIAN));
		FailedSOPSequence objRSPFailedSOPSequence = (FailedSOPSequence)DicomV3Factory.createInstance().createSequence(0x0008,0x1198, new TransferSyntax(DicomConstants.TS_DEFAULT_IMPLICIT_VR_LITTLE_ENDIAN));

		ISingleCollection<IDataSet> objDataSetCollection = new SingleCollection<IDataSet>();
		try
		{
			/*
			 * retrieve DataSet Collection, for which Storage Commitment has to be performed.
			 */
			objIDataSource.retrieve(objDicomMessage, objDataSetCollection);

			DicomMessage objTempDicomMessage = new DicomMessage();
			if(objDataSetCollection.size() != 0)
			{
				/*
				 * For each DataSet Collection Peform Storage Operation.
				 * If the Storage Operation is successfuly performed , then from SOP Class UID and SOP Instance UID 
				 * of the DataSet , Referenced SOP Sequence is created. If the Storage Operation is failed
				 * then Failed SOP Sequence is provided.
				 */
				for(IDataSet objTempIDataSet : objDataSetCollection)
				{
					try
					{
						objTempDicomMessage.setDataSet(objTempIDataSet);
						if(strStorageCommitmentPath != null)
						{
							objIDataSink.store(objTempDicomMessage, strStorageCommitmentPath);
							IItem objRSPReferencedSOPSequenceItem = objRSPReferencedSOPSequence.getNewItem();
							IDataElement objIDataElement = new ImplicitDE(0x0008,0x1155,objTempIDataSet.getValue(0x0008, 0x0018),objDicomMessage.getDataSet().getDictionaryReader());
							objRSPReferencedSOPSequenceItem.addDataElement(objIDataElement);
							objIDataElement = new ImplicitDE(0x0008,0x1150,objTempIDataSet.getValue(0x0008,0x0016),objDicomMessage.getDataSet().getDictionaryReader());
							objRSPReferencedSOPSequenceItem.addDataElement(objIDataElement);
							objRSPReferencedSOPSequence.addItem(objRSPReferencedSOPSequenceItem);
							if(DicomConfig.createInstance().isLoggingOn())
							{
								DicomLogger objDicomLogger = DicomLogger.getLogger();
								objDicomLogger.log(ResourceBundleWrapper.getValue("status","StorageCommitment.FileStoredSOPClass",new Locale(DicomConfig.createInstance().getLocale()))+ objTempIDataSet.getValue(0x0008,0x0016));
								objDicomLogger.log(ResourceBundleWrapper.getValue("status","StorageCommitment.FileStoredSOPInstance",new Locale(DicomConfig.createInstance().getLocale()))+ objTempIDataSet.getValue(0x0008,0x0018));
							}
						}
					}
					catch(SinkException se)
					{
						if(DicomConfig.createInstance().isLoggingOn())
						{
							DicomLogger.getLogger().log(se.getMessage());
							DicomLogger.getLogger().log(ResourceBundleWrapper.getValue("status","StorageCommitment.FileNotStoredSOPClass",new Locale(DicomConfig.createInstance().getLocale()))+ objTempIDataSet.getValue(0x0008,0x0016));
							DicomLogger.getLogger().log(ResourceBundleWrapper.getValue("status","StorageCommitment.FileNotStoredSOPInstance",new Locale(DicomConfig.createInstance().getLocale()))+ objTempIDataSet.getValue(0x0008,0x0018));
						}
						IItem objRSPFailedSOPSequenceItem = objRSPFailedSOPSequence.getNewItem();
						IDataElement objIDataElement = new ImplicitDE(0x0008,0x1155,objTempIDataSet.getValue(0x0008, 0x0018),objDicomMessage.getDataSet().getDictionaryReader());
						objRSPFailedSOPSequenceItem.addDataElement(objIDataElement);
						objIDataElement = new ImplicitDE(0x0008,0x1150,objTempIDataSet.getValue(0x0008,0x0016),objDicomMessage.getDataSet().getDictionaryReader());
						objRSPFailedSOPSequenceItem.addDataElement(objIDataElement);
						objRSPFailedSOPSequence.addItem(objRSPFailedSOPSequenceItem);
					}
				}
			}

			/*
			 * Now Failed SOP Sequence is to be created for the DataSets which are not retrieved.
			 */
			ISingleCollection<ReferencedSOPSequenceItem> objReferencedSOPSequenceItemCol = (ISingleCollection<ReferencedSOPSequenceItem>)objDicomMessage.getDataSet().getValue(0x0008,0x1199);
			for(ReferencedSOPSequenceItem objReferencedSOPSequenceItem : objReferencedSOPSequenceItemCol)
			{
				boolean isPresent = false;
				String strSOPClassUID = objReferencedSOPSequenceItem.getValue(0x0008,0x1150).toString();
				String strSOPInstanceUID = objReferencedSOPSequenceItem.getValue(0x0008,0x1155).toString();
				for(IDataSet objTempIDataSet : objDataSetCollection)
				{
					if(objTempIDataSet.getSOPClassUID().equals(strSOPClassUID) && objTempIDataSet.getValue(0x0008, 0x0018).toString().equals(strSOPInstanceUID))
					{
						isPresent = true;
						break;
					}
				}
				if(!isPresent)
				{
					if(DicomConfig.createInstance().isLoggingOn())
					{
						DicomLogger objDicomLogger = DicomLogger.getLogger();
						objDicomLogger.log(ResourceBundleWrapper.getValue("status", "StorageCommitment.RetrieveFailedSOPClass", new Locale(DicomConfig.createInstance().getLocale())) + strSOPClassUID);
						objDicomLogger.log(ResourceBundleWrapper.getValue("status", "StorageCommitment.RetrieveFailedSOPInstance", new Locale(DicomConfig.createInstance().getLocale())) + strSOPInstanceUID);
					}
					IItem objRSPFailedSOPSequenceItem = objRSPFailedSOPSequence.getNewItem();
					IDataElement objIDataElement = new ImplicitDE(0x0008,0x1155,strSOPInstanceUID,objDicomMessage.getDataSet().getDictionaryReader());
					objRSPFailedSOPSequenceItem.addDataElement(objIDataElement);
					objIDataElement = new ImplicitDE(0x0008,0x1150,strSOPClassUID,objDicomMessage.getDataSet().getDictionaryReader());
					objRSPFailedSOPSequenceItem.addDataElement(objIDataElement);
					objRSPFailedSOPSequence.addItem(objRSPFailedSOPSequenceItem);
				}
			}
			IDataElement objIDataElement = new ImplicitDE(0x0008,0x1199,objRSPReferencedSOPSequence,objIDataSet.getTransferSyntax(),objIDataSet.getDictionaryReader());
			objIDataSet.addDataElement(objIDataElement);
			objIDataElement = new ImplicitDE(0x0008,0x1198,objRSPFailedSOPSequence,objIDataSet.getTransferSyntax(),objIDataSet.getDictionaryReader());
			objIDataSet.addDataElement(objIDataElement);

		}
		catch(SinkException de)
		{
			objIDataSet = null;
			if(DicomConfig.createInstance().isLoggingOn() ) 
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(de.getMessage());
			}
		}
		catch(SourceException se)
		{
			objIDataSet = null;
			if(DicomConfig.createInstance().isLoggingOn() ) 
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(se.getMessage());
			}
		}
		catch(IOException ioe)
		{
			objIDataSet = null;
			if(DicomConfig.createInstance().isLoggingOn() ) 
			{
				DicomLogger objDicomLogger = DicomLogger.getLogger();
				objDicomLogger.log(ioe.getMessage());
			}
		}
		return objIDataSet;
	}

	/**
	 * Sets the path where the files for which storage commitment is provided is stored.
	 * @param strStorageCommitmentPath path where the files for which storage commitment is provided is stored.
	 */
	public void setStorageCommitmentPath(String strStorageCommitmentPath)
	{
		this.strStorageCommitmentPath = strStorageCommitmentPath;
	}

	/**
	 * Get the path where the files for whcih Storage Commitment is provided is stored.
	 * @return String value of path where the files for which storage commitment is provided is stored.
	 */
	public String getStorageCommitmentPath()
	{
		return strStorageCommitmentPath;
	}

	/**
	 * Add N-Event Report SCP IP and Port information for recieving N-Event Report Request.
	 * This information is used when Storage Comment Request is received.
	 * @param strAETile AE Title name.
	 * @param strIP String value of IP.
	 * @param port Port on whcih AETitle Server is started.
	 */
	public void addNEventReportSCPInformation(String strAETile, String strIP, int port)
	{
		objIPPortCollection.put(strAETile, strIP+":"+port);
	}

	/*
	 * this function initiates SCU.
	 */
	@SuppressWarnings("unchecked")
	private Object instantiateSCU(EnumSCUType enumClassname, InetSocketAddress objInetSocketAddress)throws ClassNotFoundException,NoSuchMethodException,InvocationTargetException,InstantiationException,IllegalAccessException
	{
		Class fSCU = Class.forName(enumClassname.getValue());
		Class[] fInetSocketAddress = new Class[]{InetSocketAddress.class};
		Object[] objInetSocketAddressObject = new Object[]{objInetSocketAddress};
		Constructor objArgsConstructor = fSCU.getConstructor(fInetSocketAddress);	
		SCU objSCU = (SCU)objArgsConstructor.newInstance(objInetSocketAddressObject);
		return objSCU;
	}

	/**
	 * This function gets the Storage Path for C-Store Operation
	 * @return strStoragePath String value of Storage Path.
	 */
	public String getStoragePath()
	{
		return strStoragePath;
	}
}
