#include "SDCMSendImpl.h"
//#include "SThreadProgress.h"

#include <stdio.h>

#ifdef UNICODE
#undef UNICODE
#undef _UNICODE
#define UNICODE_DEFINED
#endif

#include "dcmtk/dcmdata/dcfilefo.h"
#include "dcmtk/dcmnet/diutil.h"

#include "dcmtk/dcmdata/dcxfer.h"

#include "dcmtk/dcmjpeg/djdecode.h"  /* for JPEG decoders */
#include "dcmtk/dcmjpeg/djencode.h"  /* for JPEG encoders */
#include "dcmtk/dcmjpls/djdecode.h"  /* for JPEG-LS decoders */
#include "dcmtk/dcmjpls/djencode.h"  /* for JPEG-LS encoders */
#include "dcmtk/dcmdata/dcrledrg.h"  /* for RLE decoder */
#include "dcmtk/dcmdata/dcrleerg.h"  /* for RLE encoder */
#include "dcmtk/dcmjpeg/dipijpeg.h"  /* for dcmimage JPEG plugin */

#include "dcmtk/dcmnet/cond.h"

#ifdef UNICODE_DEFINED
#define UNICODE
#define _UNICODE
#undef UNICODE_DEFINED
#endif

#include <QFile>

#include <QThread>

#include <QElapsedTimer>

#include "cscallbacksendprogress.h"

/*
	typedef struct {
    void *callbackData;
    T_DIMSE_StoreProgress *progress;
    T_DIMSE_C_StoreRQ *request;
    DIMSE_StoreUserCallback callback;
	CSThread* pCallbackThread;
} DIMSE_PrivateUserContext;
*/

typedef struct _DIMSE_PrivateUserContext{
	void *callbackData;
	T_DIMSE_StoreProgress *progress;
	T_DIMSE_C_StoreRQ *request;
	DIMSE_StoreUserCallback callback;
	CSCallback* pCallback;
    CSDCMSendImpl* pThis;
    T_ASC_Association *assoc;
    bool bSendComplete;
} DIMSE_PrivateUserContext;


static void
privateUserCallback(void *callbackData, unsigned long bytes)
{
    DIMSE_PrivateUserContext *ctx;
    ctx = (DIMSE_PrivateUserContext*)callbackData;
    ctx->progress->state = DIMSE_StoreProgressing;
    ctx->progress->progressBytes = bytes;
    ctx->progress->callbackCount++;
    if (ctx->callback) {
        ctx->callback(ctx->callbackData, ctx->progress, ctx->request);
    }
}

#include "dcmtk/dcmdata/dcdict.h"
#include "dcmtk/dcmdata/dcdicent.h"

extern DCMTK_DCMDATA_EXPORT GlobalDcmDataDictionary dcmDataDict;

OFBool
isDataDictPresent()
{
    /* is a data dictionary present */
    return dcmDataDict.isDictionaryLoaded();
}




OFCondition CSDCMSendImpl::DIMSE_storeUser(
    T_ASC_Association *assoc, T_ASC_PresentationContextID presId,
    T_DIMSE_C_StoreRQ *request,
    const char *imageFileName, DcmDataset *imageDataSet,
    DIMSE_StoreUserCallback callback, void *callbackData,
    T_DIMSE_BlockingMode blockMode, int timeout,
    T_DIMSE_C_StoreRSP *response,
    DcmDataset **statusDetail,
    T_DIMSE_DetectedCancelParameters *checkForCancelParams,
    long imageFileTotalBytes)
    /*
     * This function transmits data from a file or a dataset to an SCP. The transmission is
     * conducted via network and using DIMSE C-STORE messages. Additionally, this function
     * evaluates C-STORE-Response messages which were received from the SCP.
     *
     * Parameters:
     *   assoc                - [in] The association (network connection to SCP).
     *   presId               - [in] The ID of the presentation context which shall be used
     *   request              - [in] Represents a DIMSE C-Store Request Message. Contains corresponding
     *                               information, e.g. message ID, affected SOP class UID, etc.
     *   imageFileName        - [in] The name of the file which is currently processed.
     *   imageDataSet         - [in] The data set which is currently processed.
     *   callback             - [in] Pointer to a function which shall be called to indicate progress.
     *   callbackData         - [in] Pointer to data which shall be passed to the progress indicating function
     *   blockMode            - [in] The blocking mode for receiving data (either DIMSE_BLOCKING or DIMSE_NONBLOCKING)
     *   timeout              - [in] Timeout interval for receiving data. If the blocking mode is DIMSE_NONBLOCKING
     *   response             - [out] Represents a DIMSE C-Store Response Message. Contains corresponding
     *                                information, e.g. message ID being responded to, affected SOP class UID, etc.
     *                                This variable contains in the end the C-STORE-RSP command which was received
     *                                as a response to the C-STORE-RQ which was sent.
     *   statusDetail         - [out] If a non-NULL value is passed this variable will in the end contain detailed
     *                                information with regard to the status information which is captured in the status
     *                                element (0000,0900) of the response message. Note that the value for element (0000,0900)
     *                                is not contained in this return value but in response.
     *   checkForCancelParams - [out] Indicates, if a C-Cancel (Request) Message was encountered. Contains corresponding
     *                                information, e.g. a boolean value if a corresponding message was encountered and the
     *                                C-Cancel (Request) Message itself (in case it actually was encountered).
     *   imageFileTotalBytes  - [in] The size of the file which is currently processed in bytes.
     */
{
    OFCondition cond = EC_Normal;
    T_DIMSE_Message req, rsp;
    DIMSE_PrivateUserContext callbackCtx;
    DIMSE_ProgressCallback privCallback = NULL;
    T_DIMSE_StoreProgress progress;

    /* if there is no image file or no data set, no data can be sent */
    if (imageFileName == NULL && imageDataSet == NULL) return DIMSE_NULLKEY;

    /* initialize the variables which represent DIMSE C-STORE request and DIMSE C-STORE response messages */
    bzero((char*)&req, sizeof(req));
    bzero((char*)&rsp, sizeof(rsp));

    /* set corresponding values in the request message variable */
    req.CommandField = DIMSE_C_STORE_RQ;
    request->DataSetType = DIMSE_DATASET_PRESENT;
    req.msg.CStoreRQ = *request;

    /* set up callback routine which is used to indicate progress */
    if (callback != NULL) {
        /* in case the caller indicated that he has his own progress indicating */
        /* function set some variables correspondingly so that this particular */
        /* function will be called whenever progress shall be indicated. */
        privCallback = privateUserCallback;     /* function defined above */
        callbackCtx.callbackData = callbackData;
        progress.state = DIMSE_StoreBegin;
        progress.callbackCount = 1;
        progress.progressBytes = 0;
        if (imageFileTotalBytes > 0) progress.totalBytes = imageFileTotalBytes;
        else
        {
          if (imageFileName != NULL) progress.totalBytes = OFstatic_cast(long, OFStandard::getFileSize(imageFileName));
          else progress.totalBytes = dcmGuessModalityBytes(request->AffectedSOPClassUID);
        }
        callbackCtx.progress = &progress;
        callbackCtx.request = request;
        callbackCtx.callback = callback;
        /* execute initial callback */
        callback(callbackData, &progress, request);
    } else {
        /* in case the caller does not have his own progress indicating function no */
        /* corresponding function will be called when progress shall be indicated. */
        privCallback = NULL;
    }

    /* send C-STORE-RQ message and instance data using file data or data set */
    if (imageFileName != NULL) {
        DcmDataset statusDetail;
        cond = DIMSE_sendMessageUsingFileData(assoc, presId, &req,
            &statusDetail, imageFileName, privCallback, &callbackCtx);
    } else {
        cond = DIMSE_sendMessageUsingMemoryData(assoc, presId, &req,
            NULL, imageDataSet, privCallback, &callbackCtx);
    }

    if (cond != EC_Normal) {
        return cond;
    }

    /* execute final callback */
    if (callback) {
        progress.state = DIMSE_StoreEnd;
        progress.callbackCount++;
        /* execute final callback */
        callback(callbackData, &progress, request);
    }

    /* check if a C-CANCEL-RQ message was encountered earlier */
    if (checkForCancelParams != NULL) {
        checkForCancelParams->cancelEncountered = OFFalse;
    }

    /* try to receive C-STORE-RSP */
    do
    {
        /* remember the ID of the presentation context in a local variable */
        T_ASC_PresentationContextID thisPresId = presId;

        /* try to receive a C-STORE-RSP over the network. */
        cond = DIMSE_receiveCommand(assoc, blockMode, timeout,
            &thisPresId, &rsp, statusDetail);
        if (cond != EC_Normal) return cond;

        /* if everything was successful so far, the rsp variable contains the command which */
        /* was received check if we encountered a C-CANCEL-RQ; if so, set some variables */
        if (checkForCancelParams != NULL && rsp.CommandField == DIMSE_C_CANCEL_RQ)
        {
            checkForCancelParams->cancelEncountered = OFTrue;
            checkForCancelParams->req = rsp.msg.CCancelRQ;
            checkForCancelParams->presId = thisPresId;
        } else {
        /* if we did not receive a C-CANCEL-RQ */

            /* if we did also not encounter a C-STORE-RSP, something is wrong */
            if (rsp.CommandField != DIMSE_C_STORE_RSP)
            {
              char buf[256];
              sprintf(buf, "DIMSE: Unexpected Response Command Field: 0x%x", (unsigned)rsp.CommandField);
              return makeDcmnetCondition(DIMSEC_UNEXPECTEDRESPONSE, OF_error, buf);
            }
        /* if we get to here, we received a C-STORE-RSP; store this message in the reference parameter */
            *response = rsp.msg.CStoreRSP;          // BoundsChecker warning !?

            /* check if the response relates to the request which was sent earlier; if not, return an error */
            if (response->MessageIDBeingRespondedTo != request->MessageID)
            {
              char buf2[256];
              sprintf(buf2, "DIMSE: Unexpected Response MsgId: %d (expected: %d)", response->MessageIDBeingRespondedTo, request->MessageID);
              return makeDcmnetCondition(DIMSEC_UNEXPECTEDRESPONSE, OF_error, buf2);
            }
        }
    } while (checkForCancelParams != NULL && rsp.CommandField == DIMSE_C_CANCEL_RQ);

    /* return result value */
    return EC_Normal;
}




