# include "display.h"
# define DEBUG 0

/** this list must match the one in kapa/include/structures.h, and equiv */
# define NGRAPHCOLORS 23
static char GRAPHCOLORS[NGRAPHCOLORS][2][15] = {
  {"black",    "0.00 0.00 0.00"},
  {"white",    "1.00 1.00 1.00"},
  {"red",      "1.00 0.00 0.00"}, 
  {"pink",     "1.00 0.75 0.80"}, 
  {"orange",   "1.00 0.65 0.00"}, 
  {"yellow",   "1.00 1.00 0.00"}, 
  {"wheat",    "0.96 0.87 0.70"}, 
  {"gold",     "1.00 0.84 0.00"}, 
  {"green",    "0.00 1.00 0.00"}, 
  {"darkgreen","0.00 0.40 0.00"}, 
  {"blue",     "0.00 0.00 1.00"}, 
  {"skyblue",  "0.53 0.81 0.92"}, 
  {"indigo",   "0.56 0.16 0.87"}, 
  {"violet",   "1.00 0.00 0.00"},
  {"grey10",   "0.10 0.10 0.10"},
  {"grey20",   "0.20 0.20 0.20"},
  {"grey30",   "0.30 0.30 0.30"},
  {"grey40",   "0.40 0.40 0.40"},
  {"grey50",   "0.50 0.50 0.50"},
  {"grey60",   "0.60 0.60 0.60"},
  {"grey70",   "0.70 0.70 0.70"},
  {"grey80",   "0.80 0.80 0.80"},
  {"grey90",   "0.90 0.90 0.90"}};

  /* we have space for several kapa windows */
# define NXGRAPH 5

static int       IsImage = FALSE;
static int       Active;
static int       Xgraph[NXGRAPH];  
static Graphdata graphdata[NXGRAPH];

int GetCurrentDevice () {
  return (IsImage);
}

void SetImageDevice (int state) {
  IsImage = state;
}

void QuitGraph () {

  int i;
  
  for (i = 0; i < NXGRAPH; i++) {
    if (Xgraph[i] > 0) {
      write (Xgraph[i], "QUIT", 4);
    }
  }
}

void InitGraph () {

  int i;

  Active = 0;
  for (i = 0; i < NXGRAPH; i++) {
    Xgraph[i] = -1;

    graphdata[i].xmin = graphdata[i].ymin = 0.0;
    graphdata[i].xmax = graphdata[i].ymax = 1.0;
    graphdata[i].style = graphdata[i].ptype = 0;
    graphdata[i].ltype = graphdata[i].color = 0;
    graphdata[i].etype = graphdata[i].ebar = 0;
    graphdata[i].lweight = graphdata[i].size = 1.0;
    
    graphdata[i].coords.pc1_1 = graphdata[i].coords.pc2_2 = 1.0;
    graphdata[i].coords.pc1_2 = graphdata[i].coords.pc2_1 = 0.0;
    strcpy (graphdata[i].coords.ctype, "RA---LIN");
    graphdata[i].coords.crval1 = 0.0;
    graphdata[i].coords.crval2 = 0.0;
    graphdata[i].coords.crpix1 = 0.0;
    graphdata[i].coords.crpix2 = 0.0;
    graphdata[i].coords.cdelt1 = graphdata[i].coords.cdelt2 = 1.0;
    graphdata[i].flipeast = TRUE;
    graphdata[i].flipnorth = FALSE;
  }
}

/* set SIGPIPE to this function to close cleanly */ 
void XGraphDead (int input) {
  signal (SIGPIPE, XGraphDead);
  fprintf (stderr, "kapa is dead, must restart\n");
  Xgraph[Active] = -1;
}

