#include <errno.h>
#include <malloc.h>
#include <sys/socket.h>
#include <rpc/xdr.h>
#include "StatePacketSender.h"
#include "ourTypes.h"
#include "Syslog.h"

StatePacketSender::StatePacketSender() {

  Boolean debug = False;
  dprintf("StatePacketSender constructor\n");
  // Allocate XDR state buffer - allocate lots of extra
  unsigned int outBufSize = 2 * sizeof(StatePacket);

  _outBuf = (char *)malloc(outBufSize);

  // First three bytes of outBuf hold message type and XDR buf size; 
  // remainder stores state in XDR format
  _xdrStateBuf = &_outBuf[3];

  dprintf("_outBuf: 0x%0lx, _xdrStateBuf: 0x%0lx, outBufSize=%d\n", 
	  &_outBuf[0], &_xdrStateBuf[0], outBufSize);


  xdrmem_create(&_xdrStream, _xdrStateBuf, outBufSize-3, XDR_ENCODE); 

  dprintf("TEST xdr_setpos()\n");
  if (!xdr_setpos(&_xdrStream, 0)) {
    Syslog::write("StatePacketSender ctr: xdr_setpos() failed!");
  }
  else {
    dprintf("xdr_setpos() OK\n");
  }
}





StatePacketSender::~StatePacketSender() {
  free(_outBuf);
}

int StatePacketSender::sendHeader(char type, int socket, 
				  struct sockaddr_in &addr) {
  if( ::sendto(socket, &type, 1, 0, (struct sockaddr *)&addr,
	       sizeof(addr))<0 ) {
    Syslog::write("StatePacketSender ERROR: %s\n", strerror(errno));
    return -1;
  }
  return 0;
}


int StatePacketSender::send(int32_t id, char type, int socket, 
			    struct sockaddr_in &addr) {
  uint32_t *tmp = (uint32_t *)&id;
  uint32_t net = htonl(*tmp); // encode the id for neetwork
  char msg[6]; // message length is 5+1 
  int ret;
//   if( sendHeader(LcMsgHeader, socket, addr)<0 )
// 	return -1;
  msg[0] = LcMsgHeader;
  msg[1] = type;
  memcpy(msg+2, &net, 4 /*sizeof(uint32_t)*/);
  if( ::sendto(socket, msg, 6, 0,
	       (struct sockaddr *)&addr, sizeof(addr)) <0 ) {
    Syslog::write("StatePacketSender ERROR: failed to send message !");
    return -1;
  }
  return 0;
}


int StatePacketSender::send(StatePacket *statePacket, int socket,
			    struct sockaddr_in &servAddr) {

  Boolean debug = FALSE;

  char errorBuf[100];

  dprintf("xdr_setpos()\n");
  if (!xdr_setpos(&_xdrStream, 0)) {
    Syslog::write("StatePacketSender ERROR: xdr_setpos() failed!");
    return -1;
  }

  // Encode state packet to XDR and send it over the socket
  dprintf("OK, encode state packet to XDR\n");
  if (xdr_StatePacket(&_xdrStream, statePacket)) {
    dprintf("sending data through socket\n");

    // Compute total size of outgoing XDR data record
    short nXdrBytes = xdr_getpos(&_xdrStream);

    // Convert size to network-order
    uint16_t val = htons(nXdrBytes);
    char *valBuf = (char *)&val;
    // First byte idenitfies thde message
    _outBuf[0] = SpMsgHeader;
    // First two bytes of outBuf contain XDR byte count (network order)
    _outBuf[1] = valBuf[0];
    _outBuf[2] = valBuf[1];
    dprintf("nXdrBytes=%d, htons=%d (0x%hx, 0x%hx)", 
	    nXdrBytes, val, valBuf[0], valBuf[1]);

    int n;
  //   if( sendHeader(SpMsgHeader, socket, servAddr)<0 )
//       return -1;
  
    // Write data, first 2 bytes (holding XDR byte count) followed by 
    // XDR record
    if( (n = ::sendto(socket, _outBuf, nXdrBytes+3, 0,
		      (struct sockaddr*)&servAddr, sizeof(servAddr)))<0 ) {
      sprintf(errorBuf, "StatePacketSender: send() failed: %s", 
	      strerror(errno));
      Syslog::write("%s", errorBuf);
      return -1;
    } else {
      dprintf("sent %d bytes to AMC\n", n);
    }
  }
  else {
    Syslog::write("xdr_StatePacket() failed\n");
    return -1;
  }
  return 0;
}