//OFLogger *m_pLoggerStoreSCU("store.log", OFLogger::TRACE_LOG_LEVEL);

CSDCMSendImpl::CSDCMSendImpl()
{
	m_pCallback = NULL;
    //COleDateTime dt = COleDateTime::GetCurrentTime();

	char strLog[128];
    memset(strLog, 0, 128);

	//sprintf(strLog, "store_%04d%02d%02d.log", dt.GetYear(), dt.GetMonth(), dt.GetDay());
	sprintf(strLog, "store.log");

    OFLogger log = OFLog::getLogger(strLog);
    m_pLoggerStoreSCU = &log;
    m_pLoggerStoreSCU->setLogLevel(dcmtk::log4cplus::FATAL_LOG_LEVEL);

    //m_pLoggerStoreSCU->Delete();
    //m_pLoggerStoreSCU->Init("store.log");
    //m_pLoggerStoreSCU->ClearLog();
    //*m_pLoggerStoreSCU = OFLog::getLogger(strLog);

    m_nMaxReceivePDULength = ASC_MAXIMUMPDUSIZE;
    m_NetworkTransferSyntax = EXS_JPEGProcess14SV1;//EXS_Unknown;

	m_bIdentResponse = false;

	m_bHaltOnUnsuccessfulStore = OFTrue;
	m_bUnsuccessfulStoreEncountered = OFFalse;

	m_ReadMode = ERM_autoDetect;

	m_bInventSOPInstanceInformation = OFFalse;

	m_bCorrectUIDPadding = OFTrue;

	m_DIMSEBlockMode = DIMSE_BLOCKING;

	m_nLastStatusCode = STATUS_Success;

	m_bAbortAssociation = false;

	m_nTimeoutACSE = 0;
	m_nTimeoutDIMSE = 0;

	m_pNetwork = NULL;
	m_pNetworkParams = NULL;
	m_pAssoc = NULL;

	m_bCombineProposedTransferSyntaxes = true;
	m_bProposeOnlyRequiredPresentationContexts = false;

	m_IdentMode = ASC_USER_IDENTITY_NONE;

	m_nRepeatCount = 2;

	m_pCurrentFileNameList = NULL;


//	m_pNetClass = new CSDCMNetBase();

	

	//register global JPEG decompression codecs
	DJDecoderRegistration::registerCodecs();

	// register global JPEG compression codecs
	DJEncoderRegistration::registerCodecs();

	// register JPEG-LS decompression codecs
    DJLSDecoderRegistration::registerCodecs();

	// register JPEG-LS compression codecs
    DJLSEncoderRegistration::registerCodecs();

	// register RLE compression codec
    DcmRLEEncoderRegistration::registerCodecs();

	// register RLE decompression codec
	DcmRLEDecoderRegistration::registerCodecs();
	
}

CSDCMSendImpl::~CSDCMSendImpl()
{

}

void CSDCMSendImpl::Stop()
{
	//cleanup global JPEG decompression codecs
	DJDecoderRegistration::cleanup();

	// cleanup global JPEG compression codecs
	DJEncoderRegistration::cleanup();

	// cleanup JPEG-LS decompression codecs
    DJLSDecoderRegistration::cleanup();

	// cleanup JPEG-LS compression codecs
    DJLSEncoderRegistration::cleanup();

	// cleanup RLE compression codec
    DcmRLEEncoderRegistration::cleanup();

	// cleanup RLE decompression codec
	DcmRLEDecoderRegistration::cleanup();
}


int CSDCMSendImpl::InitNetwork(OFString strServerAETitle, OFString strClientAETitle, OFString strHostIP, int nPort, int nConnectType, int nBlock, int nTimeoutDIMSE, int nTimeoutACSE, E_TransferSyntax networkTransferSyntax)
{	
	SetServerInfo(strServerAETitle, strClientAETitle, strHostIP, nPort, nConnectType, nBlock);


	return 0;
}


OFCondition CSDCMSendImpl::AddStoragePresentationContexts(T_ASC_Parameters *params, OFList<OFString> &sopClasses)
{
	/*
	* Each SOP Class will be proposed in two presentation contexts (unless
	* the m_bCombineProposedTransferSyntaxes global variable is true).
	* The command line specified a preferred transfer syntax to use.
	* This prefered transfer syntax will be proposed in one
	* presentation context and a set of alternative (fallback) transfer
	* syntaxes will be proposed in a different presentation context.
	*
	* Generally, we prefer to use Explicitly encoded transfer syntaxes
	* and if running on a Little Endian machine we prefer
	* LittleEndianExplicitTransferSyntax to BigEndianTransferSyntax.
	* Some SCP implementations will just select the first transfer
	* syntax they support (this is not part of the standard) so
	* organise the proposed transfer syntaxes to take advantage
	* of such behaviour.
	*/

	// Which transfer syntax was preferred on the command line
	OFString preferredTransferSyntax;
	if (m_NetworkTransferSyntax == EXS_Unknown) {
		/* gLocalByteOrder is defined in dcxfer.h */
		if (gLocalByteOrder == EBO_LittleEndian) {
			/* we are on a little endian machine */
			//preferredTransferSyntax = UID_LittleEndianExplicitTransferSyntax;
			//preferredTransferSyntax = UID_JPEGProcess1TransferSyntax;
			preferredTransferSyntax =  UID_LittleEndianExplicitTransferSyntax;
		}
		else {
			/* we are on a big endian machine */
			preferredTransferSyntax = UID_BigEndianExplicitTransferSyntax;
		}
	}
	else {
		DcmXfer xfer(m_NetworkTransferSyntax);
		preferredTransferSyntax = xfer.getXferID();
		//preferredTransferSyntax = UID_LittleEndianExplicitTransferSyntax;
	}

	OFListIterator(OFString) s_cur;
	OFListIterator(OFString) s_end;

	OFList<OFString> fallbackSyntaxes;
	// - If little endian implicit is preferred, we don't need any fallback syntaxes
	//   because it is the default transfer syntax and all applications must support it.
	// - If MPEG2 or MPEG4 is preferred, we don't want to propose any fallback solution
	//   because this is not required and we cannot decompress the movie anyway.
	if ((m_NetworkTransferSyntax != EXS_LittleEndianImplicit) &&
		(m_NetworkTransferSyntax != EXS_MPEG2MainProfileAtMainLevel) &&
		(m_NetworkTransferSyntax != EXS_MPEG2MainProfileAtHighLevel) &&
		(m_NetworkTransferSyntax != EXS_MPEG4HighProfileLevel4_1) &&
		(m_NetworkTransferSyntax != EXS_MPEG4BDcompatibleHighProfileLevel4_1))
	{
//		fallbackSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax);
//		fallbackSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax);
//		fallbackSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax);		
		// Remove the preferred syntax from the fallback list
		fallbackSyntaxes.remove(preferredTransferSyntax);
	}

	// create a list of transfer syntaxes combined from the preferred and fallback syntaxes
	OFList<OFString> combinedSyntaxes;
	s_cur = fallbackSyntaxes.begin();
	s_end = fallbackSyntaxes.end();
	combinedSyntaxes.push_back(preferredTransferSyntax);
	//sopClasses.push_back(preferredTransferSyntax);

	OFString strCur;
	while (s_cur != s_end)
	{
		strCur = *s_cur;
		if (!IsaListMember(combinedSyntaxes, *s_cur))
		{
//			combinedSyntaxes.push_back(*s_cur);
//			sopClasses.push_back(*s_cur);
		}

		++s_cur;
	}

	int nNumber = numberOfDcmShortSCUStorageSOPClassUIDs;
	m_bProposeOnlyRequiredPresentationContexts = true;
	if (!m_bProposeOnlyRequiredPresentationContexts) {
		// add the (short list of) known storage SOP classes to the list
		// the array of Storage SOP Class UIDs comes from dcuid.h
		for (int i = 0; i < numberOfDcmShortSCUStorageSOPClassUIDs; i++)
		{
			OFString strTest = dcmShortSCUStorageSOPClassUIDs[i];
			sopClasses.push_back(dcmShortSCUStorageSOPClassUIDs[i]);
		}
	}

	// thin out the SOP classes to remove any duplicates
	OFList<OFString> sops;
	s_cur = sopClasses.begin();
	s_end = sopClasses.end();
	while (s_cur != s_end) {
		strCur = *s_cur;
		if (!IsaListMember(sops, *s_cur)) {
			sops.push_back(*s_cur);
		}
		++s_cur;
	}

	// add a presentations context for each SOP class / transfer syntax pair
	OFCondition cond = EC_Normal;
	int pid = 1; // presentation context id
	s_cur = sops.begin();
	s_end = sops.end();
	while (s_cur != s_end && cond.good()) {

		strCur = *s_cur;

		if (pid > 255) 
		{
            OFLOG_ERROR(*m_pLoggerStoreSCU, "Too many presentation contexts");
			return ASC_BADPRESENTATIONCONTEXTID;
		}

		if (m_bCombineProposedTransferSyntaxes) 
		{
			cond = AddPresentationContext(params, pid, *s_cur, combinedSyntaxes);
			pid += 2;   /* only odd presentation context id's */
		}
		else 
		{

			// SOP class with preferred transfer syntax
			cond = AddPresentationContext(params, pid, *s_cur, preferredTransferSyntax);
			pid += 2;   /* only odd presentation context id's */

			if (fallbackSyntaxes.size() > 0) 
			{
				if (pid > 255) 
				{
                    OFLOG_ERROR(*m_pLoggerStoreSCU, "Too many presentation contexts");
					return ASC_BADPRESENTATIONCONTEXTID;
				}

				// SOP class with fallback transfer syntax
				cond = AddPresentationContext(params, pid, *s_cur, fallbackSyntaxes);
				pid += 2; /* only odd presentation context id's */
			}
		}
		++s_cur;
	}

	return cond;
}

