/*******************************************************************************
*       FILE CONTAINING UTILITY FUNCTIONS USED IN CEREBELLAR PROGRAMS          *
*******************************************************************************/


/* include files */

#include <stdio.h>
#include <math.h>
/*gn*/
#include <suntool/sunview.h>
/*gn*/
#include <suntool/panel.h>
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <strings.h>
#include "util_fns.h"


/* definitions of functions */

/*******************************************************************************
*       FUNCTION TO GENERATE A REAL RANDOM NUMBER IN THE RANGE SUPPLIED        *
*******************************************************************************/

double rnd(range)
register double range; /* max size of random number to be returned (min = 0.0)*/
{
	/* drand returns random double in range 0.0-1.0 */
	return(drand48() * range);
}


/*******************************************************************************
*       FUNCTION TO GENERATE A REAL RANDOM NUMBER IN THE RANGE SUPPLIED        *
*    		  BUT WITH A NON_RECTANGULAR DISTRIBUTION 		       *
*******************************************************************************/

double double_rnd(range)
register double range; /* max size of random number to be returned (min = 0.0) */
{

	/* get two random numbers between 0 and range and return the average
	of them - this is equivalent to the above function except that while
	the average is the same, the standard deviation is reduced */

	return(((drand48()+drand48())*range/2.0));
}


/*******************************************************************************
*             FUNCTION TO ROUND A REAL NUMBER TO THE NEAREST INTEGER           *
*******************************************************************************/

double round(arg)
register double arg;		/* number to be rounded */
{

  /* different procedures for positive or negative numbers */
  if (arg > 0.0) {

	/* if decimal part > 0.5 then round up */
	if ((arg - (double)(int)arg) > 0.5) 
		return(1.0 + ((double)((int)arg)));
	/* if decimal part < 0.5 then round down */
	else 
		return((double)((int)arg));
  }

  else {

	/* if decimal part > 0.5 then round down */
	if (((0.0-arg) - ((double)((int)(0.0-arg)))) > 0.5) 
		return(((double)((int)arg))-1.0);
	/* if decimal part < 0.5 then round up */
	else 
		return((double)((int)arg));
  }	
}


/*******************************************************************************
*             FUNCTION TO RETURN THE LARGER OF TWO REAL NUMBERS			       *
*******************************************************************************/

double maxi(arg1, arg2)
double arg1;
double arg2;
{

  /* return the first if it is larger than the second */
  if (arg1 > arg2)
	return(arg1);
  /* otherwise return the second */
  else
	return(arg2);
}


/*******************************************************************************
*             FUNCTION TO RETURN THE SMALLER OF TWO REAL NUMBERS			   *
*******************************************************************************/

double mini(arg1, arg2)
double arg1;
double arg2;
{

  /* return the first if it is smaller than the second */
  if (arg1 < arg2)
	return(arg1);
  /* otherwise return the second */
  else
	return(arg2);
}


/*******************************************************************************
*       FUNCTION TO OPEN FILES WITH ERROR MESSAGES IF THEY CAN'T BE OPENED     *
*******************************************************************************/

FILE *fopenwithcheck(filename, type)
char *filename;			/* name of file to be opened */
char *type;			/* mode for which to open file */
{

	FILE *file;		/* file to be opened */
	char message[100];	/* error message if file can't be opened */

	/* if it is not possible to open file */
	if ((file = fopen(filename, type)) == NULL) {

		sleep(5);

		/* if it is not possible to open file */
		if ((file = fopen(filename, type)) == NULL) {

			/* create and print an error message and then quit */
			sprintf(message, "%s does not exist or cannot be opened\n",
			  filename);
			perror("error is:");
			printf(message);
			exit(0);
		}
	}

	/* else return a pointer to the opened file */
	return(file);
}


/*******************************************************************************
*          FUNCTION TO SET THE RANDOM NUMBER SEED FROM THE CURRENT TIME        *
*		   OR FROM A COMMAND LINE ARGUMENT IF SUPPLIED 		       *
*******************************************************************************/

void set_rand_seed()
{

	time_t time();		/* function to get time */
	time_t the_time,	/* time variable */
	*pthe_time;	     	/* pointer to the time variable */

    /* set seed for random number series from time */
	pthe_time = &the_time;
    time(pthe_time);
    srand48(the_time);     /* type time_t is a long int anyway */
}
 

