/*
 *  
 *  $Id: dicomcustomassociation.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 <wx/intl.h>
#include <wx/filename.h>

#include <api/controllers/icontroladorlog.h>
#include <api/controllers/ipacscontroller.h>
#include <main/controllers/controladorlog.h>
#include <main/entorno.h>

#include <main/controllers/dcmtk/ginkgouid.h>
#include <api/internationalization/internationalization.h>

#include "dicomcustomassociation.h"
#include "helpercompresion.h"

#include <api/dicom/dcmdictionary.h>
//#include <main/controllers/dicommanager.h>
#include <api/dicom/dcmdictionary.h>

#ifdef verify
#define MACRO_QUE_ESTORBA verify
#undef verify
#endif
#include <dcmtk/dcmdata/dctk.h>
#include <dcmtk/dcmimgle/dcmimage.h>
#include <dcmtk/dcmdata/dcfilefo.h>
#include <dcmtk/dcmdata/dcdatset.h>
#include <dcmtk/dcmdata/dcdeftag.h>
#include <dcmtk/dcmdata/dcdict.h>
#include <dcmtk/dcmdata/dcdicent.h>

#ifdef MACRO_QUE_ESTORBA
#define verify MACRO_QUE_ESTORBA
#endif


void DIMSE_printNStatusString(std::ostream& dumpStream, int status)
{
  switch(status)
  {
    case STATUS_Success:
      dumpStream << "0x0000: Success";
      break;
    case STATUS_N_Cancel:
      dumpStream << "0xFE00: Cancel";
      break;
    case STATUS_N_AttributeListError:
      dumpStream << "0x0107: Attribute list error";
      break;
    case STATUS_N_SOPClassNotSupported:
      dumpStream << "0x0122: SOP class not supported";
      break;
    case STATUS_N_ClassInstanceConflict:
      dumpStream << "0x0119: Class/instance conflict";
      break;
    case STATUS_N_DuplicateSOPInstance:
      dumpStream << "0x0111: Duplicate SOP instance";
      break;
    case STATUS_N_DuplicateInvocation:
      dumpStream << "0x0210: Duplicate invocation";
      break;
    case STATUS_N_InvalidArgumentValue:
      dumpStream << "0x0115: Invalid argument value";
      break;
    case STATUS_N_InvalidAttributeValue:
      dumpStream << "0x0106: Invalid attribute value";
      break;
    case STATUS_N_InvalidObjectInstance:
      dumpStream << "0x0117: Invalid object instance";
      break;
    case STATUS_N_MissingAttribute:
      dumpStream << "0x0120: Missing attribute";
      break;
    case STATUS_N_MissingAttributeValue:
      dumpStream << "0x0121: Missing attribute value";
      break;
    case STATUS_N_MistypedArgument:
      dumpStream << "0x0212: Mistyped argument";
      break;
    case STATUS_N_NoSuchArgument:
      dumpStream << "0x0114: No such argument";
      break;
    case STATUS_N_NoSuchAttribute:
      dumpStream << "0x0105: No such attribute";
      break;
    case STATUS_N_NoSuchEventType:
      dumpStream << "0x0113: No such event type";
      break;
    case STATUS_N_NoSuchObjectInstance:
      dumpStream << "0x0112: No such object instance";
      break;
    case STATUS_N_NoSuchSOPClass:
      dumpStream << "0x0118: No such SOP class";
      break;
    case STATUS_N_ProcessingFailure:
      dumpStream << "0x0110: Processing failure";
      break;
    case STATUS_N_ResourceLimitation:
      dumpStream << "0x0213: Resource limitation";
      break;
    case STATUS_N_UnrecognizedOperation:
      dumpStream << "0x0211: Unrecognized operation";
      break;
    default:
      dumpStream << "0x" << STD_NAMESPACE hex << STD_NAMESPACE setfill('0') << STD_NAMESPACE setw(4)
          << status << ": Unknown Status Code";
      break;
  }
}

CustomAssociation::CustomAssociation(void* connectionKey, const std::string& ambitolog, GNC::IProxyNotificadorProgreso* pNotificadorProgreso) :
		Association(ambitolog), GIL::DICOM::ICustomAssociation()
{
	if (connectionKey == NULL) {
		LOG_ERROR(ambitolog, "NULL Connection key");
	}
	this->Net = GIL::DICOM::DCMTK::Network::Instance(connectionKey);
	this->m_pNotificadorProgreso = pNotificadorProgreso;
	this->ambitolog = ambitolog;
	this->blockMode = DIMSE_BLOCKING;
	this->eventHandler = NULL;
	this->presId = 0;
}

CustomAssociation::~CustomAssociation() {
	
}
bool CustomAssociation::Connect(const std::string& /*serverId*/, const std::string& /*local_aet*/)
{
	/*
	CONDITION status = DIMSE_NORMAL;
	
	//1. Open Association
	
	if (!Net->Initiallized()) {
		Net->InitializeNetwork(GetTimeout(), GetRole(), GetAcceptorPort());
	}
	
	Create(
			server->AET,
			server->HostName,
			server->Port,
			local_aet
	);
	
	SetNotificadorProgreso(m_pNotificadorProgreso);

	LOG_DEBUG(ambitolog, "Connecting: AET = " << server->AET << ", Host = " << server->HostName << ", Port = " << server->Port << ", Local AET = " << local_aet << ", PDU = " << server->PDU);
	CONDITION r = Association::Connect(Net, server->PDU);
	
	CONDITION c = ECC_Normal;
	
	//Uint16 rstatus;

	if (r.good() == true) {
		
		// 3. N-CREATE (UPS)
		
		DcmDataset* response;
		DcmDataset attrs;
		DcmElement* e = NULL;
		DcmSequenceOfItems* seq = NULL;
		DcmItem* item = NULL;
		
		e = newDicomElement(DCM_UnifiedProcedureStepState);
		e->putString("SCHEDULED");
		attrs.insert(e);

		e = newDicomElement(DCM_ScheduledProcedureStepPriority);
		e->putString("MEDIUM");
		attrs.insert(e);

		e = newDicomElement(DCM_WorklistLabel);
		e->putString("worklist test");
		attrs.insert(e);

		e = newDicomElement(DCM_ProcedureStepLabel);
		e->putString("test step");
		attrs.insert(e);

		e = newDicomElement(DCM_CommentsOnTheScheduledProcedureStep);
		e->putString("comentarios");
		attrs.insert(e);

		e = newDicomElement(DCM_ScheduledProcedureStepStartDateTime);
		e->putString("20120416114500");
		attrs.insert(e);

		e = newDicomElement(DCM_ExpectedCompletionDateTime);
		e->putString("20120416144000");
		attrs.insert(e);

		std::string strTmp;
		e = newDicomElement(DCM_StudyInstanceUID);
		if (parameters.getTag(GKDCM_StudyInstanceUID, strTmp)) {
			e->putString(strTmp.c_str());
		}
		attrs.insert(e);

		e = newDicomElement(DCM_PatientName);
		if (parameters.getTag(GKDCM_PatientName, strTmp)) {
			e->putString(strTmp.c_str());
		}
		attrs.insert(e);

		e = newDicomElement(DCM_PatientID);
		if (parameters.getTag(GKDCM_PatientID, strTmp)) {
			e->putString(strTmp.c_str());
		}
		attrs.insert(e);

		e = newDicomElement(DCM_AdmissionID);
		if (parameters.getTag(GKDCM_AdmissionID, strTmp)) {
			e->putString(strTmp.c_str());
		}
		attrs.insert(e);

		e = newDicomElement(DCM_TransactionUID);
		attrs.insert(e);

		OFString upsSopInstanceUID;
		c = createRQ(UID_UnifiedProcedureStepPushSOPClass, upsSopInstanceUID, &attrs, rstatus, response);



		DcmDataset actionInformation;
		e = newDicomElement(DCM_TransactionUID);

		e->putString("1.2.40.0.13.1.1.10.231.162.70.20100921082909711.32774.1");
		actionInformation.insert(e);

		e = newDicomElement(DCM_UnifiedProcedureStepState);
		e->putString("IN PROGRESS");
		actionInformation.insert(e);

		OFCondition resultStatus = actionRQ(UID_UnifiedProcedureStepPullSOPClass, upsSopInstanceUID.c_str(), 1, &actionInformation, rstatus, response);

		
		if (c.good()) {
		}
		else {
			return c;
		}
		return r;
	}
	else {
		LOG_ERROR(ambitolog, "Error al conectar:" << r.text());
		Drop();
		Destroy();
		throw GIL::DICOM::PACSException(r.text());
	}
	
	if (!c.good()) {
		LOG_ERROR(ambitolog, "Error al enviar objeto: " << c.text());
		Drop();
		Destroy();
		throw GIL::DICOM::PACSException(c.text());
	}
	
	return status;
	*/
	return false;
}

