#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <varargs.h>
#include <errno.h>
#include <unistd.h>

/****************************************************************************************
 * meter manipulation code
 *
 * "dmeter" must be in your path so that the exec will find it.
 *
 *    CreateMeter(type,title,arguments) -- does the obvious
 *        title = a string to appear in the title bar of the meter
 *        geom  = the geometry, which can be NULL
 *
 *    UpdateMeter(meter, val,which) -- causes the supplied value to appear on the meter
 *        meter = a value returned by CreateMeter
 *        val   = what you want to display
 *        which = on which component of the display
 *
 *    DestroyMeter(meter, kill)-- does the obvious
 *        meter = a value returned by CreateMeter
 *        kill  = a flag indicating whether or not the dmeter process
 *                should be killed, which causes the meter to disappear.
 *
 *    ShutdownAllMeters(kill) -- destroys all meters
 *        kill  = a flag indicating whether or not the dmeter process
 *                should be killed, which causes the meter to disappear.
 ***************************************************************************************/

#define MAXMETERS 50
struct meter_info { int sd; int pid; char name[100]; } minfo[MAXMETERS];
int meter_num = 0;

void
ConfigureMeters()
{
  int i;
  for (i=0; i<MAXMETERS; i++) minfo[i].sd = -1;
}

/*
 * CreateMeter(type, title, arguments to widget)
 *
 */
int CreateMeter(va_alist)
     va_dcl
{
  va_list ap;
  char *type, *title;
  char geombuf[100];
  int sd, pid, i, status;
  struct sockaddr sa;
  

#define MAXARGS 100
  char *args[MAXARGS]; 
  int argno =0;
  va_start(ap);
  type = va_arg(ap, char *);
  title = va_arg(ap, char *);

  sprintf(minfo[meter_num].name,"/tmp/xm_%d",meter_num); 
  if (unlink(minfo[meter_num].name) && errno != ENOENT) { 
    perror("Could not unlink meter socket\n");
  };

  args[argno]=type; argno++;  
  args[argno]="-title"; argno++;
  args[argno]=title; argno++;
  args[argno]="-sa"; argno++;
  args[argno]=minfo[meter_num].name; argno++;
  while((args[argno] = va_arg(ap, char *)) != NULL) {
    argno++;
  }
  va_end(ap);

  
  if ( !(pid = fork()) ) {
    execvp(type, args);
    perror("CreateMeter: exec failed");
    return(-1);
  }
  sd = socket(AF_UNIX,SOCK_STREAM,0);
  sa.sa_family = AF_UNIX;
  strcpy(sa.sa_data, minfo[meter_num].name);
  for (i=0; i<50; i++) {        /* this give us 25 seconds to get the meter running */
    if ( (status = connect(sd,&sa,sizeof(sa))) != -1) break;
    sleep(1);
  }
  if (status == -1) {
    perror("Unable to connect to meter");
    exit(1);
  }
  minfo[meter_num].sd = sd;
  minfo[meter_num].pid = pid;
  return(meter_num++);
}


/* causes the meter to display the given value */
void
UpdateMeter(meterid, value, which)
int meterid;
int value;
int which;
{
  int wbuf[2];
  wbuf[0] = which;
  wbuf[1] = value;

  if (write(minfo[meterid].sd, wbuf, sizeof(wbuf)) < sizeof(wbuf)) {
    fprintf(stderr,"Unable to write to meter %d\n",meterid);
  }
}

void
DestroyMeter(meterid, killproc)
int meterid;
int killproc;
{
  close(minfo[meterid].sd);
  if (killproc) kill(minfo[meterid].pid, SIGTERM);
  if (unlink(minfo[meterid].name)) {perror("Could not unlink meter socket");}
  minfo[meterid].sd = -1;
}

void
ShutdownAllMeters(killproc)
int killproc;
{
  int i;
  for (i=0; i<MAXMETERS; i++) if (minfo[i].sd >= 0) DestroyMeter(i, killproc);
}

