/*
*  
*  $Id: incomingdicomassociationcommand.cpp $
*  Ginkgo CADx Project
*
*  Copyright 2008-12 MetaEmotion S.L. All rights reserved.
*  http://ginkgo-cadx.com
*
*  This file is licensed under LGPL v3 license.
*  See License.txt for details
*
*/
#include <wx/string.h>

#include <api/imodelointegracion.h>
#include <api/internationalization/internationalization.h>
#include <commands/incomingdicomassociationcommand.h>
#include <commands/comandoincluirhistorial.h>
#include <main/controllers/controladorlog.h>
#include <main/controllers/controladorcomandos.h>
#include <main/entorno.h>
#include <eventos/mensajes.h>


#ifdef MACRO_QUE_ESTORBA
#define verify MACRO_QUE_ESTORBA
#endif

#include <dcmtk/dcmnet/cond.h>

#include <dcmtk/dcmnet/assoc.h>
#include <dcmtk/dcmnet/dimse.h>

#include <dcmtk/dcmdata/dcfilefo.h>
#include <dcmtk/dcmdata/dcmetinf.h>

#include <dcmtk/dcmdata/dcdeftag.h>
#ifdef MACRO_QUE_ESTORBA
#define verify MACRO_QUE_ESTORBA
#endif

#include <main/controllers/pacscontroller.h>
#include <main/controllers/historycontroller.h>
#include <main/controllers/controladoreventos.h>
struct StoreCallbackData
{
	std::string imageFileName;
	DcmFileFormat* dcmff;
	T_ASC_Association* assoc;
};

