/*
 *  
 *  $Id: dicomfindassociation.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
 *
 *  Code adapted from Aeskulap
 *
 */
#include <api/controllers/icontroladorlog.h>
#include <main/controllers/controladorlog.h>
#include "dicomfindassociation.h"
#include <wx/string.h>
#include <wx/intl.h>
#include <api/internationalization/internationalization.h>

#ifdef verify
#define MACRO_QUE_ESTORBA verify
#undef verify
#endif


#ifdef MACRO_QUE_ESTORBA
#define verify MACRO_QUE_ESTORBA
#endif

FindAssociation::FindAssociation(const std::string& ambitolog) : Association(ambitolog) {
	SetFindRootQueryRetrieveInformationModel(FRQRIM_Study);
	maxResults = 400;
	bPushResults = true;
}

FindAssociation::~FindAssociation() {
	DeleteResultStack();
}

CONDITION FindAssociation::findSCU(T_ASC_Association *assoc, DcmDataset *query) {
	CONDITION cond;
	DIC_US msgId = assoc->nextMsgID++;
	T_ASC_PresentationContextID presId;
	T_DIMSE_C_FindRQ req;
	T_DIMSE_C_FindRSP rsp;
	DcmDataset *statusDetail = NULL;
	
	if (query == NULL) {
		LOG_ERROR(ambitolog, "DIMSE Query dataset nulo");
		return DIMSE_BADDATA;
	}
	
	DeleteResultStack();
	
	/* which presentation context should be used */
	presId = ASC_findAcceptedPresentationContextID(assoc, m_abstractSyntax.c_str());
	if (presId == 0) {
		LOG_ERROR(ambitolog, "PresentationContextId inválido");
		return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
	}
	
	req.MessageID = msgId;
	req.DataSetType = DIMSE_DATASET_PRESENT;
	req.Priority = DIMSE_PRIORITY_LOW;
	strcpy(req.AffectedSOPClassUID, m_abstractSyntax.c_str());
	
	FindCallbackInfo callbackData;
	callbackData.pCaller = this;
	callbackData.assoc = assoc;
	
	cond = DIMSE_findUser(assoc, presId, &req, query,
				   findCallback, (void*) &callbackData,
				   (m_timeout == 0) ? DIMSE_BLOCKING : DIMSE_NONBLOCKING,
				   m_timeout,
				   &rsp, &statusDetail);
	
	if (cond == DIMSE_NORMAL) {
		if (rsp.DimseStatus == STATUS_Success) {
		}
	}
	
	if (statusDetail != NULL) {
		LOG_DEBUG(ambitolog, "DIMSE_findUser(): Estado: " << std::endl << DumpDataset(statusDetail));
		delete statusDetail;
	}
	return cond;
}

void FindAssociation::findCallback(void* callbackData, T_DIMSE_C_FindRQ* /*rq*/, int responseCount, T_DIMSE_C_FindRSP* rsp, DcmDataset *responseIdentifiers) {
	FindCallbackInfo* pCallback = (FindCallbackInfo*) callbackData;
	
	if (pCallback->pCaller->maxResults > 0 && responseCount > pCallback->pCaller->maxResults) {
		LOG_DEBUG(pCallback->pCaller->ambitolog, "findCallback(): Ignorando respuesta número " << responseCount << ". El número maximo de respuestas se fijó en " << pCallback->pCaller->maxResults);
		rsp->DimseStatus = STATUS_FIND_Cancel_MatchingTerminatedDueToCancelRequest;
		pCallback->pCaller->Stop();
		ASC_releaseAssociation(pCallback->assoc);
		return;
	}
	
	wxString mess = wxString::Format(_("%d results has been found"),responseCount);
	std::string mensaje(mess.ToUTF8());
	
	LOG_DEBUG(pCallback->pCaller->ambitolog, "Procesando Respuesta número " << responseCount);
	if(!pCallback->pCaller->NotificarProgreso(0.0f, mensaje))
	{
		rsp->DimseStatus = STATUS_FIND_Cancel_MatchingTerminatedDueToCancelRequest;
		pCallback->pCaller->Stop();
		ASC_releaseAssociation(pCallback->assoc);
		LOG_INFO(pCallback->pCaller->ambitolog, "Operation canceled by user");
		return;
	} else {
		DcmDataset* response = new DcmDataset(*responseIdentifiers);
		
		if (pCallback->pCaller->bPushResults) {
			pCallback->pCaller->result.push(response);
		}
		else {
		    LOG_WARN("C-FIND", "No se obtuvieron resultados para la búsqueda");
		}
		pCallback->pCaller->OnResponseReceived(response);
	}
}

CONDITION FindAssociation::SendObject(DcmDataset *dataset) {
	return findSCU(assoc, dataset);
}

void FindAssociation::OnResponseReceived(DcmDataset* response) {
	LOG_DEBUG(ambitolog, "Respuesta recibida: " << std::endl << DumpDataset(response));
}

DcmStack* FindAssociation::GetResultStack() {
	return &result;
}

DcmStack FindAssociation::CopyResultStack() {
	DcmStack copy;
	
	for (unsigned int i = 0; i < result.card(); i++) {
		DcmDataset* dset = new DcmDataset( *(static_cast<DcmDataset*>(result.elem(i))) );
		copy.push(dset);
	}
	
	return copy;
}

void FindAssociation::DeleteResultStack() {
	DcmDataset* obj = NULL;
	unsigned int size = result.card();
	
	for (Uint32 i = 0; i < size; i++) {
		obj = static_cast<DcmDataset*>(result.elem(i));
		delete obj;
	}
	
	result.clear();
}

void FindAssociation::SetMaxResults(int max) {
	maxResults = max;
}

int FindAssociation::GetMaxResults() {
	return maxResults;
}

void FindAssociation::OnAddPresentationContext(T_ASC_Parameters* params) {
	CONDITION cond = ASC_addPresentationContext(params, 1, m_abstractSyntax.c_str(), AllTransferSyntaxes, 3);
	if (cond.bad()) {
		LOG_ERROR(ambitolog, "Unable to add default presentation context");
	}
}