void CustomAssociation::OnAddPresentationContext(T_ASC_Parameters* params) {
	OFCondition cond = EC_Normal;
	
	const char* transferSyntaxes[3];
	int transferSyntaxCount = 0;
	
	/* gLocalByteOrder is defined in dcxfer.h */
	if (gLocalByteOrder == EBO_LittleEndian) {
		/* we are on a little endian machine */
		transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax;
		transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax;
	} else {
		/* we are on a big endian machine */
		transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax;
		transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
	}
	transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
	transferSyntaxCount = 3;
	
	if (cond.good()) cond = ASC_addPresentationContext(params, 1, UID_UnifiedProcedureStepPushSOPClass, transferSyntaxes, transferSyntaxCount);
	if (cond.good()) cond = ASC_addPresentationContext(params, 3, UID_UnifiedProcedureStepPullSOPClass, transferSyntaxes, transferSyntaxCount);
}

void CustomAssociation::dumpNMessage(T_DIMSE_Message &msg, DcmItem *dataset, OFBool outgoing)
{
    OFString str;
    if (outgoing) {
        DIMSE_dumpMessage(str, msg, DIMSE_OUTGOING, dataset);
    } else {
        DIMSE_dumpMessage(str, msg, DIMSE_INCOMING, dataset);
    }
    LOG_DEBUG(ambitolog, str);
}