OFBool CSDCMSendImpl::IsaListMember(OFList<OFString> &lst, OFString &s)
{
	OFListIterator(OFString) cur = lst.begin();
	OFListIterator(OFString) end = lst.end();

	OFBool found = OFFalse;
	while (cur != end && !found) {
		found = (s == *cur);
		++cur;
	}

	return found;
}


OFCondition CSDCMSendImpl::AddPresentationContext(T_ASC_Parameters *params, int presentationContextId, const OFString &abstractSyntax, const OFString &transferSyntax, T_ASC_SC_ROLE proposedRole)
{
	const char *c_p = transferSyntax.c_str();
	OFCondition cond = ASC_addPresentationContext(params, presentationContextId,
		abstractSyntax.c_str(), &c_p, 1, proposedRole);
	return cond;
}

OFCondition CSDCMSendImpl::AddPresentationContext(T_ASC_Parameters *params, int presentationContextId, const OFString &abstractSyntax, const OFList<OFString> &transferSyntaxList, T_ASC_SC_ROLE proposedRole)
{
	// create an array of supported/possible transfer syntaxes
	const char **transferSyntaxes = new const char*[transferSyntaxList.size()];
	int transferSyntaxCount = 0;
	OFListConstIterator(OFString) s_cur = transferSyntaxList.begin();
	OFListConstIterator(OFString) s_end = transferSyntaxList.end();
	while (s_cur != s_end) {
		transferSyntaxes[transferSyntaxCount++] = (*s_cur).c_str();
		++s_cur;
	}

	OFCondition cond = ASC_addPresentationContext(params, presentationContextId,
		abstractSyntax.c_str(), transferSyntaxes, transferSyntaxCount, proposedRole);

	delete[] transferSyntaxes;
	return cond;
}

OFCondition CSDCMSendImpl::CheckUserIdentityResponse(T_ASC_Parameters *params)
{
	if (params == NULL)
		return ASC_NULLKEY;

	/* So far it is only checked whether a requested, positive response was
	actually received */

	// In case we sent no user identity request, there are no checks at all
	if ((m_IdentMode == ASC_USER_IDENTITY_NONE) || (!m_bIdentResponse))
		return EC_Normal;

	// If positive response was requested, we expect a corresponding response
	if ((m_IdentMode == ASC_USER_IDENTITY_USER) || (m_IdentMode == ASC_USER_IDENTITY_USER_PASSWORD))
	{
		UserIdentityNegotiationSubItemAC *rsp = params->DULparams.ackUserIdentNeg;
		if (rsp == NULL)
		{
            OFLOG_ERROR(*m_pLoggerStoreSCU, "User Identity Negotiation failed: Positive response requested but none received");
			return ASC_USERIDENTIFICATIONFAILED;
		}
	}
	return EC_Normal;
}


OFCondition CSDCMSendImpl::cstore(T_ASC_Association *assoc, const OFString &fname)
/*
* This function will process the given file as often as is specified by opt_repeatCount.
* "Process" in this case means "read file, send C-STORE-RQ, receive C-STORE-RSP".
*
* Parameters:
*   assoc - [in] The association (network connection to another DICOM application).
*   fname - [in] Name of the file which shall be processed.
*/
{
	OFCondition cond = EC_Normal;

	/* opt_repeatCount specifies how many times a certain file shall be processed */
	int n = OFstatic_cast(int, m_nRepeatCount);

	/* as long as no error occured and the counter does not equal 0 */
	while ((cond.good()) && n-- && !(m_bHaltOnUnsuccessfulStore && m_bUnsuccessfulStoreEncountered))
	{
		/* process file (read file, send C-STORE-RQ, receive C-STORE-RSP) */
		cond = storeSCU(assoc, fname.c_str());

		if(cond.good())
		{
			break;
		}
	}

	// we don't want to return an error code if --no-halt was specified.
	if (!m_bHaltOnUnsuccessfulStore)
	{
		cond = EC_Normal;
	}

	/* return result value */
	return cond;
}