/*g*//*******************************************************************************
/*g*//**       FUNCTION TO CHANGE THE SETTINGS OF A FRAME SO THAT IT IS DISPLAYED     *
/*g*//********************************************************************************/
/*g*/
/*g*/void turn_on(frame)
/*g*/Frame frame;
/*g*/{
/*g*/
/*g*/	window_set(frame, WIN_SHOW, TRUE, 0);
/*g*/
/*g*/	/* always deal with events when a window needs to be turned on */
/*g*/	notify_dispatch();
/*g*/}
/*g*/
/*g*/
/*g*//*******************************************************************************
/*g*//**    FUNCTION TO CHANGE THE SETTINGS OF A WINDOW SO THAT IT IS NOT DISPLAYED   *
/*g*//********************************************************************************/
/*g*/
/*g*/void turn_off(frame)
/*g*/Frame frame;
/*g*/{
/*g*/
/*g*/	window_set(frame, WIN_SHOW, FALSE, 0);
/*g*/
/*g*/	/* always deal with events when a window needs to be turned off */
/*g*/	notify_dispatch();
/*g*/}
/*g*/
/*g*/
/*g*//*******************************************************************************
/*g*//** 		           FUNCTION TO DESTROY A WINDOW                        *
/*g*//********************************************************************************/
/*g*/
/*g*/void destroy(frame)
/*g*/Frame frame;
/*g*/{
/*g*/
/*g*/	window_set(frame, FRAME_NO_CONFIRM, TRUE, 0);
/*g*/	window_destroy(frame);
/*g*/
/*g*/	/* always deal with events when a window needs to be destroyed */
/*g*/	notify_dispatch();
/*g*/}
/*g*/
/*g*/
/*g*//* procedure that does absolutely nothing (for when you need to have
/*g*//*procedures for sliders although you don't want to do anything) */
/*g*/void do_nothing_proc(item, value, event)
/*g*/Panel_item item;
/*g*/int value;
/*g*/Event *event;
/*g*/{
/*g*/
/*g*/}
/*g*/
/*g*/
/* function to return true if two strings are equal, false otherwise */
int strings_equal_q(s1, s2)
char *s1;
char *s2;
{

  if (!strcmp(s1, s2))
	return(1);			/* TRUE */
  else
	return(0);			/* FALSE */
}


/*******************************************************************************
*       FUNCTION TO GENERATE A RANDOM REAL NUMBER WITH NORMAL DISTRIBUTION     *
*                     OF ST.DEV stdev ABOUT MEAN mean						   *
*******************************************************************************/

double g_rnd(mean, stdev)
double mean;
double stdev;
{

  double fac,r,v1,v2;

  do {
	v1 = 2.0*rnd(1.0)-1.0;
	v2 = 2.0*rnd(1.0)-1.0;
	r  = v1*v1+v2*v2;
  } while (r >= 1.0);

  fac = sqrt(-2.0*log(r)/r);

  return((v2*fac*stdev + mean));
}


/*******************************************************************************
*		 FUNCTION TO CREATE A SLAVE SOCKET AND CONNECT IT TO THE MASTER		   *
*******************************************************************************/

/* 'slave socket' means the socket that makes the connection, rather than
receives it */
int make_slave_socket(hostname, portnum)
char *hostname;	/* the name of the machine to be called */
u_short portnum;	/* the number of the port on the remote machine */
{

  int socket_id;
  struct sockaddr_in my_socket;
  struct hostent *receiver_host;
  int result;

  /* get info. on host to contact */
  receiver_host = gethostbyname(hostname);
  if (receiver_host == NULL) {
	printf("error: bad receiver host info.\n");
	exit(0);
  }

  /* clear the address of this socket */
  bzero(&my_socket, sizeof(my_socket));

  /* set some socket attributes */
  my_socket.sin_family = AF_INET;
  bcopy(receiver_host->h_addr, (char *)&my_socket.sin_addr,
		receiver_host->h_length); /* address = that of master machine */
  my_socket.sin_port = htons((u_short)portnum); /* port = that of master socket */

  /* create the socket */
  if ((socket_id = socket(receiver_host->h_addrtype, SOCK_STREAM, 0)) < 0) {
	printf("error: can't create socket (%d)\n", portnum);
	exit(0);
  }

  /* connect this slave socket to the specified master socket */
  result = connect(socket_id, &my_socket, sizeof my_socket);

  /* keep trying to get a connection until one is made, or until a
  non-timeout error is received */
  while ((result < 0) &&
		 ((errno == ETIMEDOUT) || (errno == EADDRINUSE) ||
		  (errno == ECONNREFUSED))) {

	sleep(5);
	result = connect(socket_id, &my_socket, sizeof my_socket);
  }

  if (result < 0) {
	printf("error: can't connect master and slave sockets, errno = %d\n",
	  errno); 
	exit(0);
  }

  /* return the socket id */
  return(socket_id);
}