OFCondition CustomAssociation::sendNRequest(
    T_ASC_PresentationContextID presId,
    T_DIMSE_Message &request,
    DcmDataset *rqDataSet,
    T_DIMSE_Message &response,
    DcmDataset* &statusDetail,
    DcmDataset* &rspDataset)
{
    OFCondition cond = EC_Normal;
    T_DIMSE_Command expectedResponse;
    DIC_US expectedMessageID=0;
    if (assoc == NULL)
    {
      return DIMSE_ILLEGALASSOCIATION;
    }

    T_DIMSE_DataSetType datasetType = DIMSE_DATASET_NULL;
    if (rqDataSet && (rqDataSet->card() > 0)) datasetType = DIMSE_DATASET_PRESENT;
    
    switch(request.CommandField)
    {
      case DIMSE_N_GET_RQ:
        request.msg.NGetRQ.DataSetType = datasetType;
        expectedResponse = DIMSE_N_GET_RSP;
        expectedMessageID = request.msg.NGetRQ.MessageID;
        break;
      case DIMSE_N_SET_RQ:
        request.msg.NSetRQ.DataSetType = datasetType;
        expectedResponse = DIMSE_N_SET_RSP;
        expectedMessageID = request.msg.NSetRQ.MessageID;
        break;
      case DIMSE_N_ACTION_RQ:
        request.msg.NActionRQ.DataSetType = datasetType;
        expectedResponse = DIMSE_N_ACTION_RSP;
        expectedMessageID = request.msg.NActionRQ.MessageID;
        break;
      case DIMSE_N_CREATE_RQ:
        request.msg.NCreateRQ.DataSetType = datasetType;
        expectedResponse = DIMSE_N_CREATE_RSP;
        expectedMessageID = request.msg.NCreateRQ.MessageID;
        break;
      case DIMSE_N_DELETE_RQ:
        request.msg.NDeleteRQ.DataSetType = datasetType;
        expectedResponse = DIMSE_N_DELETE_RSP;
        expectedMessageID = request.msg.NDeleteRQ.MessageID;
        break;
      default:
        return DIMSE_BADCOMMANDTYPE;
        /* break; */
    }

    dumpNMessage(request, rqDataSet, OFTrue);
    cond = DIMSE_sendMessageUsingMemoryData(assoc, presId, &request, NULL, rqDataSet, NULL, NULL);
    if (cond.bad()) return cond;

    T_ASC_PresentationContextID thisPresId;
    T_DIMSE_Message eventReportRsp;
    DIC_US eventReportStatus;
    do
    {
        thisPresId = presId;
        statusDetail = NULL;
        cond = DIMSE_receiveCommand(assoc, blockMode, this->m_timeout, &thisPresId, &response, &statusDetail);
        if (cond.bad()) return cond;

        if (response.CommandField == DIMSE_N_EVENT_REPORT_RQ)
        {
          /* handle N-EVENT-REPORT-RQ */
          rspDataset = NULL;
          if (response.msg.NEventReportRQ.DataSetType == DIMSE_DATASET_PRESENT)
          {
            cond = DIMSE_receiveDataSetInMemory(assoc, blockMode, m_timeout, &thisPresId, &rspDataset, NULL, NULL);
            if (cond.bad()) return cond;
          }  
          dumpNMessage(response, rspDataset, OFFalse);
          // call event handler if registered
          eventReportStatus = STATUS_Success;
          if (eventHandler) eventReportStatus = eventHandler->handleEvent(response.msg.NEventReportRQ, rspDataset, statusDetail);
          if (rspDataset) delete rspDataset;
          rspDataset = NULL;
          if (statusDetail) delete statusDetail;
          statusDetail = NULL;
          
          // send back N-EVENT-REPORT-RSP */
          eventReportRsp.CommandField = DIMSE_N_EVENT_REPORT_RSP;
          eventReportRsp.msg.NEventReportRSP.MessageIDBeingRespondedTo = response.msg.NEventReportRQ.MessageID;
          eventReportRsp.msg.NEventReportRSP.EventTypeID = response.msg.NEventReportRQ.EventTypeID;
          eventReportRsp.msg.NEventReportRSP.DimseStatus = eventReportStatus;
          eventReportRsp.msg.NEventReportRSP.DataSetType = DIMSE_DATASET_NULL;
          eventReportRsp.msg.NEventReportRSP.opts = O_NEVENTREPORT_EVENTTYPEID;
          eventReportRsp.msg.NEventReportRSP.AffectedSOPClassUID[0] = 0;
          eventReportRsp.msg.NEventReportRSP.AffectedSOPInstanceUID[0] = 0;
          dumpNMessage(eventReportRsp, NULL, OFTrue);
          cond = DIMSE_sendMessageUsingMemoryData(assoc, thisPresId, &eventReportRsp, NULL, NULL, NULL, NULL);
          if (cond.bad()) return cond;
        } else {
          /* No N-EVENT-REPORT-RQ. Check if this message is what we expected */
          if (response.CommandField != expectedResponse)
          {
            char buf1[256];
            sprintf(buf1, "DIMSE: Unexpected Response Command Field: 0x%x", (unsigned)response.CommandField);
            return makeDcmnetCondition(DIMSEC_UNEXPECTEDRESPONSE, OF_error, buf1);
          }
          T_DIMSE_DataSetType responseDataset = DIMSE_DATASET_NULL;
          DIC_US responseMessageID = 0;
          /** change request to response */     
          switch(expectedResponse)
          {
            case DIMSE_N_GET_RSP:
              responseDataset = response.msg.NGetRSP.DataSetType;
              responseMessageID = response.msg.NGetRSP.MessageIDBeingRespondedTo;
              break;
            case DIMSE_N_SET_RSP:
              responseDataset = response.msg.NSetRSP.DataSetType;
              responseMessageID = response.msg.NSetRSP.MessageIDBeingRespondedTo;
              break;
            case DIMSE_N_ACTION_RSP:
              responseDataset = response.msg.NActionRSP.DataSetType;
              responseMessageID = response.msg.NActionRSP.MessageIDBeingRespondedTo;
              break;
            case DIMSE_N_CREATE_RSP:
              responseDataset = response.msg.NCreateRSP.DataSetType;
              responseMessageID = response.msg.NCreateRSP.MessageIDBeingRespondedTo;
              break;
            case DIMSE_N_DELETE_RSP:
              responseDataset = response.msg.NDeleteRSP.DataSetType;
              responseMessageID = response.msg.NDeleteRSP.MessageIDBeingRespondedTo;
              break;
            default:
              {
                char buf1[256];
                sprintf(buf1, "DIMSE: Unexpected Response Command Field: 0x%x", (unsigned)response.CommandField);
                return makeDcmnetCondition(DIMSEC_UNEXPECTEDRESPONSE, OF_error, buf1);
              }
              /* break; */
          }
          if (responseMessageID != expectedMessageID)
          {
            char buf1[256];
            sprintf(buf1, "DIMSE: Unexpected Response Command Field: 0x%x", (unsigned)response.CommandField);
            return makeDcmnetCondition(DIMSEC_UNEXPECTEDRESPONSE, OF_error, buf1);
          }
          rspDataset = NULL;
          if (responseDataset == DIMSE_DATASET_PRESENT)
          {
            cond = DIMSE_receiveDataSetInMemory(assoc, blockMode, m_timeout, &thisPresId, &rspDataset, NULL, NULL);
            if (cond.bad()) return cond;
          }
          dumpNMessage(response, rspDataset, OFFalse);
        }
    } while (response.CommandField == DIMSE_N_EVENT_REPORT_RQ);
    return EC_Normal;
}    