/**
* This function.is used to indicate progress when storescp receives instance data over the
* network. On the final call to this function (identified by progress->state == DIMSE_StoreEnd)
* this function will store the data set which was received over the network to a file.
* Earlier calls to this function will simply cause some information to be dumped to stdout.
*
* Parameters:
*   callbackData  - [in] data for this callback function
*   progress      - [in] The state of progress. (identifies if this is the initial or final call
*                   to this function, or a call in between these two calls.
*   req           - [in] The original store request message.
*   imageFileName - [in] The path to and name of the file the information shall be written to.
*   imageDataSet  - [in] The data set which shall be stored in the image file
*   rsp           - [inout] the C-STORE-RSP message (will be sent after the call to this function)
*   statusDetail  - [inout] This variable can be used to capture detailed information with regard to
*                   the status information which is captured in the status element (0000,0900). Note
*                   that this function does specify any such information, the pointer will be set to NULL.
*/
static void storeSCPCallback( void * callbackData, T_DIMSE_StoreProgress * progress, T_DIMSE_C_StoreRQ * /*req*/, char * /*imageFileName*/, DcmDataset ** imageDataSet, T_DIMSE_C_StoreRSP * rsp, DcmDataset ** statusDetail)
{
	//DIC_UI sopClass;
	//DIC_UI sopInstance;

	std::string ambitoLog = "storeSCPCallback";

	// if this is the final call of this function, save the data which was received to a file
	// (note that we could also save the image somewhere else, put it in database, etc.)
	if (progress->state == DIMSE_StoreEnd)
	{
		OFString tmpStr;

		// do not send status detail information
		*statusDetail = NULL;

		// remember callback data
		StoreCallbackData *cbdata = OFstatic_cast(StoreCallbackData *, callbackData);

		// Concerning the following line: an appropriate status code is already set in the resp structure,
		// it need not be success. For example, if the caller has already detected an out of resources problem
		// then the status will reflect this.  The callback function is still called to allow cleanup.
		//rsp->DimseStatus = STATUS_Success;

		// we want to write the received information to a file only if this information
		// is present and the options opt_bitPreserving and opt_ignore are not set.
		if ((imageDataSet != NULL) && (*imageDataSet != NULL))
		{
			OFString fileName;

			OFString OFPacienteUId;
			OFString OFEstudioUId;
			OFString OFSerieUId;
			OFString OFImagenUId;

			std::string PacienteUId;
			std::string EstudioUId;
			std::string SerieUId;
			std::string ImagenUId;

			if ((*imageDataSet)->findAndGetOFString(DCM_PatientID, OFPacienteUId).good()) {
				PacienteUId.assign(OFPacienteUId.c_str());
			} else {
				LOG_ERROR(ambitoLog, _Std("element patient id absent in dataset" ));
				rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand;
				return;
			}
			if ((*imageDataSet)->findAndGetOFString(DCM_StudyInstanceUID, OFEstudioUId).good()) {
				EstudioUId.assign(OFEstudioUId.c_str());
			} else {
				LOG_ERROR(ambitoLog, _Std("element study instance uid absent in dataset" ));
				rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand;
				return;
			}
			if ((*imageDataSet)->findAndGetOFString(DCM_SeriesInstanceUID, OFSerieUId).good()) {
				SerieUId.assign(OFSerieUId.c_str());
			} else {
				LOG_ERROR(ambitoLog, _Std("element series instance uid absent in dataset" ));
				rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand;
				return;
			}

			if ((*imageDataSet)->findAndGetOFString(DCM_SOPInstanceUID, OFImagenUId).good()) {
				ImagenUId.assign(OFImagenUId.c_str());
			} else {
				LOG_ERROR(ambitoLog, _Std("element sop instance uid absent in dataset" ));
				rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand;
				return;
			}

			std::string rutaStd;
			if (!GIL::DICOM::PACSController::Instance()->GetRutaImagenTemp(PacienteUId,EstudioUId,SerieUId,ImagenUId, rutaStd)) {
				LOG_ERROR(ambitoLog, "could not create subdirectory for study: " << rutaStd);
				rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand;
				return;
			}
			fileName = rutaStd.c_str();

			// determine the transfer syntax which shall be used to write the information to the file
			E_TransferSyntax xfer = (*imageDataSet)->getOriginalXfer();

			// store file either with meta header or as pure dataset
			LOG_INFO(ambitoLog, "storing DICOM file: " << fileName);
			/*   if (OFStandard::fileExists(fileName))
			{
			LOG_WARN(ambitoLog, "DICOM file already exists, overwriting: " << fileName);
			}*/
			OFCondition cond = cbdata->dcmff->saveFile(fileName.c_str(), xfer);
			if (cond.bad())
			{
				LOG_ERROR(ambitoLog, "cannot write DICOM file: " << fileName << ": " << cond.text());
				rsp->DimseStatus = STATUS_STORE_Refused_OutOfResources;
			}

			// check the image to make sure it is consistent, i.e. that its sopClass and sopInstance correspond
			// to those mentioned in the request. If not, set the status in the response message variable.
			if (rsp->DimseStatus == STATUS_Success)
			{
				// which SOP class and SOP instance ?
				/* if (!DU_findSOPClassAndInstanceInDataSet(*imageDataSet, sopClass, sopInstance))
				{
				LOG_ERROR(ambitoLog, "bad DICOM file: " << fileName);
				rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand;
				}
				else if (strcmp(sopClass, req->AffectedSOPClassUID) != 0)
				{
				rsp->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass;
				}
				else if (strcmp(sopInstance, req->AffectedSOPInstanceUID) != 0)
				{
				rsp->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass;
				}*/
			}
		}

		// in case opt_bitPreserving is set, do some other things
		/* if( opt_bitPreserving )
		{
		// we need to set outputFileNameArray and outputFileNameArrayCnt to be
		// able to perform the placeholder substitution in executeOnReception()
		outputFileNameArray.push_back(OFStandard::getFilenameFromPath(tmpStr, cbdata->imageFileName));
		}*/
	}



	/*


	// determine if the association shall be aborted
	if( (opt_abortDuringStore && progress->state != DIMSE_StoreBegin) ||
	(opt_abortAfterStore && progress->state == DIMSE_StoreEnd) )
	{
	OFLOG_INFO(storescpLogger, "ABORT initiated (due to command line options)");
	ASC_abortAssociation((OFstatic_cast(StoreCallbackData*, callbackData))->assoc);
	rsp->DimseStatus = STATUS_STORE_Refused_OutOfResources;
	return;
	}

	// if opt_sleepAfter is set, the user requires that the application shall
	// sleep a certain amount of seconds after having received one PDU.
	if (opt_sleepDuring > 0)
	{
	OFStandard::sleep(OFstatic_cast(unsigned int, opt_sleepDuring));
	}

	// dump some information if required (depending on the progress state)
	// 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:
	COUT << "RECV: ";
	break;
	case DIMSE_StoreEnd:
	COUT << OFendl;
	break;
	default:
	COUT << '.';
	break;
	}
	COUT.flush();
	}

	// if this is the final call of this function, save the data which was received to a file
	// (note that we could also save the image somewhere else, put it in database, etc.)
	if (progress->state == DIMSE_StoreEnd)
	{
	OFString tmpStr;

	// do not send status detail information
	*statusDetail = NULL;

	// remember callback data
	StoreCallbackData *cbdata = OFstatic_cast(StoreCallbackData *, callbackData);

	// Concerning the following line: an appropriate status code is already set in the resp structure,
	// it need not be success. For example, if the caller has already detected an out of resources problem
	// then the status will reflect this.  The callback function is still called to allow cleanup.
	//rsp->DimseStatus = STATUS_Success;

	// we want to write the received information to a file only if this information
	// is present and the options opt_bitPreserving and opt_ignore are not set.
	if ((imageDataSet != NULL) && (*imageDataSet != NULL) && !opt_bitPreserving && !opt_ignore)
	{
	OFString fileName;

	// in case one of the --sort-xxx options is set, we need to perform some particular steps to
	// determine the actual name of the output file
	if (opt_sortStudyMode != ESM_None)
	{
	// determine the study instance UID in the (current) DICOM object that has just been received
	OFString currentStudyInstanceUID;
	if ((*imageDataSet)->findAndGetOFString(DCM_StudyInstanceUID, currentStudyInstanceUID).bad() || currentStudyInstanceUID.empty())
	{
	OFLOG_ERROR(storescpLogger, "element StudyInstanceUID " << DCM_StudyInstanceUID << " absent or empty in data set");
	rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand;
	return;
	}

	// if --sort-on-patientname is active, we need to extract the
	// patient's name (format: last_name^first_name)
	OFString currentPatientName;
	if (opt_sortStudyMode == ESM_PatientName)
	{
	OFString tmpName;
	if ((*imageDataSet)->findAndGetOFString(DCM_PatientName, tmpName).bad() || tmpName.empty())
	{
	// default if patient name is missing or empty
	tmpName = "ANONYMOUS";
	OFLOG_WARN(storescpLogger, "element PatientName " << DCM_PatientName << " absent or empty in data set, using '"
	<< tmpName << "' instead");
	}

	// substitute non-ASCII characters in patient name to ASCII "equivalent" 
	const size_t length = tmpName.length();
	for (size_t i = 0; i < length; i++)
	mapCharacterAndAppendToString(tmpName[i], currentPatientName);
	}

	// if this is the first DICOM object that was received or if the study instance UID in the
	// current DICOM object does not equal the last object's study instance UID we need to create
	// a new subdirectory in which the current DICOM object will be stored
	if (lastStudyInstanceUID.empty() || (lastStudyInstanceUID != currentStudyInstanceUID))
	{
	// if lastStudyInstanceUID is non-empty, we have just completed receiving all objects for one
	// study. In such a case, we need to set a certain indicator variable (lastStudySubdirectoryPathAndName),
	// so that we know that executeOnEndOfStudy() might have to be executed later. In detail, this indicator
	// variable will contain the path and name of the last study's subdirectory, so that we can still remember
	// this directory, when we execute executeOnEndOfStudy(). The memory that is allocated for this variable
	// here will be freed after the execution of executeOnEndOfStudy().
	if (!lastStudyInstanceUID.empty())
	lastStudySubdirectoryPathAndName = subdirectoryPathAndName;

	// create the new lastStudyInstanceUID value according to the value in the current DICOM object
	lastStudyInstanceUID = currentStudyInstanceUID;

	// get the current time (needed for subdirectory name)
	OFDateTime dateTime;
	dateTime.setCurrentDateTime();

	// create a name for the new subdirectory.
	char timestamp[32];
	sprintf(timestamp, "%04u%02u%02u_%02u%02u%02u%03u",
	dateTime.getDate().getYear(), dateTime.getDate().getMonth(), dateTime.getDate().getDay(),
	dateTime.getTime().getHour(), dateTime.getTime().getMinute(), dateTime.getTime().getIntSecond(), dateTime.getTime().getMilliSecond());

	OFString subdirectoryName;
	switch (opt_sortStudyMode)
	{
	case ESM_Timestamp:
	// pattern: "[prefix]_[YYYYMMDD]_[HHMMSSMMM]"
	subdirectoryName = opt_sortStudyDirPrefix;
	if (!subdirectoryName.empty())
	subdirectoryName += '_';
	subdirectoryName += timestamp;
	break;
	case ESM_StudyInstanceUID:
	// pattern: "[prefix]_[Study Instance UID]"
	subdirectoryName = opt_sortStudyDirPrefix;
	if (!subdirectoryName.empty())
	subdirectoryName += '_';
	subdirectoryName += currentStudyInstanceUID;
	break;
	case ESM_PatientName:
	// pattern: "[Patient's Name]_[YYYYMMDD]_[HHMMSSMMM]"
	subdirectoryName = currentPatientName;
	subdirectoryName += '_';
	subdirectoryName += timestamp;
	break;
	case ESM_None:
	break;
	}

	// create subdirectoryPathAndName (string with full path to new subdirectory)
	OFStandard::combineDirAndFilename(subdirectoryPathAndName, OFStandard::getDirNameFromPath(tmpStr, cbdata->imageFileName), subdirectoryName);

	// check if the subdirectory already exists
	// if it already exists dump a warning
	if( OFStandard::dirExists(subdirectoryPathAndName) )
	OFLOG_WARN(storescpLogger, "subdirectory for study already exists: " << subdirectoryPathAndName);
	else
	{
	// if it does not exist create it
	OFLOG_INFO(storescpLogger, "creating new subdirectory for study: " << subdirectoryPathAndName);
	#ifdef HAVE_WINDOWS_H
	if( _mkdir( subdirectoryPathAndName.c_str() ) == -1 )
	#else
	if( mkdir( subdirectoryPathAndName.c_str(), S_IRWXU | S_IRWXG | S_IRWXO ) == -1 )
	#endif
	{
	OFLOG_ERROR(storescpLogger, "could not create subdirectory for study: " << subdirectoryPathAndName);
	rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand;
	return;
	}
	// all objects of a study have been received, so a new subdirectory is started.
	// ->timename counter can be reset, because the next filename can't cause a duplicate.
	// if no reset would be done, files of a new study (->new directory) would start with a counter in filename
	if (opt_timeNames)
	timeNameCounter = -1;
	}
	}

	// integrate subdirectory name into file name (note that cbdata->imageFileName currently contains both
	// path and file name; however, the path refers to the output directory captured in opt_outputDirectory)
	OFStandard::combineDirAndFilename(fileName, subdirectoryPathAndName, OFStandard::getFilenameFromPath(tmpStr, cbdata->imageFileName));

	// update global variable outputFileNameArray
	// (might be used in executeOnReception() and renameOnEndOfStudy)
	outputFileNameArray.push_back(tmpStr);
	}
	// if no --sort-xxx option is set, the determination of the output file name is simple
	else
	{
	fileName = cbdata->imageFileName;

	// update global variables outputFileNameArray
	// (might be used in executeOnReception() and renameOnEndOfStudy)
	outputFileNameArray.push_back(OFStandard::getFilenameFromPath(tmpStr, fileName));
	}

	// determine the transfer syntax which shall be used to write the information to the file
	E_TransferSyntax xfer = opt_writeTransferSyntax;
	if (xfer == EXS_Unknown) xfer = (*imageDataSet)->getOriginalXfer();

	// store file either with meta header or as pure dataset
	OFLOG_INFO(storescpLogger, "storing DICOM file: " << fileName);
	if (OFStandard::fileExists(fileName))
	{
	OFLOG_WARN(storescpLogger, "DICOM file already exists, overwriting: " << fileName);
	}
	OFCondition cond = cbdata->dcmff->saveFile(fileName.c_str(), xfer, opt_sequenceType, opt_groupLength,
	opt_paddingType, OFstatic_cast(Uint32, opt_filepad), OFstatic_cast(Uint32, opt_itempad),
	(opt_useMetaheader) ? EWM_fileformat : EWM_dataset);
	if (cond.bad())
	{
	OFLOG_ERROR(storescpLogger, "cannot write DICOM file: " << fileName << ": " << cond.text());
	rsp->DimseStatus = STATUS_STORE_Refused_OutOfResources;
	}

	// check the image to make sure it is consistent, i.e. that its sopClass and sopInstance correspond
	// to those mentioned in the request. If not, set the status in the response message variable.
	if ((rsp->DimseStatus == STATUS_Success)&&(!opt_ignore))
	{
	// which SOP class and SOP instance ?
	if (!DU_findSOPClassAndInstanceInDataSet(*imageDataSet, sopClass, sopInstance, opt_correctUIDPadding))
	{
	OFLOG_ERROR(storescpLogger, "bad DICOM file: " << fileName);
	rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand;
	}
	else if (strcmp(sopClass, req->AffectedSOPClassUID) != 0)
	{
	rsp->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass;
	}
	else if (strcmp(sopInstance, req->AffectedSOPInstanceUID) != 0)
	{
	rsp->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass;
	}
	}
	}

	// in case opt_bitPreserving is set, do some other things
	if( opt_bitPreserving )
	{
	// we need to set outputFileNameArray and outputFileNameArrayCnt to be
	// able to perform the placeholder substitution in executeOnReception()
	outputFileNameArray.push_back(OFStandard::getFilenameFromPath(tmpStr, cbdata->imageFileName));
	}
	}
	*/
}