/*******************************************************************************
*    				FUNCTION TO OPEN/ESTABLISH A MASTER SOCKET 				   *
*******************************************************************************/

/* 'master socket' means the socket that receives the connection, rather than
makes it */
int make_master_socket(portnum)
u_short portnum;	/* the number of the port to bind to */
{

  char my_host_name[200];
  struct hostent * my_host;
  int socket_id;
  struct sockaddr_in my_socket;

  bzero(&my_socket, sizeof(struct sockaddr_in));
  gethostname(my_host_name, 200);
  my_host = gethostbyname(my_host_name);
  if (my_host == NULL) {
	printf("error: host %s not recognised by itself!\n", my_host_name);
	exit(0);
  }

  /* set some socket attributes */
  my_socket.sin_family = my_host->h_addrtype;
  my_socket.sin_port = htons(portnum);
  
  /* create the socket */
  if ((socket_id = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
	printf("error: can't create socket\n");
	exit(0);
  }

  /* bind an address to the socket */
  if (bind(socket_id, &my_socket, sizeof my_socket) < 0) {
	printf("error: can't bind socket to port %d\n", portnum);
	exit(0);
  }

  /* set the maximum number of queued connects */
  listen(socket_id, 4);

  /* return the socket id */
  return(socket_id);
}


/*******************************************************************************
*		FUNCTION TO MAKE A MASTER SOCKET WAIT TO BE CONNECTED BY A SLAVE	   *
*******************************************************************************/

/* 'master socket' means the socket that receives the connection, rather than
makes it */
int activate_master_socket(socket_id)
int socket_id;	/* socket to be activated */
{

  struct sockaddr_in socket_addr;
  int addr_length;
  int caller_socket_id;

  /* find socket's address for accept() */
  addr_length = sizeof(socket_addr);
  getsockname(socket_id, &socket_addr, &addr_length);

  /* make socket wait for connection to be made by slave */
  if ((caller_socket_id = accept(socket_id, &socket_addr, &addr_length)) < 0) {
	printf("error: can't perform accept on socket %d, errno = %d\n",
	  socket_id, errno);
	exit(0);
  }

  /* return the caller's socket id */
  return(caller_socket_id);
}


/*******************************************************************************
*		FUNCTION TO READ A MESSAGE FROM A SOCKET (EITHER SLAVE OR MASTER)	   *
*******************************************************************************/

int get_message(socket_id, message, exp_message_size)
int socket_id;		/* socket from which to get message */
char *message;		/* buffer to hold incoming message */
int exp_message_size;		/* number of bytes there should be in message */
{

  int byte_count = 0;
  int m_c;
  int i;

  bzero(message, exp_message_size);

  /* count bytes as read */
  while (byte_count < exp_message_size) {

	if ((m_c = read(socket_id,message,(exp_message_size-byte_count))) < 0) {
	  printf("error: in reading message from socket %d\n", socket_id);
	  exit(0);
	}
	else if (m_c > 0) {
	  byte_count += m_c;
	  message += m_c;
	}
  }

  /* return the number of bytes read in */
  return(byte_count);
}


/*******************************************************************************
*		FUNCTION TO WRITE A MESSAGE TO A SOCKET (EITHER SLAVE OR MASTER)	   *
*******************************************************************************/

int send_message(socket_id, message, exp_message_size)
int socket_id;		/* socket down which to send message */
char *message;		/* buffer holding outgoing message */
int exp_message_size;
{

  int byte_count = 0;
  int m_c;
  int i;

  /* count bytes as read */
  while (byte_count < exp_message_size) {

	if ((m_c = write(socket_id,message,(exp_message_size-byte_count))) < 0) {
	  printf("error: in writing message to socket %d\n", socket_id);
	  exit(0);
	}
	else if (m_c > 0) {
	  byte_count += m_c;
	  message += m_c;
	}
  }

  /* return the number of bytes read in */
  return(byte_count);
}