bool CustomAssociation::createRQ( const std::string& /*sopclassUID*/, const std::string& /*sopinstanceUID*/, const GIL::DICOM::DicomDataset& /*attributeListIn*/,  int& /*status*/, GNC::GCS::Ptr<GIL::DICOM::DicomDataset>& /*attributeListOut*/)
/*
OFCondition CustomAssociation::createRQ(
    const char *sopclassUID, 
    OFString& sopinstanceUID, 
    DcmDataset *attributeListIn, 
    Uint16& status, 
    DcmDataset* &attributeListOut)
*/
{
	/*
  if (assoc == NULL)
  {
    return DIMSE_ILLEGALASSOCIATION;
  }
  if (sopclassUID==NULL)
  {
    return DIMSE_NULLKEY;
  }

  T_ASC_PresentationContextID presCtx = findAcceptedPC(sopclassUID);
  if (presCtx == 0)
  {
    return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
  }  

  T_DIMSE_Message request;
  T_DIMSE_Message response;
  DcmDataset *statusDetail = NULL;

  // construct N-CREATE-RQ
  request.CommandField = DIMSE_N_CREATE_RQ;
  request.msg.NCreateRQ.MessageID = assoc->nextMsgID++;
  strcpy(request.msg.NCreateRQ.AffectedSOPClassUID, sopclassUID);
  if (sopinstanceUID.size() > 0)
  {
    strcpy(request.msg.NCreateRQ.AffectedSOPInstanceUID, sopinstanceUID.c_str());
    request.msg.NCreateRQ.opts = O_NCREATE_AFFECTEDSOPINSTANCEUID;
  } else {
    request.msg.NCreateRQ.AffectedSOPInstanceUID[0] = 0;
    request.msg.NCreateRQ.opts = 0;
  }
  
  OFCondition cond = sendNRequest(presCtx, request, attributeListIn, response, statusDetail, attributeListOut);
  if (statusDetail) delete statusDetail;
  if (cond.good()) 
  {
    status = response.msg.NCreateRSP.DimseStatus;
	 if (status != 0) {
		 LOG_ERROR(ambitolog, "Error sending create rq status: "<< status);
		 std::ostringstream ostr;
		 ostr << "Error sending create rq status: "<< status << " details: ";
		 DIMSE_printNStatusString(ostr, status);
		 throw GIL::DICOM::PACSException(ostr.str(), "GIL::CustomAssociation");
	 }
    // if response contains SOP Instance UID, copy it.
    if (response.msg.NCreateRSP.opts & O_NCREATE_AFFECTEDSOPINSTANCEUID)
    {
      sopinstanceUID = response.msg.NCreateRSP.AffectedSOPInstanceUID;
    }
  }
  return cond;
  */
	return false;
}