GADAPI::PACS::IncomingDicomAssociationCommandParams::IncomingDicomAssociationCommandParams(T_ASC_Association* assoc, unsigned long rcvTimeout) {
	m_pAssoc = assoc;
	m_rcvTimeout = rcvTimeout;
}

//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------

GADAPI::PACS::IncomingDicomAssociationCommand::IncomingDicomAssociationCommand(IncomingDicomAssociationCommandParams* pParams, const std::string& name) : IComando(pParams, name){
	m_pIncommingassociationParams = pParams;
	ambitolog = name;
}

GADAPI::PACS::IncomingDicomAssociationCommand::~IncomingDicomAssociationCommand() {
	T_ASC_Association* assoc = m_pIncommingassociationParams->m_pAssoc;
	CONDITION cond = ASC_dropSCPAssociation(assoc);
	OFString temp_str;

	if (cond.bad())
	{
		LOG_FATAL(ambitolog, DimseCondition::dump(temp_str, cond).c_str());
	}

	cond = ASC_destroyAssociation(&assoc);
	if (cond.bad())
	{
		LOG_FATAL(ambitolog, DimseCondition::dump(temp_str, cond).c_str());
	}
}

void GADAPI::PACS::IncomingDicomAssociationCommand::Execute() {
	CONDITION cond = EC_Normal;
	OFString temp_str;

	T_ASC_Association* assoc = m_pIncommingassociationParams->m_pAssoc;

	T_DIMSE_Message msg;
	T_ASC_PresentationContextID presID = 0;
	DcmDataset *statusDetail = NULL;

	std::string cmdname;

	// start a loop to be able to receive more than one DIMSE command
	while( cond == EC_Normal || cond == DIMSE_NODATAAVAILABLE || cond == DIMSE_OUTOFRESOURCES )
	{
		// receive a DIMSE command over the network
		cond = DIMSE_receiveCommand(assoc, DIMSE_BLOCKING, m_pIncommingassociationParams->m_rcvTimeout, &presID, &msg, &statusDetail);

		// if the command which was received has extra status
		// detail information, dump this information
		if (statusDetail != NULL)
		{
			LOG_WARN(ambitolog, "Status Detail:" << OFendl << DcmObject::PrintHelper(*statusDetail));
			delete statusDetail;
		}

		// check if peer did release or abort, or if we have a valid message
		if (cond == EC_Normal)
		{

			switch (msg.CommandField)
			{
			case DIMSE_C_ECHO_RQ:

				echoSCP(assoc, &msg, presID, &cond);

				break;
			case DIMSE_C_STORE_RQ:
				cmdname = "C-STORE-RQ";

				storeSCP(assoc, &msg, presID, &cond);
				break;

			case DIMSE_C_GET_RQ:
				cmdname = "C-GET-RQ";
#if 0
				getSCP(assoc, &msg, presID, &cond);
#else
				{
					LOG_ERROR(ambitolog, _Std("Ignoring incoming operation ") << cmdname << ":" << _Std("Not implemented"));

					DIC_UL x = 0, y = 0;
					DIMSE_ignoreDataSet(assoc, DIMSE_BLOCKING, 0, &x, &y);

					T_DIMSE_Message rsp;
					bzero((char*)&rsp, sizeof(rsp));
					rsp.CommandField = DIMSE_C_GET_RSP;
					rsp.msg.CGetRSP.DimseStatus = STATUS_GET_Failed_SOPClassNotSupported;
					rsp.msg.CGetRSP.MessageIDBeingRespondedTo = msg.msg.CGetRQ.MessageID;
					strcpy(rsp.msg.CGetRSP.AffectedSOPClassUID, msg.msg.CGetRQ.AffectedSOPClassUID);
					rsp.msg.CGetRSP.opts = O_GET_AFFECTEDSOPCLASSUID
						| O_GET_NUMBEROFREMAININGSUBOPERATIONS
						| O_GET_NUMBEROFCOMPLETEDSUBOPERATIONS
						| O_GET_NUMBEROFFAILEDSUBOPERATIONS
						| O_GET_NUMBEROFWARNINGSUBOPERATIONS;
					rsp.msg.CGetRSP.DataSetType = DIMSE_DATASET_NULL;
					rsp.msg.CGetRSP.NumberOfCompletedSubOperations = 0;
					rsp.msg.CGetRSP.NumberOfFailedSubOperations = 1;
					rsp.msg.CGetRSP.NumberOfRemainingSubOperations = 0;
					rsp.msg.CGetRSP.NumberOfWarningSubOperations = 0;

					DcmDataset ds_detail;
					ds_detail.putAndInsertString(DCM_SpecificCharacterSet, "ISO_IR 192");
					ds_detail.putAndInsertString(DCM_ErrorComment, _Std("Not implemented").c_str());
					cond = DIMSE_sendMessageUsingMemoryData(assoc, presID, &rsp, &ds_detail, NULL, NULL, NULL);					
				}
#endif
				break;
			case DIMSE_C_FIND_RQ:
				cmdname = "C-FIND-RQ";
				cond = DIMSE_BADCOMMANDTYPE;
				break;
			case DIMSE_C_MOVE_RQ:
				cmdname = "C-MOVE-RQ";
				cond = DIMSE_BADCOMMANDTYPE;
				break;
			case DIMSE_C_CANCEL_RQ:
				cmdname = "C-CANCEL-RQ";
				cond = DIMSE_BADCOMMANDTYPE;
				break;
			case DIMSE_N_EVENT_REPORT_RQ:
				cmdname = "N-EVENT-RQ";
				cond = DIMSE_BADCOMMANDTYPE;
				break;
			case DIMSE_N_GET_RQ:
				cmdname = "N-GET-RQ";
				cond = DIMSE_BADCOMMANDTYPE;
				break;
			case DIMSE_N_SET_RQ:
				cmdname = "N-SET-RQ";
				cond = DIMSE_BADCOMMANDTYPE;
				break;
			case DIMSE_N_ACTION_RQ:
				cmdname = "N-ACTION-RQ";
				cond = DIMSE_BADCOMMANDTYPE;
				break;
			case DIMSE_N_CREATE_RQ:
				cmdname = "N-CREATE-RQ";
				cond = DIMSE_BADCOMMANDTYPE;
				break;
			case DIMSE_N_DELETE_RQ:
				cmdname = "N-DELETE-RQ";
				cond = DIMSE_BADCOMMANDTYPE;
				break;
			case DIMSE_NOTHING:
				cmdname = "NOTHING";
				cond = DIMSE_BADCOMMANDTYPE;
				break;
			default:
				// we cannot handle this kind of message
				cond = DIMSE_BADCOMMANDTYPE;				
				break;
			}
		}
	}

	if (cond == DIMSE_BADCOMMANDTYPE) {
		std::ostringstream os;
				os << "0x" << std::hex << OFstatic_cast(unsigned, msg.CommandField);
				cmdname = os.str();
				LOG_ERROR(ambitolog, _Std("Ignoring incoming operation ") << cmdname << ":" << _Std("Not implemented"));
		ASC_abortAssociation(assoc);
	}
	else {
		if (cond == DUL_PEERREQUESTEDRELEASE) {
			LOG_INFO(ambitolog, _Std("Association Release"));
			cond = ASC_acknowledgeRelease(assoc);
		}
		else if (cond == DUL_PEERABORTEDASSOCIATION) {
			LOG_INFO(ambitolog, _Std("Association Aborted"));
		}
		else {
			LOG_ERROR(ambitolog, "DIMSE failure (aborting association): " << DimseCondition::dump(temp_str, cond).c_str());
			// some kind of error so abort the association
			cond = ASC_abortAssociation(assoc);
		}
		if (cond.bad()) {
			LOG_WARN(ambitolog, "DIMSE failure (closing association): " << DimseCondition::dump(temp_str, cond).c_str());
		}
	}
}