OFCondition CSDCMSendImpl::storeSCU(T_ASC_Association *assoc, const char *fname)
/*
* This function will read all the information from the given file,
* figure out a corresponding presentation context which will be used
* to transmit the information over the network to the SCP, and it
* will finally initiate the transmission of all data to the SCP.
*
* Parameters:
*   assoc - [in] The association (network connection to another DICOM application).
*   fname - [in] Name of the file which shall be processed.
*/
{
	DIC_US msgId = assoc->nextMsgID++;
	T_ASC_PresentationContextID presID;
	T_DIMSE_C_StoreRQ req;
	T_DIMSE_C_StoreRSP rsp;
	DIC_UI sopClass;
	DIC_UI sopInstance;
	DcmDataset *statusDetail = NULL;

	m_bUnsuccessfulStoreEncountered = OFTrue; // assumption

    OFLOG_INFO(*m_pLoggerStoreSCU, "Sending file: " << fname);

	/* read information from file. After the call to DcmFileFormat::loadFile(...) the information */
	/* which is encapsulated in the file will be available through the DcmFileFormat object. */
	/* In detail, it will be available through calls to DcmFileFormat::getMetaInfo() (for */
	/* meta header information) and DcmFileFormat::getDataset() (for data set information). */
	DcmFileFormat dcmff;
	OFCondition cond = dcmff.loadFile(fname, EXS_Unknown, EGL_noChange, DCM_MaxReadLength, m_ReadMode);

	/* figure out if an error occured while the file was read*/
	if (cond.bad()) 
	{
        //OFLOG_ERROR(*m_pLoggerStoreSCU, "Bad DICOM file: " << fname << ": " << cond.text());
		return cond;
	}

	/* if required, invent new SOP instance information for the current data set (user option) */
	if (m_bInventSOPInstanceInformation) 
	{
		ReplaceSOPInstanceInformation(dcmff.getDataset());
	}

	/* figure out which SOP class and SOP instance is encapsulated in the file */
    //if (!DU_findSOPClassAndInstanceInDataSet(dcmff.getDataset(), sopClass, sopInstance, m_bCorrectUIDPadding))
    if (!DU_findSOPClassAndInstanceInDataSet(dcmff.getDataset(), sopClass, sizeof(sopClass), sopInstance, sizeof(sopInstance), m_bCorrectUIDPadding))
	{
        OFLOG_ERROR(*m_pLoggerStoreSCU, "No SOP Class or Instance UID in file: " << fname);
		return DIMSE_BADDATA;
	}

	/* figure out which of the accepted presentation contexts should be used */
	DcmXfer filexfer(dcmff.getDataset()->getOriginalXfer());

	/* special case: if the file uses an unencapsulated transfer syntax (uncompressed
	* or deflated explicit VR) and we prefer deflated explicit VR, then try
	* to find a presentation context for deflated explicit VR first.
	*/
	if (filexfer.isNotEncapsulated() &&
		m_NetworkTransferSyntax == EXS_DeflatedLittleEndianExplicit)
	{
		filexfer = EXS_DeflatedLittleEndianExplicit;
	}


	if (filexfer.getXfer() != EXS_Unknown)
		presID = ASC_findAcceptedPresentationContextID(assoc, sopClass, filexfer.getXferID());
	else
		presID = ASC_findAcceptedPresentationContextID(assoc, sopClass);

//	presID = ASC_findAcceptedPresentationContextID(assoc, sopClass);
	if (presID == 0) 
	{
		const char *modalityName = dcmSOPClassUIDToModality(sopClass);
		if (!modalityName) modalityName = dcmFindNameOfUID(sopClass);
		if (!modalityName) modalityName = "unknown SOP class";
        OFLOG_ERROR(*m_pLoggerStoreSCU, "No presentation context for: (" << modalityName << ") " << sopClass);
		return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
	}
	

	T_ASC_PresentationContext pc;
	ASC_findAcceptedPresentationContext(assoc->params, presID, &pc);
	DcmXfer netTransfer(pc.acceptedTransferSyntax);

	/* if required, dump general information concerning transfer syntaxes */
	
    if (m_pLoggerStoreSCU->isEnabledFor(OFLogger::INFO_LOG_LEVEL)) {

        //register global JPEG decompression codecs
        DJDecoderRegistration::registerCodecs();

        // register global JPEG compression codecs
        DJEncoderRegistration::registerCodecs();

 		DcmXfer fileTransfer(dcmff.getDataset()->getOriginalXfer());
        OFLOG_INFO(*m_pLoggerStoreSCU, "Converting transfer syntax: " << fileTransfer.getXferName()
 			<< " -> " << netTransfer.getXferName());
 	}
	

	dcmff.getDataset()->chooseRepresentation(netTransfer.getXfer(), NULL);
#ifdef ON_THE_FLY_COMPRESSION
	
#endif

	/* prepare the transmission of data */
	bzero(OFreinterpret_cast(char *, &req), sizeof(req));
	req.MessageID = msgId;
	strcpy(req.AffectedSOPClassUID, sopClass);
	strcpy(req.AffectedSOPInstanceUID, sopInstance);
	req.DataSetType = DIMSE_DATASET_PRESENT;
	req.Priority = DIMSE_PRIORITY_LOW;

	/* if required, dump some more general information */
    OFLOG_INFO(*m_pLoggerStoreSCU, "Sending Store Request (MsgID " << msgId << ", " << dcmSOPClassUIDToModality(sopClass, "OT") << ")");



	DIMSE_PrivateUserContext dpuc;
    T_DIMSE_StoreProgress store_progress;
	//dpuc.pCallbackThread = m_pCallbackThread;
	dpuc.pCallback = m_pCallback;
    dpuc.pThis = this;
    dpuc.assoc = assoc;
    dpuc.bSendComplete = false;
    dpuc.progress = &store_progress;

    m_DIMSEBlockMode = DIMSE_NONBLOCKING;

    m_nTimeoutDIMSE = 5;

    T_DIMSE_DetectedCancelParameters dcp;

	/* finally conduct transmission of data */
	cond = DIMSE_storeUser(assoc, presID, &req,
		fname, dcmff.getDataset(), ProgressCallback, &dpuc,
		m_DIMSEBlockMode, m_nTimeoutDIMSE,
        &rsp, &statusDetail, &dcp, OFStandard::getFileSize(fname));

    QElapsedTimer timeElapsed;
    timeElapsed.start();

    bool bError = false;

    while(dpuc.bSendComplete==false && bError==false && store_progress.state!=DIMSE_StoreEnd)
    {
        QThread::usleep(100*1000);

        if(timeElapsed.elapsed()>m_nTimeoutDIMSE*1000)
        {
            bError = true;
        }

        timeElapsed.restart();
    }

    if(bError==true)
    {

    }

    if(cond.bad()==OFTrue)
    {
        return cond;
    }
	/*
	cond = DIMSE_storeUser(assoc, presID, &req,
		fname, dcmff.getDataset(), ProgressCallback, NULL,
		m_DIMSEBlockMode, m_nTimeoutDIMSE,
		&rsp, &statusDetail, NULL, OFStandard::getFileSize(fname));
		*/
	
	/*
	* If store command completed normally, with a status
	* of success or some warning then the image was accepted.
	*/
	if (cond == EC_Normal && (rsp.DimseStatus == STATUS_Success || DICOM_WARNING_STATUS(rsp.DimseStatus))) 
	{
		m_bUnsuccessfulStoreEncountered = OFFalse;
	}

	

	/* remember the response's status for later transmissions of data */
	m_nLastStatusCode = rsp.DimseStatus;

	/* dump some more general information */
 	if (cond == EC_Normal)
 	{
 		OFString temp_str;
        if (m_pLoggerStoreSCU->isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
 		{
            OFLOG_INFO(*m_pLoggerStoreSCU, "Received Store Response");
            //OFLOG_DEBUG(*m_pLoggerStoreSCU, DIMSE_dumpMessage(temp_str, rsp, DIMSE_INCOMING, NULL, presID));
 		}
 		else {
            OFLOG_INFO(*m_pLoggerStoreSCU, "Received Store Response (" << DU_cstoreStatusString(rsp.DimseStatus) << ")");
 		}

        if (m_pLoggerStoreSCU->isEnabledFor(OFLogger::TRACE_LOG_LEVEL))
		{
            OFLOG_ERROR(*m_pLoggerStoreSCU, "Dump dcm file: " << fname << ":" << OFendl << DimseCondition::dump(temp_str, cond));
		}
	
 	}
 	else
 	{
 		OFString temp_str;
        OFLOG_ERROR(*m_pLoggerStoreSCU, "Store Failed, file: " << fname << ":" << OFendl << DimseCondition::dump(temp_str, cond));
 	}

	/* dump status detail information if there is some */
	if (statusDetail != NULL) {
        OFLOG_DEBUG(*m_pLoggerStoreSCU, "Status Detail:" << OFendl << DcmObject::PrintHelper(*statusDetail));
		delete statusDetail;
	}
	/* return */
	return cond;
}




void CSDCMSendImpl::ReplaceSOPInstanceInformation(DcmDataset *dataset)
{
// 	static OFCmdUnsignedInt patientCounter = 0;
// 	static OFCmdUnsignedInt studyCounter = 0;
// 	static OFCmdUnsignedInt seriesCounter = 0;
 	static OFCmdUnsignedInt imageCounter = 0;
// 	static OFString seriesInstanceUID;
// 	static OFString seriesNumber;
// 	static OFString studyInstanceUID;
// 	static OFString studyID;
// 	static OFString accessionNumber;
// 	static OFString patientID;
// 	static OFString patientName;
// 
// 	if (seriesInstanceUID.empty()) seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, OFstatic_cast(int, seriesCounter));
// 	if (seriesNumber.empty()) seriesNumber = intToString(OFstatic_cast(int, seriesCounter));
// 	if (studyInstanceUID.empty()) studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, OFstatic_cast(int, studyCounter));
// 	if (studyID.empty()) studyID = studyIDPrefix + intToString(OFstatic_cast(int, secondsSince1970())) + intToString(OFstatic_cast(int, studyCounter));
// 	if (accessionNumber.empty()) accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, studyCounter));
// 	if (patientID.empty()) patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, patientCounter));
// 	if (patientName.empty()) patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, patientCounter));
// 
// 	if (imageCounter >= opt_inventSeriesCount) {
// 		imageCounter = 0;
// 		seriesCounter++;
// 		seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, OFstatic_cast(int, seriesCounter));
// 		seriesNumber = intToString(OFstatic_cast(int, seriesCounter));
// 	}
// 	if (seriesCounter >= opt_inventStudyCount) {
// 		seriesCounter = 0;
// 		studyCounter++;
// 		studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, OFstatic_cast(int, studyCounter));
// 		studyID = studyIDPrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, studyCounter));
// 		accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, studyCounter));
// 	}
// 	if (studyCounter >= opt_inventPatientCount) {
// 		// we create as many patients as necessary */
// 		studyCounter = 0;
// 		patientCounter++;
// 		patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, patientCounter));
// 		patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, patientCounter));
// 	}
// 
// 	OFString sopInstanceUID = makeUID(SITE_INSTANCE_UID_ROOT, OFstatic_cast(int, imageCounter));
// 	OFString imageNumber = intToString(OFstatic_cast(int, imageCounter));
// 
// 	OFLOG_INFO(*m_pLoggerStoreSCU, "Inventing Identifying Information ("
// 		<< "pa" << patientCounter << ", st" << studyCounter
// 		<< ", se" << seriesCounter << ", im" << imageCounter << "):");
// 	OFLOG_INFO(*m_pLoggerStoreSCU, "  PatientName=" << patientName);
// 	OFLOG_INFO(*m_pLoggerStoreSCU, "  PatientID=" << patientID);
// 	OFLOG_INFO(*m_pLoggerStoreSCU, "  StudyInstanceUID=" << studyInstanceUID);
// 	OFLOG_INFO(*m_pLoggerStoreSCU, "  StudyID=" << studyID);
// 	OFLOG_INFO(*m_pLoggerStoreSCU, "  SeriesInstanceUID=" << seriesInstanceUID);
// 	OFLOG_INFO(*m_pLoggerStoreSCU, "  SeriesNumber=" << seriesNumber);
// 	OFLOG_INFO(*m_pLoggerStoreSCU, "  SOPInstanceUID=" << sopInstanceUID);
// 	OFLOG_INFO(*m_pLoggerStoreSCU, "  ImageNumber=" << imageNumber);
// 
// 	updateStringAttributeValue(dataset, DCM_PatientName, patientName);
// 	updateStringAttributeValue(dataset, DCM_PatientID, patientID);
// 	updateStringAttributeValue(dataset, DCM_StudyInstanceUID, studyInstanceUID);
// 	updateStringAttributeValue(dataset, DCM_StudyID, studyID);
// 	updateStringAttributeValue(dataset, DCM_SeriesInstanceUID, seriesInstanceUID);
// 	updateStringAttributeValue(dataset, DCM_SeriesNumber, seriesNumber);
// 	updateStringAttributeValue(dataset, DCM_SOPInstanceUID, sopInstanceUID);
// 	updateStringAttributeValue(dataset, DCM_InstanceNumber, imageNumber);

	imageCounter++;
}


void CSDCMSendImpl::ProgressCallback(void * callbackData, T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ * req)
{
	//TRACE("Send Bytes: %d\r\n", progress->progressBytes);
	DIMSE_PrivateUserContext* pPrivate = (DIMSE_PrivateUserContext*)callbackData;
    //T_ASC_Association *assoc = pPrivate->assoc;
	if (pPrivate->pCallback != NULL)
	{
		CALLBACK_STATE(pPrivate->pCallback, progress->progressBytes, progress->totalBytes);
	}

    CSDCMSendImpl* pThis = pPrivate->pThis;
    OFLogger* pLog = pThis->GetLogger();

	if (progress->state == DIMSE_StoreBegin)
	{
		OFString str;
        OFLOG_DEBUG(*pLog, DIMSE_dumpMessage(str, *req, DIMSE_OUTGOING));
	}

	// We can't use oflog for the pdu output, but we use a special logger for
	// generating this output. If it is set to level "INFO" we generate the
	// output, if it's set to "DEBUG" then we'll assume that there is debug output
	// generated for each PDU elsewhere.
	//OFLogger progressLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION ".progress");
	//if (progressLogger.getChainedLogLevel() == OFLogger::INFO_LOG_LEVEL) {
	switch (progress->state) {
	case DIMSE_StoreBegin:
		break;
	case DIMSE_StoreEnd:
        pPrivate->bSendComplete = true;

		if (pPrivate->pCallback != NULL)
		{
			CALLBACK_STATE(pPrivate->pCallback, progress->progressBytes, progress->totalBytes);

			//CALLBACK_COMPLETE(pPrivate->pCallback);
		}
		break;
	default:
        {

        }
		break;
	}
	//COUT.flush();
	//}
}

/*
void CSDCMSendImpl::ProgressCallback(void * callbackData, T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ * req)
{
	//TRACE("Send Bytes: %d\r\n", progress->progressBytes);
	DIMSE_PrivateUserContext* pPrivate = (DIMSE_PrivateUserContext*)callbackData;
	if(pPrivate->pCallbackThread!=NULL)
	{
		pPrivate->pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_PROGRESS, (WPARAM)progress->progressBytes, (LPARAM)progress->totalBytes);
	}
	
	if (progress->state == DIMSE_StoreBegin)
	{
		OFString str;
        //OFLOG_DEBUG(*m_pLoggerStoreSCU, DIMSE_dumpMessage(str, *req, DIMSE_OUTGOING));
	}

	// We can't use oflog for the pdu output, but we use a special logger for
	// generating this output. If it is set to level "INFO" we generate the
	// output, if it's set to "DEBUG" then we'll assume that there is debug output
	// generated for each PDU elsewhere.
	//OFLogger progressLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION ".progress");
	//if (progressLogger.getChainedLogLevel() == OFLogger::INFO_LOG_LEVEL) {
		switch (progress->state) {
		case DIMSE_StoreBegin:
			break;
		case DIMSE_StoreEnd:
			if(pPrivate->pCallbackThread!=NULL)
			{
				pPrivate->pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_PROGRESS, (WPARAM)progress->totalBytes, (LPARAM)progress->totalBytes);
			}
			break;
		default:
			break;
		}
		//COUT.flush();
	//}
}
*/


OFBool CSDCMSendImpl::FindSOPClassAndInstanceInFile(const char *fname, char *sopClass, char *sopInstance)
{
    DcmFileFormat dcmff;

    DcmDataset* pDcmDataset = NULL;

    OFCondition cond = dcmff.loadFile(fname, EXS_Unknown, EGL_noChange, DCM_MaxReadLength, m_ReadMode);

    if (cond.bad()==OFTrue)
        return OFFalse;

    pDcmDataset = dcmff.getDataset();
    pDcmDataset->loadAllDataIntoMemory();

	DIC_UI uisopClass;
	DIC_UI uisopInstance;

	/* look in the meta-header first */
    //OFBool found = DU_findSOPClassAndInstanceInDataSet((DcmItem *)ff.getMetaInfo(), sopClass, sopInstance, m_bCorrectUIDPadding);
    OFBool found = DU_findSOPClassAndInstanceInDataSet(pDcmDataset, uisopClass, sizeof(uisopClass), uisopInstance, sizeof(uisopInstance), m_bCorrectUIDPadding);

    int nLength = 0;
    nLength = strlen(uisopClass);
    memcpy(sopClass, uisopClass, nLength);

    nLength = strlen(uisopInstance);
    memcpy(sopInstance, uisopInstance, nLength);

	if (!found)
	{
        //found = DU_findSOPClassAndInstanceInDataSet(ff.getDataset(), sopClass, sopInstance, m_bCorrectUIDPadding);
        found = DU_findSOPClassAndInstanceInDataSet(pDcmDataset, uisopClass, sizeof(uisopClass), uisopInstance, sizeof(uisopInstance), m_bCorrectUIDPadding);

        OFString strSOPClassUID;
        pDcmDataset->findAndGetOFString(DCM_SOPClassUID, strSOPClassUID);


	}

    dcmff.clear();

    pDcmDataset->clear();

	return found;
}

void CSDCMSendImpl::SetAETitle(OFString strAETitle)
{
	m_strAETitle = strAETitle;
}

void CSDCMSendImpl::SetServerInfo(OFString strServerAETitle, OFString strClientAETitle, OFString strIP, int nPort, int nConnectionType, int nBlockingMethod)
{
	m_strAETitle = strClientAETitle;
	m_strServerAETitle = strServerAETitle;
	m_strHostIP = strIP;
	m_nPort = nPort;

	m_ConnectType = (SNETWORK_CONNECTION)nConnectionType;
	m_BlockMode = (SNETWORK_BLOCK_MODE)nBlockingMethod;
}

void CSDCMSendImpl::SetServerInfo(QString strServerAETitle, QString strClientAETitle, QString strIP, int nPort, int nConnectionType, int nBlockingMethod)
{
    m_strAETitle = strClientAETitle.toStdString().c_str();
    m_strServerAETitle = strServerAETitle.toStdString().c_str();
    m_strHostIP = strIP.toStdString().c_str();
    m_nPort = nPort;

    m_ConnectType = (SNETWORK_CONNECTION)nConnectionType;
    m_BlockMode = (SNETWORK_BLOCK_MODE)nBlockingMethod;
}

void CSDCMSendImpl::AddImageFilename(OFString strFilename)
{
	m_ImageFileNameList.push_back(strFilename);
}

void CSDCMSendImpl::AddMpegFilename(OFString strFilename)
{
	m_MpegFileNameList.push_back(strFilename);
}

void CSDCMSendImpl::ClearFileList()
{
	ClearImageFileList();
	ClearMpegFileList();
}

void CSDCMSendImpl::ClearImageFileList()
{
	m_ImageFileNameList.clear();
}

void CSDCMSendImpl::ClearMpegFileList()
{
	m_MpegFileNameList.clear();
}

void CSDCMSendImpl::SetCurrentFilenameList(int nCurrent)
{
	if(nCurrent==0)
	{
		m_pCurrentFileNameList = NULL;
	}
	else if(nCurrent==1)
	{
		m_pCurrentFileNameList = &m_ImageFileNameList;
	}
	else if(nCurrent==2)
	{
		m_pCurrentFileNameList = &m_MpegFileNameList;
	}
}

int CSDCMSendImpl::GetImageFileCount()
{
	return m_ImageFileNameList.size();
}

int CSDCMSendImpl::GetMpegFileCount()
{
	return m_MpegFileNameList.size();
}

vector<QString> CSDCMSendImpl::Send(CSCallback* pCallback, int nTimeoutDIMSE, int nTimeoutACSE, E_TransferSyntax networkTransferSyntax)
{
	m_pCallback = pCallback;
    if(nTimeoutDIMSE>0)
    {
        m_nTimeoutDIMSE = nTimeoutDIMSE;
    }

    if(nTimeoutACSE>0)
    {
        m_nTimeoutACSE = nTimeoutACSE;

    }

    dcmConnectionTimeout.set(m_nTimeoutACSE);


	m_NetworkTransferSyntax = networkTransferSyntax;

	
    //PostThreadMessage(WM_DCM_SEND, NULL, NULL);
    return OnDCMSend();
}

/*
int CSDCMSendImpl::Send(CSThread* pCallbackThread, int nTimeoutDIMSE, int nTimeoutACSE, E_TransferSyntax networkTransferSyntax)
{
	m_pCallbackThread = pCallbackThread;
	m_nTimeoutDIMSE = nTimeoutDIMSE;
	m_nTimeoutACSE = nTimeoutACSE;
	m_NetworkTransferSyntax = networkTransferSyntax;

	PostThreadMessage(WM_DCM_SEND, NULL, NULL);
	

	return 0;
}
*/

vector<QString> CSDCMSendImpl::OnDCMSend()
{
    vector<QString> listSendCompleteFile;
    //SetSleep(10);
	const char* pServerAETitle = NULL;
	const char* pClientAETitle = NULL;
	OFString strServerIPnPort;

//	char* pPeer = NULL;

	OFBool bSecureConnection = false;

	OFList<OFString> sopClassUIDList;    // the list of SOP classes
	OFList<OFString> sopInstanceUIDList; // the list of SOP instances


	OFCondition cond;

	int nLength = 0;

	char sopClassUID[128];
	char sopInstanceUID[128];

	OFString temp_str;

	//fileNameList.push_back("test.dcm");

    if(m_pCurrentFileNameList->size()==0)
    {
        return listSendCompleteFile;
    }

	OFListIterator(OFString) iterFirst = m_pCurrentFileNameList->begin();


	//FindSOPClassAndInstanceInFile("mpeg_test.dcm", sopClassUID, sopInstanceUID);
	memset(sopClassUID, 0, 128);
	memset(sopInstanceUID, 0, 128);

    bool bFindInstanceUID = false;

    while(bFindInstanceUID==false && iterFirst!=m_pCurrentFileNameList->end())
    {
        OFString strFirstDcmFile = *iterFirst;
        FindSOPClassAndInstanceInFile(strFirstDcmFile.c_str(), sopClassUID, sopInstanceUID);
        iterFirst++;
    }



	pServerAETitle = m_strServerAETitle.c_str();
	pClientAETitle = m_strAETitle.c_str();

    //m_nTimeoutACSE = 10;

    //DCM_dcmnetLogger = *m_pLoggerStoreSCU;

    OFLogger log = OFLog::getLogger("store.log");
    m_pLoggerStoreSCU = &log;
    m_pLoggerStoreSCU->setLogLevel(dcmtk::log4cplus::FATAL_LOG_LEVEL);

    dcmConnectionTimeout.set(m_nTimeoutACSE);

    OFLOG_INFO(*m_pLoggerStoreSCU, "------------------------ DICOM Store Start --------------------------------------------");

	CALLBACK_INFO(m_pCallback, INITIALIZE_NETWORK);
	cond = ASC_initializeNetwork(NET_REQUESTOR, 0, m_nTimeoutACSE, &m_pNetwork);
	if (cond.bad())
	{
		CALLBACK_ERROR(m_pCallback, INITIALIZE_NETWORK);
        return listSendCompleteFile;
	}

	CALLBACK_INFO(m_pCallback, CREATE_ASSOCIATION_PARAMETERS);
	/* initialize asscociation parameters, i.e. create an instance of T_ASC_Parameters*. */
	cond = ASC_createAssociationParameters(&m_pNetworkParams, m_nMaxReceivePDULength);
	if (cond.bad())
	{
		CALLBACK_ERROR(m_pCallback, CREATE_ASSOCIATION_PARAMETERS);
        return listSendCompleteFile;
    }

	CALLBACK_INFO(m_pCallback, SET_APTITLES);
	/* sets this application's title and the called application's title in the params */
	/* structure. The default values to be set here are "STORESCU" and "ANY-SCP". */
	cond = ASC_setAPTitles(m_pNetworkParams, pClientAETitle, pServerAETitle, NULL);
	if (cond.bad())
	{
		CALLBACK_ERROR(m_pCallback, SET_APTITLES);
        return listSendCompleteFile;
	}

	CALLBACK_INFO(m_pCallback, SET_TRANSPORT_LAYER_TYPE);
	cond = ASC_setTransportLayerType(m_pNetworkParams, bSecureConnection);
	if (cond.bad())
	{
		CALLBACK_ERROR(m_pCallback, SET_TRANSPORT_LAYER_TYPE);
        //Sleep(10);
        return listSendCompleteFile;
	}

	/* Figure out the presentation addresses and copy the */
	/* corresponding values into the association parameters.*/
	gethostname(m_LocalHost, sizeof(m_LocalHost) - 1);
	// 	sprintf(peerHost, "%s:%d", pPeer, OFstatic_cast(int, m_nPort));	

	//sprintf(m_LocalHost, "192.168.123.23");
	char* pStrServerIPnPort = new char[1024];
	sprintf(pStrServerIPnPort, "%s:%d", m_strHostIP.c_str(), m_nPort);
	strServerIPnPort = pStrServerIPnPort;
	delete[] pStrServerIPnPort;



	nLength = strServerIPnPort.length();
	const char* pData = NULL;
	pData = strServerIPnPort.c_str();
	memset(m_PeerHost, 0, sizeof(m_PeerHost));
	memcpy(m_PeerHost, pData, nLength);

	CALLBACK_INFO(m_pCallback, SET_PRESENTATION_ADDRESSES);
	cond = ASC_setPresentationAddresses(m_pNetworkParams, m_LocalHost, m_PeerHost);
	if (cond.bad())
	{
		CALLBACK_ERROR(m_pCallback, SET_TRANSPORT_LAYER_TYPE);
        //Sleep(10);
        return listSendCompleteFile;
	}

	sopClassUIDList.push_back(sopClassUID);
	sopInstanceUIDList.push_back(sopInstanceUID);

	CALLBACK_INFO(m_pCallback, ADD_STORAGE_PRESENTATION_CONTEXTS);
    cond = AddStoragePresentationContexts(m_pNetworkParams, sopClassUIDList);
	if (cond.bad())
	{
		CALLBACK_ERROR(m_pCallback, ADD_STORAGE_PRESENTATION_CONTEXTS);
        return listSendCompleteFile;
	}


//#include "dcmtk\dcmnet\dul.h"
//	m_pNetworkParams->DULparams.requestedPresentationContext;

	CALLBACK_INFO(m_pCallback, REQUEST_ASSOCIATION);
	cond = ASC_requestAssociation(m_pNetwork, m_pNetworkParams, &m_pAssoc);
	if (cond.bad())
	{
		if (cond == DUL_ASSOCIATIONREJECTED)
		{
			CALLBACK_ERROR(m_pCallback, REJECTED_ASSOCIATION);

			T_ASC_RejectParameters rej;

			ASC_getRejectParameters(m_pNetworkParams, &rej);

            OFLOG_FATAL(*m_pLoggerStoreSCU, "Association Rejected:" << OFendl << ASC_printRejectParameters(temp_str, &rej));
		}
		else
		{
			CALLBACK_ERROR(m_pCallback, UNKNOWN_ERROR_ASSOCIATION);

            OFLOG_FATAL(*m_pLoggerStoreSCU, "Association Rejected:" << OFendl << cond.text());

			if (m_pAssoc != NULL)
			{
				cond = ASC_destroyAssociation(&m_pAssoc);
			}
			if (m_pNetwork != NULL)
			{
				cond = ASC_dropNetwork(&m_pNetwork);
			}
		}
        return listSendCompleteFile;
	}

	CALLBACK_INFO(m_pCallback, COUNT_ACCEPTED_PRESENTATION_CONTEXTS);
	if (ASC_countAcceptedPresentationContexts(m_pNetworkParams) == 0)
	{
        OFLOG_FATAL(*m_pLoggerStoreSCU, "No Acceptable Presentation Contexts");
		CALLBACK_ERROR(m_pCallback, COUNT_ACCEPTED_PRESENTATION_CONTEXTS);

		if (m_pAssoc != NULL)
		{
			cond = ASC_destroyAssociation(&m_pAssoc);
		}
		if (m_pNetwork != NULL)
		{
			cond = ASC_dropNetwork(&m_pNetwork);
		}
        return listSendCompleteFile;
	}

	CALLBACK_INFO(m_pCallback, CHECK_USER_IDENTITY_RESPONSE);
	cond = CheckUserIdentityResponse(m_pNetworkParams);
	if (cond.bad())
	{
        OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
		CALLBACK_ERROR(m_pCallback, CHECK_USER_IDENTITY_RESPONSE);

		if (m_pAssoc != NULL)
		{
			cond = ASC_destroyAssociation(&m_pAssoc);
		}
		if (m_pNetwork != NULL)
		{
			cond = ASC_dropNetwork(&m_pNetwork);
		}
        return listSendCompleteFile;
	}

	cond = EC_Normal;
	OFListIterator(OFString) iter = m_pCurrentFileNameList->begin();
	OFListIterator(OFString) enditer = m_pCurrentFileNameList->end();

	CALLBACK_INFO(m_pCallback, TRY_STORE_SCU);

    bool bExitSend = false;
    CSCallbackSendProgress* pCallbackSendProgress = (CSCallbackSendProgress*)m_pCallback;

	if (iter != enditer)
	{
        while ((iter != enditer) && cond.good() && (bExitSend=pCallbackSendProgress->IsExitSend())==false)
		{
			cond = cstore(m_pAssoc, *iter);

			if (cond.good())
			{
                OFString strTmpFile = *iter;
                QString strFilename = strTmpFile.c_str();

                listSendCompleteFile.push_back(strFilename);
				cond = EC_Normal;
				m_bUnsuccessfulStoreEncountered = false;

                usleep(100);
			}
            else
            {
                int a=0;
            }
			++iter;
		}
	}
	else
	{
		cond = cstore(m_pAssoc, *iter);
	}

    if(bExitSend==true)
    {
        int a=0;
    }


	if (cond == EC_Normal)
	{
		if (m_bAbortAssociation == true)
		{
            OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");
			CALLBACK_INFO(m_pCallback, ABORT_ASSOCIATION);
			cond = ASC_abortAssociation(m_pAssoc);
			if (cond.bad())
			{
                OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
				CALLBACK_ERROR(m_pCallback, ABORT_ASSOCIATION);
                return listSendCompleteFile;
			}
		}
		else {
			/* release association */
            OFLOG_INFO(*m_pLoggerStoreSCU, "Releasing Association");
			CALLBACK_INFO(m_pCallback, RELEASE_ASSOCIATION);
			cond = ASC_releaseAssociation(m_pAssoc);
			if (cond.bad())
			{
                OFLOG_FATAL(*m_pLoggerStoreSCU, "Association Release Failed: " << DimseCondition::dump(temp_str, cond));
				CALLBACK_ERROR(m_pCallback, RELEASE_ASSOCIATION);
                return listSendCompleteFile;
			}
		}

		CALLBACK_INFO(m_pCallback, DESTROY_ASSOCIATION);
		/* destroy the association, i.e. free memory of T_ASC_Association* structure. This */
		/* call is the counterpart of ASC_requestAssociation(...) which was called above. */
		cond = ASC_destroyAssociation(&m_pAssoc);
		if (cond.bad())
		{
            OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
			CALLBACK_ERROR(m_pCallback, DESTROY_ASSOCIATION);
            return listSendCompleteFile;
		}
		/* drop the network, i.e. free memory of T_ASC_Network* structure. This call */
		/* is the counterpart of ASC_initializeNetwork(...) which was called above. */
		CALLBACK_INFO(m_pCallback, DROP_NETWORK);
		cond = ASC_dropNetwork(&m_pNetwork);
		if (cond.bad())
		{
            OFLOG_INFO(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
			CALLBACK_INFO(m_pCallback, DROP_NETWORK);
            return listSendCompleteFile;
		}

        OFLOG_INFO(*m_pLoggerStoreSCU, "------------------------------------ End --------------------------------------------");

        //CALLBACK_COMPLETE(m_pCallback);

        //SetSleep(10);

        return listSendCompleteFile;


	}
	else if (cond == DUL_PEERREQUESTEDRELEASE)
	{
		CALLBACK_INFO(m_pCallback, PEER_REQUESTED_RELEASE);

        OFLOG_ERROR(*m_pLoggerStoreSCU, "Protocol Error: Peer requested release (Aborting)");
        OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");

		CALLBACK_INFO(m_pCallback, ABORT_ASSOCIATION);
		cond = ASC_abortAssociation(m_pAssoc);
		if (cond.bad())
		{
            OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
			CALLBACK_ERROR(m_pCallback, ABORT_ASSOCIATION);
            return listSendCompleteFile;
		}
	}
	else if (cond == DUL_PEERABORTEDASSOCIATION)
	{
		CALLBACK_ERROR(m_pCallback, PEER_ABORTED_ASSOCIATION);
        OFLOG_INFO(*m_pLoggerStoreSCU, "Peer Aborted Association");
	}
	else
	{
		CALLBACK_ERROR(m_pCallback, TRY_STORE_SCU);
        OFLOG_ERROR(*m_pLoggerStoreSCU, "Store SCU Failed: " << DimseCondition::dump(temp_str, cond));
        OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");

		CALLBACK_INFO(m_pCallback, ABORT_ASSOCIATION);
        if(cond.code()!=526)
        {
            cond = ASC_abortAssociation(m_pAssoc);
        }

		if (cond.bad())
		{
			CALLBACK_ERROR(m_pCallback, ABORT_ASSOCIATION);
            OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));

			CALLBACK_INFO(m_pCallback, DESTROY_ASSOCIATION);
			cond = ASC_destroyAssociation(&m_pAssoc);

            return listSendCompleteFile;
		}
	}

	CALLBACK_INFO(m_pCallback, DESTROY_ASSOCIATION);
	/* destroy the association, i.e. free memory of T_ASC_Association* structure. This */
	/* call is the counterpart of ASC_requestAssociation(...) which was called above. */
	cond = ASC_destroyAssociation(&m_pAssoc);
	if (cond.bad())
	{
        OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
		CALLBACK_ERROR(m_pCallback, DESTROY_ASSOCIATION);
        return listSendCompleteFile;
	}
	/* drop the network, i.e. free memory of T_ASC_Network* structure. This call */
	/* is the counterpart of ASC_initializeNetwork(...) which was called above. */
	CALLBACK_INFO(m_pCallback, DROP_NETWORK);
	cond = ASC_dropNetwork(&m_pNetwork);
	if (cond.bad())
	{
        OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
		CALLBACK_INFO(m_pCallback, DROP_NETWORK);
        return listSendCompleteFile;
	}

    OFLOG_FATAL(*m_pLoggerStoreSCU, "------------------------------------ End --------------------------------------------");


    return listSendCompleteFile;

    //SetSleep(10);

	/*
	SetSleep(10);
	const char* pServerAETitle = NULL;
	const char* pClientAETitle = NULL;
	OFString strServerIPnPort;

	char* pPeer = NULL;

	OFBool bSecureConnection = false;

	OFList<OFString> sopClassUIDList;    // the list of SOP classes
	OFList<OFString> sopInstanceUIDList; // the list of SOP instances
	

	OFCondition cond;

	int nLength = 0;

	char sopClassUID[128];
	char sopInstanceUID[128];

	OFString temp_str;

	//fileNameList.push_back("test.dcm");

	OFListIterator(OFString) iterFirst = m_pCurrentFileNameList->begin();
		OFString strFirstDcmFile = *iterFirst;

		//FindSOPClassAndInstanceInFile("mpeg_test.dcm", sopClassUID, sopInstanceUID);
		memset(sopClassUID, 0, 128);
		memset(sopInstanceUID, 0, 128);

		FindSOPClassAndInstanceInFile(strFirstDcmFile.c_str(), sopClassUID, sopInstanceUID);

	
	pServerAETitle = m_strServerAETitle.c_str();
	pClientAETitle = m_strAETitle.c_str();

	m_nTimeoutACSE = 10;

    m_pLoggerStoreSCU->ClearLog();

    //DCM_dcmnetLogger = *m_pLoggerStoreSCU;

    OFLOG_FATAL(*m_pLoggerStoreSCU, "------------------------ DICOM Store Start --------------------------------------------");

	m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 1, NULL);
	Sleep(10);

	cond = ASC_initializeNetwork(NET_REQUESTOR, 0, m_nTimeoutACSE, &m_pNetwork);
	if (cond.bad()) 
	{	
		m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 1, NULL);
		Sleep(10);
		return;
	}

	m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 2, NULL);
	Sleep(10);

	cond = ASC_createAssociationParameters(&m_pNetworkParams, m_nMaxReceivePDULength);
	if (cond.bad()) 
	{	
		m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 2, NULL);
		Sleep(10);
		return;
	}

	m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 3, NULL);
	Sleep(10);

	cond = ASC_setAPTitles(m_pNetworkParams, pClientAETitle, pServerAETitle, NULL);
	if (cond.bad())
	{
		m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 3, NULL);
		Sleep(10);
		return;
	}

	m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 4, NULL);
	Sleep(10);

	cond = ASC_setTransportLayerType(m_pNetworkParams, bSecureConnection);
	if (cond.bad()) 
	{
		m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 4, NULL);
		Sleep(10);
		return;
	}

 	gethostname(m_LocalHost, sizeof(m_LocalHost)-1);
// 	sprintf(peerHost, "%s:%d", pPeer, OFstatic_cast(int, m_nPort));	

	//sprintf(m_LocalHost, "192.168.123.23");
	char* pStrServerIPnPort = new char[1024];
	sprintf(pStrServerIPnPort, "%s:%d", m_strHostIP.c_str(), m_nPort);
	strServerIPnPort = pStrServerIPnPort;
	delete[] pStrServerIPnPort;



	nLength = strServerIPnPort.length();
	const char* pData = NULL;
	pData = strServerIPnPort.c_str();
	memset(m_PeerHost, 0, sizeof(m_PeerHost));
	memcpy(m_PeerHost, pData, nLength);

	m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 5, NULL);
	Sleep(10);

	cond = ASC_setPresentationAddresses(m_pNetworkParams, m_LocalHost, m_PeerHost);
	if (cond.bad())
	{
		m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 5, NULL);
		Sleep(10);
		return;
	}

	sopClassUIDList.push_back(sopClassUID);
	sopInstanceUIDList.push_back(sopInstanceUID);

	m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 6, NULL);
	Sleep(10);

	cond = AddStoragePresentationContexts(m_pNetworkParams, sopClassUIDList);
	if (cond.bad())
	{
		m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 6, NULL);
		Sleep(10);
		return;
	}

	dcmConnectionTimeout.set(5);

#include "dcmtk\dcmnet\dul.h"
	m_pNetworkParams->DULparams.requestedPresentationContext;

	m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 7, NULL);
	Sleep(10);

	cond = ASC_requestAssociation(m_pNetwork, m_pNetworkParams, &m_pAssoc);
	//cond = m_pNetClass->ASC_requestAssociation(m_pNetwork, m_pNetworkParams, &m_pAssoc);
	if (cond.bad())
	{
		if (cond == DUL_ASSOCIATIONREJECTED) 
		{
			T_ASC_RejectParameters rej;

			ASC_getRejectParameters(m_pNetworkParams, &rej);
			
            OFLOG_FATAL(*m_pLoggerStoreSCU, "Association Rejected:" << OFendl << ASC_printRejectParameters(temp_str, &rej));
		}
		else 
		{

            OFLOG_FATAL(*m_pLoggerStoreSCU, "Association Rejected:" << OFendl << cond.text());

			if(m_pAssoc!=NULL)
			{
				cond = ASC_destroyAssociation(&m_pAssoc);			
			}
			if(m_pNetwork!=NULL)
			{
				cond = ASC_dropNetwork(&m_pNetwork);
			}
		}

		m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 7, NULL);
		Sleep(10);
		return;
	}

	m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 8, NULL);
	Sleep(10);

	if (ASC_countAcceptedPresentationContexts(m_pNetworkParams) == 0) 
	{
        OFLOG_FATAL(*m_pLoggerStoreSCU, "No Acceptable Presentation Contexts");
		m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 8, NULL);
		Sleep(10);
		return;
	}

	m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 9, NULL);
	Sleep(10);

	cond = CheckUserIdentityResponse(m_pNetworkParams);
	if (cond.bad())
	{
        OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
		m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 9, NULL);
		Sleep(10);
		return;
	}

	cond = EC_Normal;
	OFListIterator(OFString) iter = m_pCurrentFileNameList->begin();
	OFListIterator(OFString) enditer = m_pCurrentFileNameList->end();

	if (iter != enditer)
	{
		while ((iter != enditer) && cond.good())
		{
			cond = cstore(m_pAssoc, *iter);

			if (cond.good())
			{
				cond = EC_Normal;
				m_bUnsuccessfulStoreEncountered = false;
			}
			++iter;
		}
	}
	else
	{
		cond = cstore(m_pAssoc, *iter);
	}
	

	if (cond == EC_Normal)
	{
		if (m_bAbortAssociation == true)
		{
            OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");
			cond = ASC_abortAssociation(m_pAssoc);
			if (cond.bad()) 
			{
                OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
				m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 10, NULL);
				Sleep(10);
				return;
			}
		}
		else {
            OFLOG_INFO(*m_pLoggerStoreSCU, "Releasing Association");
			cond = ASC_releaseAssociation(m_pAssoc);
			if (cond.bad())
			{
                OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Release Failed: " << DimseCondition::dump(temp_str, cond));
				m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 11, NULL);
				Sleep(10);
				return;
			}
		}
	}
	else if (cond == DUL_PEERREQUESTEDRELEASE)
	{
        OFLOG_ERROR(*m_pLoggerStoreSCU, "Protocol Error: Peer requested release (Aborting)");
        OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");
		cond = ASC_abortAssociation(m_pAssoc);
		if (cond.bad()) 
		{
            OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
			m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 12, NULL);
			Sleep(10);
			return;
		}
	}
	else if (cond == DUL_PEERABORTEDASSOCIATION)
	{
        OFLOG_INFO(*m_pLoggerStoreSCU, "Peer Aborted Association");
	}
	else
	{
        OFLOG_ERROR(*m_pLoggerStoreSCU, "Store SCU Failed: " << DimseCondition::dump(temp_str, cond));
        OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");
		cond = ASC_abortAssociation(m_pAssoc);
		if (cond.bad()) 
		{
            OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
			cond = ASC_destroyAssociation(&m_pAssoc);
			m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 13, NULL);
			Sleep(10);
			return;
		}
	}

	cond = ASC_destroyAssociation(&m_pAssoc);
	if (cond.bad()) 
	{
        OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
		m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 14, NULL);
		Sleep(10);
		return;
	}

	cond = ASC_dropNetwork(&m_pNetwork);
	if (cond.bad()) 
	{
        OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
		m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 15, NULL);
		Sleep(10);
		return;
	}


	m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_COMPLETE, NULL, NULL);
	Sleep(10);


    OFLOG_FATAL(*m_pLoggerStoreSCU, "------------------------------------ End --------------------------------------------");

	SetSleep(1);
	*/
}

void CSDCMSendImpl::SetLogLevel(int nLevel)
{
    //m_pLoggerStoreSCU->SetLogLevel((OFLogger::LogLevel)nLevel);
}

OFLogger* CSDCMSendImpl::GetLogger()
{
    return m_pLoggerStoreSCU;
}