bool CustomAssociation::setRQ( const std::string& /*sopclassUID*/, const std::string& /*sopinstanceUID*/, const GIL::DICOM::DicomDataset& /*modificationList*/, int& /*status*/, GNC::GCS::Ptr<GIL::DICOM::DicomDataset>& /*attributeListOut*/)
/*
OFCondition CustomAssociation::setRQ(
    const char *sopclassUID, 
    const char *sopinstanceUID, 
    DcmDataset *modificationList, 
    Uint16& status, 
    DcmDataset* &attributeListOut)
*/
{
	/*
  if (assoc == NULL)
  {
    return DIMSE_ILLEGALASSOCIATION;
  }
  if ((sopclassUID==NULL)||(sopinstanceUID==NULL)||(modificationList==NULL))
  {
    return DIMSE_NULLKEY;
  }

  T_ASC_PresentationContextID presCtx = findAcceptedPC(sopclassUID);
  if (presCtx == 0)
  {
    return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
  }  

  T_DIMSE_Message request;
  T_DIMSE_Message response;
  DcmDataset *statusDetail = NULL;

  // construct N-SET-RQ
  request.CommandField = DIMSE_N_SET_RQ;
  request.msg.NSetRQ.MessageID = assoc->nextMsgID++;
  strcpy(request.msg.NSetRQ.RequestedSOPClassUID, sopclassUID);
  strcpy(request.msg.NSetRQ.RequestedSOPInstanceUID, sopinstanceUID);
   
  OFCondition cond = sendNRequest(presCtx, request, modificationList, response, statusDetail, attributeListOut);
  if (cond.good()) status = response.msg.NSetRSP.DimseStatus;
  if (status != 0) {
		 LOG_ERROR(ambitolog, "Error sending create rq status: "<< status);
		 std::ostringstream ostr;
		 ostr << "Error sending create rq status: "<< status << " details: ";
		 DIMSE_printNStatusString(ostr, status);
		 throw GIL::DICOM::PACSException(ostr.str(), "GIL::CustomAssociation");
  }
  if (statusDetail) delete statusDetail;
  return cond;   
  */
	return false;
}

