package cdac.medinfo.sdk.dcm30_04.services.wadors;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import cdac.medinfo.sdk.dcm30_04.baselibs.DataSet;
import cdac.medinfo.sdk.dcm30_04.baselibs.ImplicitDE;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDictionaryReader;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPDUType;
import cdac.medinfo.sdk.dcm30_04.enums.EnumSOPClassUIDs;
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.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.cget.commons.CGetRQ;
import cdac.medinfo.sdk.dcm30_04.services.cget.commons.CGetRSP;
import cdac.medinfo.sdk.dcm30_04.services.cget.scu.CGetSCU;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.DicomMessage;
import cdac.medinfo.sdk.dcm30_04.services.scu.commons.SCUSession;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConstants;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;

/**
 * This class retrieves the data from the service
 * It send the request to server and return the status and DICOM file path from the server
 *
 */
public class RetriveDataServer {
	static String path = System.getProperty("java.io.tmpdir")+"/CDAC-SDK/DCM-J/DicomDump/";
	/**
	 * This class retrieves the DICOM instance from the service. 
	 * @param studyInstanceUID
	 * @param seriesInstanceUID
	 * @param sopInstanceUID
	 * @return String path of the file
	 * @throws IOException
	 */

	public String getStudyInstanceUID(String studyInstanceUID ,String seriesInstanceUID ,String sopInstanceUID) throws IOException
	{
		//SCU Session.
		SCUSession objSession = null;
		
		try
		{
			//Create SCUSession object
			objSession = new SCUSession();
			
			/*
			 * Setting time out as 5000 milli second. It will wait 5000 mili seconds for read and write operation.
			 * If in the time specified (5000 ms) read or write operation is not performed then 
			 * session is time out.
			 */ 
			//objSession.setTimeOut(5000);

			/*
			 * Initializes the service types and populates the default association
			 */
			RQPresContext objRQPresContextCGET = new RQPresContext();
			objRQPresContextCGET.setAbstractSyntaxName(EnumSOPClassUIDs.PATIENTROOTQUERYGET.getValue());
			objRQPresContextCGET.addTransferSyntax(DicomConstants.TS_DEFAULT_IMPLICIT_VR_LITTLE_ENDIAN);

			//RQ Pres Context for X-Ray
			RQPresContext objRQPresContextXRay = new RQPresContext();
			objRQPresContextXRay.setAbstractSyntaxName(EnumSOPClassUIDs.XRAYANGIOGRAPHICIOD.getValue());
			objRQPresContextXRay.addTransferSyntax(DicomConstants.TS_LOSSY_JPEG_8_BIT);

			//RQ Pres Context for CT
			RQPresContext objRQPresContextCT = new RQPresContext();
			objRQPresContextCT.setAbstractSyntaxName(EnumSOPClassUIDs.CTIOD.getValue());
			objRQPresContextCT.addTransferSyntax(DicomConstants.TS_DEFAULT_IMPLICIT_VR_LITTLE_ENDIAN);

			//RQ Pres Context for NM
			RQPresContext objRQPresContextNM = new RQPresContext();
			objRQPresContextNM.setAbstractSyntaxName(EnumSOPClassUIDs.NMIOD.getValue());
			objRQPresContextNM.addTransferSyntax(DicomConstants.TS_EXPLICIT_VR_LITTLE_ENDIAN);

			//RQ Pres Context for SC
			RQPresContext objRQPresContextSC = new RQPresContext();
			objRQPresContextSC.setAbstractSyntaxName(EnumSOPClassUIDs.SCIOD.getValue());
			objRQPresContextSC.addTransferSyntax(DicomConstants.TS_DEFAULT_IMPLICIT_VR_LITTLE_ENDIAN);

			ISingleCollection<RQPresContext> objPressConColl = new SingleCollection<RQPresContext>();
			objPressConColl.add(objRQPresContextXRay);
			objPressConColl.add(objRQPresContextCT);
			objPressConColl.add(objRQPresContextNM);
			objPressConColl.add(objRQPresContextSC);
			objPressConColl.add(objRQPresContextCGET);

			DefaultAssociation objDefaultAssociation = new DefaultAssociation("SDK");
			objDefaultAssociation.loadAssociation(objPressConColl);

			//Create Association RQ
			AssociateRQ objAssociateRQ = objDefaultAssociation.getAssociationRQ("SDK");

			//Start SCU Session by providing the IP address and Port of SCP.
			objSession.start("localhost", 9002);

			//Create CGet SCU object using the current SCU Session.
			CGetSCU objCGetSCU = new CGetSCU(objSession);
			
			
			//The destination path where the retrieved dataset should be stored.
			objCGetSCU.setDestinationPath(path);
		
			
			//Send the Association Request
			if(objSession.sendAssociationMessage(objAssociateRQ))
			{
				System.out.println("Assocaition is established");
				/*
				 * Creating DataSet for C-Get Request.
				 */
				IDataSet objIDataSet = new DataSet();
				IDictionaryReader objIDictionaryReader = objIDataSet.getDictionaryReader();
				//query parameter PatientID 322-292-73-6
				IDataElement objIDataStudy = new ImplicitDE(0x0020,0x000D,studyInstanceUID,objIDictionaryReader);
				objIDataSet.addDataElement(objIDataStudy);	
				if(seriesInstanceUID!=null){
				IDataElement objIDataSeries = new ImplicitDE(0x0020,0x000E,seriesInstanceUID,objIDictionaryReader);
				objIDataSet.addDataElement(objIDataSeries);
				}

				//Create Default CGetRQ by giving the DataSet. This method uses
				// default values for the attributes in the request. These attributes can be
				//modified once the request object is created, before sending.
				CGetRQ objCGetRQ = CGetRQ.getDefaultRQ(DicomConstants.DCM_PATIENT_ROOT_QUERY_OR_RETRIVE_INFORMATION_MODEL_GET, objIDataSet);
				
							
				//Send the C-Get-RQ and wait for a C-Get-RSP.
				//This method exits once the response is received. This response is 
				//added in the response collection maintained by the CGetSCU which
				//can be retrieved. This method return true if request is successfully sent 
				//to the SCP and false if the message cannot be sent to the SCP( for e.g. if 
				//the association status is false or if SOP class UID is not agreed in agreed association.
				
				
				
				if(objCGetSCU.sendMessage(objCGetRQ))
				{
					System.out.println("CGet operation performed");
					ISingleCollection<DicomMessage> objSingleCollection = objCGetSCU.getDIMSEResponse();
				
					
					System.out.println("Size of Response collection :: " + objSingleCollection.size());
					/*
					 * This will get the pending response from the Dicom Message and displays it.
					 */
					for(DicomMessage objDicomMessage : objSingleCollection)
					{
						CGetRSP objCGetRSP = new CGetRSP(objDicomMessage);
						System.out.println("Response Status  :" + Integer.toHexString(objCGetRSP.getStatus()));
					}
					
						
				
				System.out.println("CGet_SCU file destination path  =  "+objCGetSCU.getDestinationPath());
				}
				
				else
					System.out.println("CGet operation Failed");


				//Create A-Release-RQ to release the association
				AReleaseRQorRP objAReleaseRQorRP = new AReleaseRQorRP(EnumPDUType.RELEASE_RQ);

				//Send the A-Release-RQ
				if(objSession.sendAssociationMessage(objAReleaseRQorRP))
				{
					System.out.println("Release Response received");

					//When successful A-Release-RP is received, close the Session.
					//Please note that instead of closing the session we can create 
					//another association and send more requests. Also it is possible
					//to create multiple C-Get-RQs and send them one by one.
					objSession.close();
				}

				//In case an ABORT is received from SCP during the C-Get operation
				if(objSession.getDIMSEAssociation() instanceof AAbort)
				{
					System.out.println("Abort arrives. Closing session.");
					objSession.close();
				}
			}
			else
			{
				System.out.println("Association cannot be established");
				objSession.close();
			}
			return objCGetSCU.getDestinationPath();					
		}
		catch(Exception e)
		{
			e.printStackTrace();
			objSession.close();
		}
		return null;
	}


}