void GADAPI::PACS::IncomingDicomAssociationCommand::echoSCP( T_ASC_Association * assoc, T_DIMSE_Message * msg, unsigned char presID, OFCondition* rcond)
{
	OFString temp_str;
	LOG_INFO(ambitolog, "Received Echo Request");
	LOG_DEBUG(ambitolog, DIMSE_dumpMessage(temp_str, msg->msg.CEchoRQ, DIMSE_INCOMING, NULL, presID));

	// the echo succeeded !! 
	OFCondition cond = DIMSE_sendEchoResponse(assoc, presID, &msg->msg.CEchoRQ, STATUS_Success, NULL);
	if (cond.bad())
	{
		LOG_ERROR(ambitolog, "Echo SCP Failed: " << DimseCondition::dump(temp_str, cond));
	}
	*rcond = cond;
}

/**
* This function processes a DIMSE C-STORE-RQ commmand that was
* received over the network connection.
*
* Parameters:
*   assoc  - [in] The association (network connection to another DICOM application).
*   msg    - [in] The DIMSE C-STORE-RQ message that was received.
*   presID - [in] The ID of the presentation context which was specified in the PDV which contained
*                 the DIMSE command.
*/
void GADAPI::PACS::IncomingDicomAssociationCommand::storeSCP( T_ASC_Association *assoc, T_DIMSE_Message *msg, unsigned char presID, OFCondition* rcond) {

	OFCondition cond = EC_Normal;
	T_DIMSE_C_StoreRQ *req;

	// assign the actual information of the C-STORE-RQ command to a local variable
	req = &msg->msg.CStoreRQ;

	if (m_TempDir.size() == 0) {
		 m_TempDir = GNC::Entorno::Instance()->CreateGinkgoTempFile();
	}

	std::string fileName = tempnam(m_TempDir.c_str(), "sscpfile_");

	// dump some information if required
	OFString str;
	LOG_INFO(ambitolog, "Received Store Request: MsgID " << req->MessageID << ", (" << dcmSOPClassUIDToModality(req->AffectedSOPClassUID, "OT") << ")");
	LOG_DEBUG(ambitolog, DIMSE_dumpMessage(str, *req, DIMSE_INCOMING, NULL, presID));

	// intialize some variables
	StoreCallbackData callbackData;
	callbackData.assoc = assoc;
	callbackData.imageFileName = fileName.c_str();
	DcmFileFormat dcmff;
	callbackData.dcmff = &dcmff;

	// store SourceApplicationEntityTitle in metaheader
	if (assoc && assoc->params)
	{
		const char *aet = assoc->params->DULparams.callingAPTitle;
		if (aet) dcmff.getMetaInfo()->putAndInsertString(DCM_SourceApplicationEntityTitle, aet);
	}

	// define an address where the information which will be received over the network will be stored

	// if opt_bitPreserving is set, the user requires that the data shall be
	// written exactly as it was received. Depending on this option, function
	// DIMSE_storeProvider must be called with certain parameters.
	bool opt_useMetaheader = true;
	int opt_dimse_timeout = 60;
	cond = DIMSE_storeProvider(assoc, presID, req, fileName.c_str(), opt_useMetaheader, NULL, storeSCPCallback, &callbackData, DIMSE_NONBLOCKING, opt_dimse_timeout);


	// if some error occured, dump corresponding information and remove the outfile if necessary
	if (cond.bad())
	{
		OFString temp_str;
		LOG_ERROR(ambitolog, "Store SCP Failed: " << DimseCondition::dump(temp_str, cond));
		// remove file
		if (strcmp(fileName.c_str(), NULL_DEVICE_NAME) != 0)
			OFStandard::deleteFile(fileName.c_str());
	}
	else {
		m_DicomFileList.push_back(fileName);
	}
	
	*rcond = cond;
}

void GADAPI::PACS::IncomingDicomAssociationCommand::Update() {


	if(m_Error != ""){
		LOG_WARN(ambitolog, m_Error);
		GNC::GCS::ControladorEventos::Instance()->ProcesarEvento(new GNC::GCS::Events::EventoMensajes(NULL, m_Error, GNC::GCS::Events::EventoMensajes::PopUpMessage, false, GNC::GCS::Events::EventoMensajes::Error));
	}
	
	if (m_DicomFileList.size() > 0) {
		GADAPI::ComandoIncluirHistorial::ComandoIncluirHistorialParams* pParams = new GADAPI::ComandoIncluirHistorial::ComandoIncluirHistorialParams(m_DicomFileList, false, GNC::GCS::HistoryController::TAA_MOVE);
		GADAPI::ComandoIncluirHistorial::ComandoIncluirHistorial * pCmd = new GADAPI::ComandoIncluirHistorial::ComandoIncluirHistorial(pParams);
		GNC::GCS::IControladorComandos::Instance()->ProcessAsync(_Std("Including files..."),pCmd,NULL);
	}
}