bool CustomAssociation::getRQ( const std::string& /*sopclassUID*/, const std::string& /*sopinstanceUID*/, const int* /*attributeIdentifierList*/, unsigned long /*numShorts*/, int& /*status*/,  GNC::GCS::Ptr<GIL::DICOM::DicomDataset>& /*attributeListOut*/)
/*
OFCondition CustomAssociation::getRQ(
    const char *sopclassUID, 
    const char *sopinstanceUID, 
    const Uint16 *attributeIdentifierList,
    ssize_t numShorts,
    Uint16& status, 
    DcmDataset* &attributeListOut)
*/
{
	/*
  if (assoc == NULL)
  {
    return DIMSE_ILLEGALASSOCIATION;
  }
  if ((sopclassUID==NULL)||(sopinstanceUID==NULL))
  {
    return DIMSE_NULLKEY;
  }

  T_ASC_PresentationContextID presCtx = findAcceptedPC(sopclassUID);
  if (presCtx == 0)
  {
    return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
  }  

  T_DIMSE_Message request;
  T_DIMSE_Message response;
  DcmDataset *statusDetail = NULL;

  // construct N-GET-RQ
  request.CommandField = DIMSE_N_GET_RQ;
  request.msg.NGetRQ.MessageID = assoc->nextMsgID++;
  strcpy(request.msg.NGetRQ.RequestedSOPClassUID, sopclassUID);
  strcpy(request.msg.NGetRQ.RequestedSOPInstanceUID, sopinstanceUID);
  request.msg.NGetRQ.ListCount = 0;
  if (attributeIdentifierList) request.msg.NGetRQ.ListCount = (int)numShorts;
  request.msg.NGetRQ.AttributeIdentifierList = (DIC_US *)attributeIdentifierList;
   
  OFCondition cond = sendNRequest(presCtx, request, NULL, response, statusDetail, attributeListOut);
  if (cond.good()) status = response.msg.NGetRSP.DimseStatus;
  if (status != 0) {
	 LOG_ERROR(ambitolog, "Error sending create rq status: "<< status);
	 std::ostringstream ostr;
	 ostr << "Error sending create rq status: "<< status << " details: ";
	 DIMSE_printNStatusString(ostr, status);
	 throw GIL::DICOM::PACSException(ostr.str(), "GIL::CustomAssociation");
  }
  if (statusDetail) delete statusDetail;
  return cond;   
  */
	return false;
}

