/*
 * responses.c,v 1.3 1994/01/30 17:10:42 franktor Exp
 */

#include <sys/time.h>
#include <sys/resource.h>
#include "client.h"
#include <high/structcodec.h>	/* want send_struct() */
#include <malloc.h>
#include <sr-util.h>

/*
 * setupResponseHandler (int ref, Client **client, ServerConnection **conn,
 *		         const char *response_name)
 *
 * Common function when handling packets from the SR server.
 * It figures out which client the packet is for, and on which connection
 * it arrived, returning it in the 2. and 3. argument respectively.
 */

Boolean
setupResponseHandler (int ref, Client **client, ServerConnection **conn,
		      const char *response_name)
{
  LOG(facHigh, llevTrace, "%s(%d)", response_name, ref);

  *client = find_client_from_SR_ref(ref);
  if (! *client)
  {
    LOG(facHigh, llevExceptions, "Got %s with unknown ref.", response_name);
    return False;
  }
  *conn = find_connection_from_SR_ref(*client, ref);
  if (*conn == (ServerConnection *) NULL)
  {
    LOG(facHigh, llevExceptions, "Internal error in %s.", response_name);
    return False;
  }
  return True;
}

/*
 * void handleInitialiseResponse(int ref)
 *
 * Reads an InitialiseResponse from the SR server and sends
 * appropriate hcOpenResponse to the correct client.
 */

void
handleInitialiseResponse(int ref)
{
  Client			*client;
  ServerConnection		*conn;
  HC_Packet			*resp;
  SRInitialiseResponse		*sr_resp;

  if (!setupResponseHandler (ref, &client, &conn, "handleInitialiseResponse"))
    return;
  conn->last_packet = hcNone;
  sr_resp = SR_ReadInitialiseResponse(ref);
  if (sr_resp == NULL)
    LOG(facHigh, llevExceptions, "Failed to decode initialise response.");
    /* Do something more here, like aborting connection */
  else
    LOG(facHigh, llevTrace, "Decoded SRInitialiseReponse.");

  resp = (HC_Packet *) malloc(sizeof(HC_Packet));
  resp->type = hcOpenResponse;
  resp->ref = conn->client_ref;
  resp->u.open_response = (HC_OpenResponse *) malloc(sizeof(HC_OpenResponse));
  resp->u.open_response->openAccepted		= True;
  resp->u.open_response->message		= (char *) NULL;
  resp->u.open_response->preferredMessageSize	= sr_resp->preferredMessageSize;
  resp->u.open_response->maximumMessageSize	= sr_resp->maximumMessageSize;
  resp->u.open_response->initialisationStatus	= sr_resp->initializationStatus; /* s->z ??? */
  if (sr_resp->implementationId)
    resp->u.open_response->implementationId	= strdup(sr_resp->implementationId);
  else
    resp->u.open_response->implementationId	= (char *) NULL;
  if (sr_resp->implementationName)
    resp->u.open_response->implementationName	= strdup(sr_resp->implementationName);
  else
    resp->u.open_response->implementationName	= (char *) NULL;
  if (sr_resp->implementationVersion)
    resp->u.open_response->implementationVersion = strdup(sr_resp->implementationVersion);
  else
    resp->u.open_response->implementationVersion = (char *) NULL;
  if (sr_resp->userInformationField)
  {
    /* Copy the EXTERN into resp->u.open_response->userInformationField if possible */
  } /* Then add an else here */
  resp->u.open_response->userInformationField	= (char *) NULL;

  send_struct(client->fd, (void *) resp, &client->selectOnWrite);
}

/*
 * void handleCloseResponse(int ref)
 * 
 * Reads CloseResponse from the SR server, and sends appropriate
 * hcCloseResponse to the client.
 */

void
handleCloseResponse(int ref)
{
  Client			*client;
  ServerConnection		*conn;
  HC_Packet			*resp;
  SRCloseResponse		*sr_resp;

  if (!setupResponseHandler (ref, &client, &conn, "handleCloseResponse"))
    return;
  conn->last_packet = hcNone;
  sr_resp = SR_ReadCloseResponse(ref);
  if (sr_resp == NULL)
  {
    LOG(facHigh, llevExceptions, "Failed to decode close response.");
    /* Do something more here, like aborting connection */
  }
  else
    LOG(facHigh, llevTrace, "Decoded SRCloseReponse.");

  resp = (HC_Packet *) malloc(sizeof(HC_Packet));
  resp->type = hcCloseResponse;
  resp->ref = conn->client_ref;
  resp->u.close_response = (HC_CloseResponse *) malloc(sizeof(HC_CloseResponse));
  resp->u.close_response->closeAccepted	= sr_resp->closeAccepted ? True : False;

  LOG(facHigh, llevDebug, "Close was %saccepted by server.", (sr_resp->closeAccepted == True) ? "" : "not");

  /* Maybe this will be something else at ie an abort */
  resp->u.close_response->message	= (sr_resp->closeAccepted
				   ? strdup("Connection closed successfully")
				   : strdup("Close was not accepted"));

  send_struct(client->fd, (void *) resp, &client->selectOnWrite);
  LOG(facHigh, llevTrace, "Sent hcCloseResponse to client.");
}

