/********************************************************
 * client.c
 *
 * This module implements the routines for both client.h
 * and oracle.h, handling all of the communication between
 * the algorithm and the data set oracle.
 *
 * Sixth Annual DIMACS Implementation Challenge
 * Author:  Michael Goldwasser (wass@cs.princeton.edu)
 * Created: Jan 16, 1998
 *******************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "client.h"
#include "oracle.h"
#include "messages.h"



/********************************************************
 *
 * Client Socket routines
 *
 *******************************************************/

typedef struct CSocket {
  int  sock;
  struct sockaddr_in serv_addr;
  struct sockaddr_in cli_addr;
} CSocket;





Oracle* OracleConnect(
  char*   host,
  int     port
)
{
  CSocket* cs;
  struct hostent *hp;
  struct sockaddr_in name;

  cs = (CSocket *) malloc(sizeof(CSocket));


  /* Grab an Internet domain socket */
  cs->sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (cs->sock<0) {
    perror("opening datagram socket");
    exit(1);
  }


  /* Construct a name */
  hp = gethostbyname(host);
  if (hp==0) {
    fprintf(stderr,"%s:unknown host",host);
    exit(2);
  }


  /* fill in the socket structure with host information */
  bcopy(hp->h_addr,&cs->serv_addr.sin_addr,hp->h_length);
  cs->serv_addr.sin_family = AF_INET;
  cs->serv_addr.sin_port = htons(port);


  if (0) {
  /* fill in the socket structure with our information */
  name.sin_family = AF_INET;
  name.sin_addr.s_addr = INADDR_ANY;
  name.sin_port = htons(port);


  /* bind the socket to the port number */
  if (bind(cs->sock, (struct sockaddr *) &name, sizeof(&name)) == -1) {
    perror("Binding datagram socket for client");
    exit(1);
  }
  }

  return((Oracle *) cs);
}



void OracleClose(
  Oracle* c
)
{
  CSocket*   cs;

  cs = (CSocket*) c;
  close(cs->sock);
}




char* OracleQuery(
  Oracle* c,
  char*   message
)
{
  CSocket*   cs;
  char   answer[MAX_MSIZE];
  char*  ans;
  int    recvlen;

  cs = (CSocket*) c;


  /* send a message to the server PORT on machine HOST */
  if (sendto(cs->sock, message, strlen(message), 0,
	     (struct sockaddr *) &cs->serv_addr,
	     sizeof(cs->serv_addr)) == -1) {
    perror("sending datagram message");
    exit(1);
  }
 
  /* wait for a message to come back from the server */
  recvlen = recvfrom(cs->sock, answer, MAX_MSIZE, 0, 0,0);
  if (recvlen == -1) {
    perror("recv");
    exit(1);
  }
  answer[recvlen]=0;
 
  ans = strdup(answer);
  return(ans);
}





/********************************************************
 *
 * Query routines
 *
 *******************************************************/
 
int  InqNumPoints(
  Oracle  *c
)
{
  char      buf[MAX_MSIZE];
  char*     ans;
  int       result;


  sprintf(buf,"%s",Protocol_NumPoints);
  ans = OracleQuery(c,buf);
  sscanf(ans,"%d",&result);
  free(ans);

  return(result);
}



 
int  InqNumQuery(
  Oracle  *c
)
{
  char      buf[MAX_MSIZE];
  char*     ans;
  int       result;


  sprintf(buf,"%s",Protocol_NumQuery);
  ans = OracleQuery(c,buf);
  sscanf(ans,"%d",&result);
  free(ans);

  return(result);
}

 


double InqDist(
  Oracle  *c,
  int p1,
  int p2
)
{
  char      buf[MAX_MSIZE];
  char*     ans;
  double    result;


  sprintf(buf,"%s %d %d",Protocol_Dist,p1,p2);
  ans = OracleQuery(c,buf);

  sscanf(ans,"%lf",&result);
  free(ans);

  return(result);
}



int InqNumFields(
  Oracle  *c,
  int p
)
{
  char      buf[MAX_MSIZE];
  char*     ans;
  int       result;

  sprintf(buf,"%s %d",Protocol_NumFields,p);
  ans = OracleQuery(c,buf);

  sscanf(ans,"%d",&result);
  free(ans);

  return(result);
}


char*  InqField(
  Oracle  *c,
  int p,
  int f
)
{
  char      buf[MAX_MSIZE];
  char*     ans;

  sprintf(buf,"%s %d %d",Protocol_Field,p,f);
  ans = OracleQuery(c,buf);

  return(ans);
}