bool CustomAssociation::actionRQ( const std::string& /*sopclassUID*/, const std::string& /*sopinstanceUID*/, int /*actionTypeID*/, const GIL::DICOM::DicomDataset& /*actionInformation*/, int& /*status*/,  GNC::GCS::Ptr<GIL::DICOM::DicomDataset>& /*attributeListOut*/)
/*
OFCondition CustomAssociation::actionRQ(
    const char *sopclassUID, 
    const char *sopinstanceUID, 
    Uint16 actionTypeID, 
    DcmDataset *actionInformation,
    Uint16& status, 
    DcmDataset* &actionReply)
	*/
{
	/*
  if (assoc == NULL)
  {
    return DIMSE_ILLEGALASSOCIATION;
  }
  if ((sopclassUID==NULL)||(sopinstanceUID==NULL))
  {
    return DIMSE_NULLKEY;
  }

  T_ASC_PresentationContextID presCtx = findAcceptedPC(sopclassUID);
  if (presCtx == 0)
  {
    return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
  }  

  T_DIMSE_Message request;
  T_DIMSE_Message response;
  DcmDataset *statusDetail = NULL;

  // construct N-ACTION-RQ
  request.CommandField = DIMSE_N_ACTION_RQ;
  request.msg.NActionRQ.MessageID = assoc->nextMsgID++;
  strcpy(request.msg.NActionRQ.RequestedSOPClassUID, sopclassUID);
  strcpy(request.msg.NActionRQ.RequestedSOPInstanceUID, sopinstanceUID);
  request.msg.NActionRQ.ActionTypeID = (DIC_US)actionTypeID;
   ////////TODO: ESTÁ FALLANDO
  OFCondition cond = sendNRequest(presCtx, request, actionInformation, response, statusDetail, actionReply);
  if (cond.good()) status = response.msg.NActionRSP.DimseStatus;
  if (status != 0) {
		LOG_ERROR(ambitolog, "Error sending create rq status: "<< status);
		std::ostringstream ostr;
		ostr << "Error sending create rq status: "<< status << " details: ";
		DIMSE_printNStatusString(ostr, status);
		throw GIL::DICOM::PACSException(ostr.str(), "GIL::CustomAssociation");
  }
  if (statusDetail) delete statusDetail;
  return cond;   
  */
	 return false;
}

bool CustomAssociation::deleteRQ( const std::string& /*sopclassUID*/, const std::string& /*sopinstanceUID*/, int& /*status*/)
/*
OFCondition CustomAssociation::deleteRQ(
    const char *sopclassUID, 
    const char *sopinstanceUID, 
    Uint16& status)
	*/
{
	/*
  if (assoc == NULL)
  {
    return DIMSE_ILLEGALASSOCIATION;
  }
  if ((sopclassUID==NULL)||(sopinstanceUID==NULL))
  {
    return DIMSE_NULLKEY;
  }

  T_ASC_PresentationContextID presCtx = findAcceptedPC(sopclassUID);
  if (presCtx == 0)
  {
    return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
  }  

  T_DIMSE_Message request;
  T_DIMSE_Message response;
  DcmDataset *statusDetail = NULL;
  DcmDataset *attributeListOut = NULL;

  // construct N-DELETE-RQ
  request.CommandField = DIMSE_N_DELETE_RQ;
  request.msg.NDeleteRQ.MessageID = assoc->nextMsgID++;
  strcpy(request.msg.NDeleteRQ.RequestedSOPClassUID, sopclassUID);
  strcpy(request.msg.NDeleteRQ.RequestedSOPInstanceUID, sopinstanceUID);
   
  OFCondition cond = sendNRequest(presCtx, request, NULL, response, statusDetail, attributeListOut);
  if (cond.good()) status = response.msg.NDeleteRSP.DimseStatus;
  if (status != 0) {
	 LOG_ERROR(ambitolog, "Error sending create rq status: "<< status);
	 std::ostringstream ostr;
	 ostr << "Error sending create rq status: "<< status << " details: ";
	 DIMSE_printNStatusString(ostr, status);
	 throw GIL::DICOM::PACSException(ostr.str(), "GIL::CustomAssociation");
  }
  if (statusDetail) delete statusDetail;
  if (attributeListOut) delete attributeListOut;  // should never happen
  return cond;   
  */
	return false;
}