/** start socketed connection */
int open_graph (int N) {

  int InitSocket, status, addreslen, Ntry, fd;
  char temp[128], socket_name[64], *kapa_exec;
  struct sockaddr_un Address;
  
  kapa_exec = get_variable ("KAPA");
  if (kapa_exec == (char *) NULL) {
    fprintf (stderr, "variable KAPA not found\n");
    return (FALSE);
  }

  sprintf (socket_name, "/tmp/Kapa.XXXXXX");
  if ((fd = mkstemp (socket_name)) == -1) {
    fprintf (stderr, "error starting kapa\n");
    return (FALSE);
  }
  close (fd);
  unlink (socket_name);

  strcpy (Address.sun_path, socket_name); 
  Address.sun_family = AF_UNIX; 
  InitSocket = socket (AF_UNIX, SOCK_STREAM, 0); 
  status = bind (InitSocket, (struct sockaddr *) &Address, sizeof (Address));
  status = listen (InitSocket, 1);
  
  sprintf (temp, "%s %s &", kapa_exec, socket_name);
  free (kapa_exec);

# if DEBUG
  fprintf (stderr, "start kapa, press return: %s\n", temp);
  fscanf (stdin, "%d", &i);
# else  
  system (temp);
# endif
  
  addreslen =  sizeof (Address);
  fcntl (InitSocket, F_SETFL, O_NONBLOCK); 

# define NTRY 200
  Ntry = 0;
  while (Ntry < NTRY) {
    Xgraph[N] = accept (InitSocket, (struct sockaddr *)&Address, &addreslen);
    if (Xgraph[N] == -1) {
      if (errno == EAGAIN) {
	usleep (10000);
	Ntry ++;
      } else { 
	Ntry = NTRY;
      }
    } else {
      Ntry = NTRY;
    }
  }
  if (Xgraph[N] < 0) {
    fprintf (stderr, "error starting kapa\n");
    return (FALSE);
  } else {
    fcntl (Xgraph[N], F_SETFL, !O_NONBLOCK); 
    return (TRUE);
  }
  
}

/* return pointers for current Xgraph, set if desired, test, open if needed */
int GetGraph (Graphdata *data, int *socket, int *N) {

  int i, n;
  char buffer[70];

  SetImageDevice (FALSE);
  if (N == (int *) NULL) {
    n = Active;
  } else {
    if (*N >= NXGRAPH) {
      fprintf (stderr, "invalid Xgraph window %d\n", *N); 
      return (FALSE);
    }
    if (*N < 0) {
      *N = n = Active;
    } else {
      Active = n = *N;
    }
  }
  
  /* test Xgraph[0], flush junk from pipe */
  signal (SIGPIPE, XGraphDead);
  fcntl (Xgraph[n], F_SETFL,  O_NONBLOCK); 
  for (i = 0; (read (Xgraph[n], buffer, 64) > 0) && (i < 20); i++);
  fcntl (Xgraph[n], F_SETFL, !O_NONBLOCK); 
  
  if (Xgraph[n] < 1) {
    if (!open_graph(n)) {
      return (FALSE);
    }
  }

  if (data != (Graphdata *) NULL) *data  = graphdata[n];
  if (socket != (int *) NULL) *socket = Xgraph[n];

  return (TRUE);

}

/* return pointers for given Xgraph, don't set or open */
int GetGraphData (Graphdata *data, int *sock, int *N) {

  int n;

  if (N == (int *) NULL) {
    n = Active;
  } else {
    if (*N >= NXGRAPH) {
      fprintf (stderr, "invalid Xgraph window %d\n", *N); 
      return (FALSE);
    }
    if (*N < 0) {
      n = Active;
    } else {
      n = *N;
    }
  }
  
  if (data != (Graphdata *) NULL) *data  = graphdata[n];
  if (sock != (int *) NULL) *sock = Xgraph[n];

  return (TRUE);

}

/* assign given values to current Xgraph */
void SetGraph (Graphdata data) {
  graphdata[Active] = data;
}

int GetColor (char *name) {

  int i;
  
  for (i = 0; i < NGRAPHCOLORS; i++) {
    if (!strcmp (name, GRAPHCOLORS[i][0])) {
      return (i);
    }	
  }
  fprintf (stderr, "color may be one of:\n");
  for (i = 0; i < NGRAPHCOLORS; i++) {
    fprintf (stderr, "  %s\n", GRAPHCOLORS[i][0]);
  }
  return (-1);
}	

int SendLabel (char *string, int Xgraph, int mode) {

  char buffer[64];

  write (Xgraph, "LABL", 4);
  sprintf (buffer, " %6d %6d  ", strlen (string), mode);
  write (Xgraph, buffer, 16);
  write (Xgraph, string, strlen (string));
  return (TRUE);
}