/*
 * void handleSearchResponse(int ref)
 *
 * Reads SearchResponse from SR server, and sends appropriate hcSearchResponse
 * to the client.
 */
 
void
handleSearchResponse(int ref)
{
  Client			*client;
  ServerConnection		*conn;
  HC_Packet			*resp;
  SRSearchResponse		*sr_resp;

  if (!setupResponseHandler (ref, &client, &conn, "handleSearchResponse"))
    return;
  conn->last_packet = hcNone;
  sr_resp = SR_ReadSearchResponse(ref);
  if (sr_resp == NULL)
    LOG(facHigh, llevExceptions, "Failed to decode initialise response.");
    /* Do something more here, like aborting connection */
  else
    LOG(facHigh, llevTrace, "Decoded SRSearchReponse.");

  resp = (HC_Packet *) malloc(sizeof(HC_Packet));
  resp->type = hcSearchResponse;
  resp->ref = conn->client_ref;
  resp->u.search_response = (HC_SearchResponse *) malloc(sizeof(HC_SearchResponse ));
  resp->u.search_response->numberOfRecordsFound	= sr_resp->numberOfRecordsFound;
  resp->u.search_response->numberOfRecordsReturned	= sr_resp->numberOfRecordsReturned;
  resp->u.search_response->nextResultSetPosition	= sr_resp->nextResultSetPosition;
  resp->u.search_response->searchStatus		= sr_resp->searchStatus;
  resp->u.search_response->resultSetStatus		= sr_resp->resultSetStatus;
  resp->u.search_response->presentStatus		= sr_resp->presentStatus;
  resp->u.search_response->records			= ConvertToHlvlRecords (sr_resp->records);

  send_struct(client->fd, (void *) resp, &client->selectOnWrite);
}

/*
 * void handlePresentResponse(int ref)
 *
 * Reads PresentResponse from the SR server and sends appropriate
 * hcPresentResponse to the client.
 */

void
handlePresentResponse(int ref)
{
  Client			*client;
  ServerConnection		*conn;
  HC_Packet			*resp;
  SRPresentResponse		*sr_resp;

  if (!setupResponseHandler (ref, &client, &conn, "handlePresentResponse"))
    return;
  conn->last_packet = hcNone;
  sr_resp = SR_ReadPresentResponse(ref);
  if (sr_resp == NULL)
    LOG(facHigh, llevExceptions, "Failed to decode initialise response.");
    /* Do something more here, like aborting connection */
  else
    LOG(facHigh, llevTrace, "Decoded SRPresentReponse.");

  resp = (HC_Packet *) malloc(sizeof(HC_Packet));
  resp->type = hcPresentResponse;
  resp->ref = conn->client_ref;
  resp->u.present_response = (HC_PresentResponse *) malloc(sizeof(HC_PresentResponse));
  resp->u.present_response->numberOfRecordsReturned	= sr_resp->numberOfRecordsReturned;
  resp->u.present_response->nextResultSetPosition	= sr_resp->nextResultSetPosition;
  LOG(facHigh, llevDebug, "Present status: %d\n", sr_resp->presentStatus);
  resp->u.present_response->presentStatus		= sr_resp->presentStatus;
  resp->u.present_response->records			= ConvertToHlvlRecords (sr_resp->records);

  send_struct(client->fd, (void *) resp, &client->selectOnWrite);
}

/*
 * void handleDeleteResultSetResponse(int ref)
 *
 * Reads DeleteResultSetResponse from SR server and sends appropriate
 * hcDeleteResultSetResponse to client.
 */

void handleDeleteResultSetResponse(int ref)
{
  Client			*client;
  ServerConnection		*conn;
  HC_Packet			*resp;
  SRDeleteResultSetResponse	*sr_resp;

  if (!setupResponseHandler (ref, &client, &conn, "handleDeleteResultSetResponse"))
    return;
  conn->last_packet = hcNone;
  sr_resp = SR_ReadDeleteResultSetResponse(ref);
  if (sr_resp == NULL)
    LOG(facHigh, llevExceptions, "Failed to decode initialise response.");
    /* Do something more here, like aborting connection */
  else
    LOG(facHigh, llevTrace, "Decoded SRDeleteResultSetReponse.");

  resp = (HC_Packet *) malloc(sizeof(HC_Packet));
  resp->type = hcDeleteResultSetResponse;
  resp->ref = conn->client_ref;
  resp->u.delete_result_set_response = (HC_DeleteResultSetResponse *) malloc(sizeof(HC_DeleteResultSetResponse ));
  resp->u.delete_result_set_response->status =
    (sr_resp->deleteOperationStatus == deleteSetStatus_success ? True : False);

  send_struct(client->fd, (void *) resp, &client->selectOnWrite);
}

/*
 * void handleAbortResponse (int ref)
 *
 * Acts upon abort from SR server, closing said connection to
 * correct client.
 */

void handleAbortResponse (int ref)
{
  Client			*client;
  ServerConnection		*conn;

  if (!setupResponseHandler (ref, &client, &conn, "handleAbortResponse"))
    return;

  SR_AbortAssociation (ref);

  abortServerConnection(client, conn);
}