bool CustomAssociation::releaseAssociation() 
/*
OFCondition CustomAssociation::releaseAssociation()
*/
{
	/*
  OFCondition result = EC_Normal;
  if (assoc)
  {
    result = ASC_releaseAssociation(assoc);
	 Drop();
	 Destroy();
    assoc = NULL;
  }
  return result;
  */
	return false;
}

bool CustomAssociation::abortAssociation()
/*
OFCondition CustomAssociation::abortAssociation()
*/
{
/*	
  OFCondition result = EC_Normal;
  if (assoc)
  {
    result = ASC_abortAssociation(assoc);
	 Drop();
	 Destroy();
	 assoc =  NULL;
  }
  return result;
  */
	return false;
}

T_ASC_PresentationContextID CustomAssociation::findAcceptedPC(const char *sopclassuid)
{
	/*
  if ((assoc==NULL)||(sopclassuid==NULL)) return 0;

  // if the SOP class is one of the Basic Grayscale Print Management Meta SOP Classes,
  // look for a presentation context for Basic Grayscale Print.
  OFString sopclass(sopclassuid);
  if ((sopclass == UID_BasicFilmSessionSOPClass) ||
      (sopclass == UID_BasicFilmBoxSOPClass) ||
      (sopclass == UID_BasicGrayscaleImageBoxSOPClass) ||
      (sopclass == UID_PrinterSOPClass)) sopclassuid = UID_BasicGrayscalePrintManagementMetaSOPClass;
	  */
	OFString sopclass(sopclassuid);
  return ASC_findAcceptedPresentationContextID(assoc, sopclassuid);
}


void CustomAssociation::Gnk2Dcmtk(const GIL::DICOM::DicomDataset& /*base*/, DcmDataset* /*query*/)
{
	/*
	OFCondition cond;
	typedef GIL::DICOM::DicomDataset TJerarquia;
	typedef GIL::DICOM::ListaTags TListaTags;
	
	for (TListaTags::const_iterator it = base.tags.begin(); it != base.tags.end(); ++it) {
		//DcmElement* e = GIL::DICOM::DICOMManager::CrearElementoConValor((*it).first.c_str());
		
		if (e != NULL) {
			const std::string& val = (*it).second;
			if (val.size() > 0) {
				e->putString( (*it).second.c_str() );
			}					
			
			cond = query->insert(e, true, false);

			if (cond.bad()) {
				LOG_ERROR("PACSCONTROLLER", "No se pudo insertar el elemento: (" << e->getTag().toString().c_str() << "): " << cond.text());
			}
		}

		for (TJerarquia::DatasetList::const_iterator it2 = base.secuencias.begin(); it2 != base.secuencias.end(); it2++) {
			const TJerarquia& seq = (*it2);
			//DcmElement* es = GIL::DICOM::DICOMManager::CrearElementoConValor(seq.tagName.c_str());			

			for (TJerarquia::DatasetList::const_iterator it3 = seq.items.begin(); it3 != seq.items.end(); it3++) {
				const TJerarquia& item = (*it3);
				DcmItem* di = new DcmItem();

				for (TListaTags::const_iterator it4 = item.tags.begin(); it4 != item.tags.end(); it4++) {
					//DcmElement* ei = GIL::DICOM::DICOMManager::CrearElementoConValor((*it4).first.c_str());
					if (ei != NULL) {
						const std::string& val = (*it4).second;
						if (val.size() > 0) {
							ei->putString( (*it4).second.c_str() );
						}					
						cond = di->insert(ei, true, false);

						if (cond.bad()) {
							LOG_ERROR("PACSCONTROLLER", "No se pudo insertar el elemento: (" << ei->getTag().toString().c_str() << "): " << cond.text());
						}
					}

				}

				query->insertSequenceItem(es->getTag(), di);
			}					
		}
	}
	*/
}




