# define PRIVATE static
# define PUBLIC

#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
# include <errno.h>

#include <netdb.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include "ldc.hh"
#include <lotos.hh>

#include "swbus.h"
#define PORT 20137

PUBLIC int error_rate;

PRIVATE int port;
PRIVATE char msg[BUFSIZ];

PRIVATE void
syserr (msg)
  char* msg;
{
  perror (msg);
  exit (1);
}

PUBLIC void
send_cmsp (o)
    kdatum  o;
{
  char msg[BUFSIZ];
  int  len;   
  int  type;
  int  bits;
  char* str;
  udatum otmp= NULL;


  printf ("\t\t-> %s\n", kd_draw (o));
  if ((rand () % 100) < error_rate) {
    fprintf (stderr, "message lost!\n");
    kd_free (o);
    return;
  }

  if (kd_gequal (isCR (kd_copy(o)), true (),3)) {
    type = line_CR;
    bits = line_NONE;
    str  = " ";
  }
  else  if (kd_gequal (isCC (kd_copy(o)), true (), 3)) {
    type = line_CC;
    bits = line_NONE;
    str  = " ";
  }
  else  if (kd_gequal (isDR (kd_copy(o)), true (), 3)) {
    type = line_DR;
    bits = line_NONE;
    str  = " ";
  }
  else  if (kd_gequal (isDC (kd_copy(o)), true (), 3)) {
    type = line_DC;
    bits = line_NONE;
    str  = " ";
  }
  else  if (kd_gequal (isAK (kd_copy(o)), true (), 3)) {
    type = line_AK;
    str  = " ";
    if (kd_gequal (bitof (kd_copy(o)), A1 () , 3))  
      bits = line_B1;
    else
      bits = line_B0;
  }
  else  if (kd_gequal (isDT (kd_copy(o)), true (), 3)) {
    type = line_DT;
    otmp= cmsduof (kd_copy(o));
    str= (char*) otmp->ptr;
    if (kd_gequal (bitof (kd_copy(o)), A1 (), 3))  
      bits = line_B1;
    else
      bits = line_B0;
  }
  
  sprintf (msg,"%d\t%d\t%s\n", type, bits, str);
  len = strlen (msg);
  if (send (port, msg, len, 0) != len ){
    perror ("error in sending at port");
    shutdown (port,1);
    exit (1);
  }

  if (otmp != NULL)
    ud_free (sdu_sort,otmp);
  kd_free(o);

}

PUBLIC int
any_message ()
{
  int len;
  int n;
  char c;

  if (! cready (port))
    return FALSE;
  else {
     c= 0;
     for (len= 0; c != '\n'; len++) {
       c= cget (port);
       msg[len]= c;
      }
     msg[len-1]= 0;
  }
}

PUBLIC kdatum
medium_input ()
{
     int type;
     int bitr;
     kdatum cmsp;

  sscanf (msg, "%d\t%d", &type, &bitr);
  switch (type) {
  case line_CR:
    cmsp= UnitInd (CR ());
    break;
  case line_CC:
    cmsp= UnitInd (CC ());
    break;
  case line_DR:
    cmsp= UnitInd (DR ());
    break;
  case line_DC:
    cmsp= UnitInd (DC ());
    break;
  case line_AK:
    cmsp= UnitInd (AK (bitr == line_B1 ? A1 () : A0 ()));
    break;
  case line_DT:
    cmsp= UnitInd (DT (bitr == line_B1 ? A1 () : A0 (),
		  mk_sdu (msg+4)));
    break;
  default :
    shutdown (port,1);
    exit (1);
  }
  printf ("\t\t<- %s\n", kd_draw (cmsp));
  return cmsp;
} 

PUBLIC void
connect_one ()		/* be server */
{
  int ls;
  struct sockaddr_in myaddr_in;
  struct sockaddr_in peeraddr_in;
  int addrlen;

  if ((ls= socket (AF_INET, SOCK_STREAM, 0)) < 0)
    syserr ("unable to create socket");
  setsockopt (ls, SOL_SOCKET, SO_REUSEADDR, (char *)0, 0);
  myaddr_in.sin_family= AF_INET;
  myaddr_in.sin_addr.s_addr= INADDR_ANY;
  myaddr_in.sin_port= htons (PORT);
  if (bind (ls, &myaddr_in, sizeof (struct sockaddr_in)) < 0)
    syserr ("unable to bind address");
  if (listen (ls, 1) < 0)
    syserr ("unable to listen on socket");
  addrlen= sizeof (struct sockaddr_in);
  while ((port= accept (ls, &peeraddr_in, &addrlen)) < 0)
    if (errno != EINTR)
      syserr ("accept failed");
}

PUBLIC void 
connect_two ()		/* be client */
{ 
  struct sockaddr_in myaddr_in;
  struct sockaddr_in peeraddr_in;
  int addrlen;
  struct hostent *hp, *gethostbyname ();

  if ((port= socket (AF_INET, SOCK_STREAM, 0)) < 0)
    syserr ("unable to create socket");
  peeraddr_in.sin_family= AF_INET;
  if ((hp= gethostbyname ("localhost")) == NULL)
    syserr ("host not found in /etc/hosts");
  bcopy (hp->h_addr, &peeraddr_in.sin_addr, hp->h_length);
  peeraddr_in.sin_port= htons (PORT);
  if (connect (port, &peeraddr_in, sizeof (struct sockaddr_in)) < 0)
    syserr ("unable to connect to remote");
}

PUBLIC void
clean_sockets ()
{
  shutdown (port,1);
}
