
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#if !defined(VMS) && !defined(_WIN32)
#include <unistd.h>
#endif

#include "gks.h"
#include "gkscore.h"

#define SEGM_SIZE 262144 /* 256K */

#if defined(__POWERPC__) || defined(aix)
#define HAVE_BIG_ENDIAN
#endif

#ifndef HAVE_BIG_ENDIAN
#define COPY(s, nmemb, size) \
  memcpy(p->buffer + p->nbytes, (void *) s, nmemb * size); \
  p->nbytes += nmemb * size
#else
#define COPY(s, nmemb, size) copy((char *) s, nmemb, size)
#endif

#define RESOLVE(arg, type, nbytes) arg = (type *)(s + sp); sp += nbytes

typedef struct ws_state_list_struct
  {
    int conid, state;
    int segn;
    int empty;
    char *buffer;
    int size, nbytes;
  }
ws_state_list;

static ws_state_list *p;
static gks_state_list_t *gkss;
static int wkid = 1;
static int unused_variable = 0;

#ifdef HAVE_BIG_ENDIAN

static
int swabint(char p[4])
{
  return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
}

static
void copy(char *s, int nmemb, int size)
{
  register int i;

  memcpy(p->buffer + p->nbytes, (void *) s, nmemb * size);
  if (size == 4)
    {
      for (i = 0; i < nmemb; i++)
	swabint(p->buffer + p->nbytes + i * size);
    }
  p->nbytes += nmemb * size;
}

#endif

static
void reallocate(int len)
{
  while (p->nbytes + len >= p->size)
    p->size += SEGM_SIZE;

  p->buffer = (char *) gks_realloc(p->buffer, p->size);
  if (p->buffer == NULL)
    {
      gks_perror("memory allocation failed");
      exit(1);
    }
}

#if 0

static
int cksum(void)
{
  int i, crc = 0;

  for (i = 0; i < p->nbytes; i++)
    {
      if (crc & 1)
        crc |= 0x10000;
      crc = ((crc >> 1) + p->buffer[i]) & 0xffff;
    }
  return crc;
}

#endif

static
void write_item(
  int sgnum, int fctid, int dx, int dy, int dimx, int *i_arr,
  int len_farr_1, double *f_arr_1, int len_farr_2, double *f_arr_2,
  int len_c_arr, char *c_arr)
{
  char s[132];
  int len = -1, slen;

  switch (fctid)
    {
    case 12:			/* polyline */
    case 13:			/* polymarker */
    case 15:			/* fill area */

      len = 4 * sizeof(int) + 2 * i_arr[0] * sizeof(double);
      if (p->nbytes + len >= p->size)
	reallocate(len);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(i_arr, 1, sizeof(int));
      COPY(f_arr_1, i_arr[0], sizeof(double));
      COPY(f_arr_2, i_arr[0], sizeof(double));
      break;

    case 14:			/* text */

      len = 4 * sizeof(int) + 2 * sizeof(double) + 132;
      if (p->nbytes + len >= p->size)
	reallocate(len);

      memset((void *) s, 0, 132);
      slen = strlen(c_arr);
      strncpy(s, c_arr, slen);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(f_arr_1, 1, sizeof(double));
      COPY(f_arr_2, 1, sizeof(double));
      COPY(&slen, 1, sizeof(int));
      COPY(s, 1, 132);
      break;

    case 16:			/* cell array */
    case 201:			/* draw image */

      len = (6 + dimx * dy) * sizeof(int) + 4 * sizeof(double);
      if (p->nbytes + len >= p->size)
	reallocate(len);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(f_arr_1, 2, sizeof(double));
      COPY(f_arr_2, 2, sizeof(double));
      COPY(&dx, 1, sizeof(int));
      COPY(&dy, 1, sizeof(int));
      COPY(&dimx, 1, sizeof(int));
      COPY(i_arr, dimx * dy, sizeof(int));
      break;

    case 19:			/* set linetype */
    case 21:			/* set polyline color index */
    case 23:			/* set markertype */
    case 25:			/* set polymarker color index */
    case 30:			/* set text color index */
    case 33:			/* set text path */
    case 36:			/* set fillarea interior style */
    case 37:			/* set fillarea style index */
    case 38:			/* set fillarea color index */
    case 52:			/* select normalization transformation */
    case 53:			/* set clipping indicator */

      len = 4 * sizeof(int);
      if (p->nbytes + len >= p->size)
	reallocate(len);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(i_arr, 1, sizeof(int));
      break;

    case 27:			/* set text font and precision */
    case 34:			/* set text alignment */

      len = 5 * sizeof(int);
      if (p->nbytes + len >= p->size)
	reallocate(len);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(i_arr, 2, sizeof(int));
      break;

    case 20:			/* set linewidth scale factor */
    case 24:			/* set marker size scale factor */
    case 28:			/* set character expansion factor */
    case 29:			/* set character spacing */
    case 31:			/* set character height */
    case 200:			/* set text slant */
    case 203:			/* set transparency */

      len = 3 * sizeof(int) + sizeof(double);
      if (p->nbytes + len >= p->size)
	reallocate(len);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(f_arr_1, 1, sizeof(double));
      break;

    case 32:			/* set character up vector */

      len = 3 * sizeof(int) + 2 * sizeof(double);
      if (p->nbytes + len >= p->size)
	reallocate(len);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(f_arr_1, 1, sizeof(double));
      COPY(f_arr_2, 1, sizeof(double));
      break;

    case 41:			/* set aspect source flags */

      len = 3 * sizeof(int) + 13 * sizeof(int);
      if (p->nbytes + len >= p->size)
	reallocate(len);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(i_arr, 13, sizeof(int));
      break;

    case 48:			/* set color representation */

      len = 4 * sizeof(int) + 3 * sizeof(double);
      if (p->nbytes + len >= p->size)
	reallocate(len);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(&i_arr[1], 1, sizeof(int));
      COPY(f_arr_1, 3, sizeof(double));
      break;

    case 49:			/* set window */
    case 50:			/* set viewport */

      len = 4 * sizeof(int) + 4 * sizeof(double);
      if (p->nbytes + len >= p->size)
	reallocate(len);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(i_arr, 1, sizeof(int));
      COPY(f_arr_1, 2, sizeof(double));
      COPY(f_arr_2, 2, sizeof(double));
      break;

    case 202:			/* set shadow */

      len = 3 * sizeof(int) + 3 * sizeof(double);
      if (p->nbytes + len >= p->size)
	reallocate(len);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(f_arr_1, 3, sizeof(double));
      break;

    case 204:			/* set coord xform */

      len = 3 * sizeof(int) + 6 * sizeof(double);
      if (p->nbytes + len >= p->size)
	reallocate(len);

      COPY(&len, 1, sizeof(int));
      COPY(&sgnum, 1, sizeof(int));
      COPY(&fctid, 1, sizeof(int));
      COPY(f_arr_1, 6, sizeof(double));
      break;
    }
}

static
void delete_seg(char *str, int segn)
{
  char *s, *d;
  int sp = 0, *len, *sgnum, dp = 0, saved_sp;

  s = d = str;

  saved_sp = sp;
  RESOLVE(len, int, sizeof(int));

  while (*len)
    {
      RESOLVE(sgnum, int, sizeof(int));
      sp = saved_sp;

      if (*sgnum != 0 && segn != *sgnum)
	{
	  if (sp > dp)
	    memcpy(d + dp, s + sp, *len);
	  dp += *len;
	}
      sp += *len;

      saved_sp = sp;
      RESOLVE(len, int, sizeof(int));
    }

  if (sp > dp)
    {
      memset(d + dp, 0, sp - dp);
      p->nbytes = dp;
    }
}

void gks_drv_wiss(
  int fctid, int dx, int dy, int dimx, int *i_arr,
  int len_farr_1, double *f_arr_1, int len_farr_2, double *f_arr_2,
  int len_c_arr, char *c_arr, void **ptr)
{
  p = (ws_state_list *) * ptr;

  switch (fctid)
    {
    case 2:			/* open workstation */

      gkss = (gks_state_list_t *) * ptr;

      p = (ws_state_list *) gks_malloc(sizeof(ws_state_list));

      p->conid = i_arr[1];
      p->state = GKS_K_WS_INACTIVE;
      p->segn = 0;
      p->empty = 1;

      p->buffer = (char *) gks_malloc(SEGM_SIZE);
      p->size = SEGM_SIZE;
      p->nbytes = 0;

      *ptr = p;
      break;

    case 3:			/* close workstation */

      free(p->buffer);
      free(p);

      p = NULL;
      break;

    case 4:			/* activate workstation */

      p->state = GKS_K_WS_ACTIVE;
      break;

    case 5:			/* deactivate workstation */

      p->state = GKS_K_WS_INACTIVE;
      break;

    case 6:			/* clear workstation */

      p->nbytes = 0;
      p->empty = 1;
      memset(p->buffer, 0, p->size);
      break;

    case 8:			/* update workstation */

      break;

    case 12:
    case 13:
    case 14:
    case 15:
    case 16:
      p->empty = 0;
    case 19:
    case 20:
    case 21:
    case 23:
    case 24:
    case 25:
    case 27:
    case 28:
    case 29:
    case 30:
    case 31:
    case 32:
    case 33:
    case 34:
    case 36:
    case 37:
    case 38:
    case 41:
    case 48:
    case 49:
    case 50:
    case 52:
    case 53:
    case 200:
    case 201:
    case 202:
    case 203:
    case 204:

      if (p->state == GKS_K_WS_ACTIVE)
	{
	  if (p->segn != 0)
	    {
	      int len = 3 * sizeof(int) + sizeof(gks_state_list_t);

	      if (p->nbytes == 0)
		{
		  int fctid = 2, sgnum = 0;

		  COPY(&len, 1, sizeof(int));
		  COPY(&sgnum, 1, sizeof(int));
		  COPY(&fctid, 1, sizeof(int));
		  COPY(gkss, 1, sizeof(gks_state_list_t));
		}

	      write_item(p->segn, fctid, dx, dy, dimx, i_arr,
			 len_farr_1, f_arr_1, len_farr_2, f_arr_2,
			 len_c_arr, c_arr);
	    }
	}
      break;

    case 56:			/* create segment */

      p->segn = i_arr[0];
      break;

    case 57:			/* close segment */

      p->segn = 0;
      break;

    case 58:			/* delete segment */

      delete_seg(p->buffer, i_arr[0]);
      break;
    }
}

static
void interp(char *str, int segn)
{
  char *s;
  gks_state_list_t *gkss = NULL;
  int sp = 0, *len, *sgnum, *fctid, sx = 1, sy = 1;
  int *i_arr = NULL, *dx = NULL, *dy = NULL, *dimx = NULL, *len_c_arr = NULL;
  double *f_arr_1 = NULL, *f_arr_2 = NULL;
  char *c_arr = NULL;
  int saved_sp;
  double mat[3][2];

  s = str;

  saved_sp = sp;
  RESOLVE(len, int, sizeof(int));

  while (*len)
    {
      RESOLVE(sgnum, int, sizeof(int));
      RESOLVE(fctid, int, sizeof(int));

      switch (*fctid)
	{
	case 2:

	  RESOLVE(gkss, gks_state_list_t, sizeof(gks_state_list_t));
	  unused_variable = gkss->ltype;
	  break;

	case 12:		/* polyline */
	case 13:		/* polymarker */
	case 15:		/* fill area */

	  RESOLVE(i_arr, int, sizeof(int));
	  RESOLVE(f_arr_1, double, i_arr[0] * sizeof(double));
	  RESOLVE(f_arr_2, double, i_arr[0] * sizeof(double));
	  break;

	case 14:		/* text */

	  RESOLVE(f_arr_1, double, sizeof(double));
	  RESOLVE(f_arr_2, double, sizeof(double));
	  RESOLVE(len_c_arr, int, sizeof(int));
	  RESOLVE(c_arr, char, 132);
	  break;

	case 16:		/* cell array */
	case 201:		/* draw image */

	  RESOLVE(f_arr_1, double, 2 * sizeof(double));
	  RESOLVE(f_arr_2, double, 2 * sizeof(double));
	  RESOLVE(dx, int, sizeof(int));
	  RESOLVE(dy, int, sizeof(int));
	  RESOLVE(dimx, int, sizeof(int));
	  RESOLVE(i_arr, int, *dimx * *dy * sizeof(int));
	  break;

	case 19:		/* set linetype */
	case 21:		/* set polyline color index */
	case 23:		/* set markertype */
	case 25:		/* set polymarker color index */
	case 30:		/* set text color index */
	case 33:		/* set text path */
	case 36:		/* set fillarea interior style */
	case 37:		/* set fillarea style index */
	case 38:		/* set fillarea color index */
	case 52:		/* select normalization transformation */
	case 53:		/* set clipping indicator */

	  RESOLVE(i_arr, int, sizeof(int));
	  break;

	case 27:		/* set text font and precision */
	case 34:		/* set text alignment */

	  RESOLVE(i_arr, int, 2 * sizeof(int));
	  break;

	case 20:		/* set linewidth scale factor */
	case 24:		/* set marker size scale factor */
	case 28:		/* set character expansion factor */
	case 29:		/* set character spacing */
	case 31:		/* set character height */
	case 200:		/* set text slant */
	case 203:		/* set transparency */

	  RESOLVE(f_arr_1, double, sizeof(double));
	  break;

	case 32:		/* set character up vector */

	  RESOLVE(f_arr_1, double, sizeof(double));
	  RESOLVE(f_arr_2, double, sizeof(double));
	  break;

	case 41:		/* set aspect source flags */

	  RESOLVE(i_arr, int, 13 * sizeof(int));
	  break;

	case 48:		/* set color representation */

	  RESOLVE(i_arr, int, sizeof(int));
	  RESOLVE(f_arr_1, double, 3 * sizeof(double));
	  break;

	case 49:		/* set window */
	case 50:		/* set viewport */

	  RESOLVE(i_arr, int, sizeof(int));
	  RESOLVE(f_arr_1, double, 2 * sizeof(double));
	  RESOLVE(f_arr_2, double, 2 * sizeof(double));
	  break;

	case 202:		/* set shadow */

	  RESOLVE(f_arr_1, double, 3 * sizeof(double));
	  break;

	case 204:		/* set coord xform */

	  RESOLVE(f_arr_1, double, 6 * sizeof(double));
	  break;

	default:
	  gks_perror("segment storage is corrupted (len=%d, fctid=%d)",
		     *len, *fctid);
	  exit(1);
	}

      if (sp != saved_sp + *len)
	{
	  gks_perror("internal error (fctid=%d)", *fctid);
	  exit(1);
	}

      if (segn == 0 || *sgnum == segn)
	{
	  switch (*fctid)
	    {
	    case 12:
	      gks_polyline(i_arr[0], f_arr_1, f_arr_2);
	      break;
	    case 13:
	      gks_polymarker(i_arr[0], f_arr_1, f_arr_2);
	      break;
	    case 14:
	      unused_variable = *len_c_arr;
	      gks_text(f_arr_1[0], f_arr_2[0], c_arr);
	      break;
	    case 15:
	      gks_fillarea(i_arr[0], f_arr_1, f_arr_2);
	      break;
	    case 16:
	      gks_cellarray(f_arr_1[0], f_arr_2[0], f_arr_1[1], f_arr_2[1],
			    *dx, *dy, sx, sy, *dimx, *dy, i_arr);
	      break;

	    case 19:
	      gks_set_pline_linetype(i_arr[0]);
	      break;
	    case 20:
	      gks_set_pline_linewidth(f_arr_1[0]);
	      break;
	    case 21:
	      gks_set_pline_color_index(i_arr[0]);
	      break;
	    case 23:
	      gks_set_pmark_type(i_arr[0]);
	      break;
	    case 24:
	      gks_set_pmark_size(f_arr_1[0]);
	      break;
	    case 25:
	      gks_set_pmark_color_index(i_arr[0]);
	      break;
	    case 27:
	      gks_set_text_fontprec(i_arr[0], i_arr[1]);
	      break;
	    case 28:
	      gks_set_text_expfac(f_arr_1[0]);
	      break;
	    case 29:
	      gks_set_text_spacing(f_arr_1[0]);
	      break;
	    case 30:
	      gks_set_text_color_index(i_arr[0]);
	      break;
	    case 31:
	      gks_set_text_height(f_arr_1[0]);
	      break;
	    case 32:
	      gks_set_text_upvec(f_arr_1[0], f_arr_2[0]);
	      break;
	    case 33:
	      gks_set_text_path(i_arr[0]);
	      break;
	    case 34:
	      gks_set_text_align(i_arr[0], i_arr[1]);
	      break;
	    case 36:
	      gks_set_fill_int_style(i_arr[0]);
	      break;
	    case 37:
	      gks_set_fill_style_index(i_arr[0]);
	      break;
	    case 38:
	      gks_set_fill_color_index(i_arr[0]);
	      break;
	    case 41:
	      gks_set_asf(i_arr);
	      break;

	    case 48:
	      gks_set_color_rep(
		wkid, i_arr[0], f_arr_1[0], f_arr_1[1], f_arr_1[2]);
	      break;

	    case 49:
	      gks_set_window(
		i_arr[0], f_arr_1[0], f_arr_1[1], f_arr_2[0], f_arr_2[1]);
	      break;
	    case 50:
	      gks_set_viewport(
		i_arr[0], f_arr_1[0], f_arr_1[1], f_arr_2[0], f_arr_2[1]);
	      break;
	    case 52:
	      gks_select_xform(i_arr[0]);
	      break;
	    case 53:
	      gks_set_clipping(i_arr[0]);
	      break;

	    case 200:
	      gks_set_text_slant(f_arr_1[0]);
	      break;
	    case 201:
	      gks_draw_image(f_arr_1[0], f_arr_2[0], f_arr_1[1], f_arr_2[1],
			     *dx, *dy, i_arr);
	      break;
	    case 202:
	      gks_set_shadow(f_arr_1[0], f_arr_1[1], f_arr_1[2]);
	      break;
	    case 203:
	      gks_set_transparency(f_arr_1[0]);
	      break;
	    case 204:
	      mat[0][0] = f_arr_1[0];
	      mat[0][1] = f_arr_1[1];
	      mat[1][0] = f_arr_1[2];
	      mat[1][1] = f_arr_1[3];
	      mat[2][0] = f_arr_1[4];
	      mat[2][1] = f_arr_1[5];
	      gks_set_coord_xform(mat);
	      break;
	    }
	}

      saved_sp = sp;
      RESOLVE(len, int, sizeof(int));
    }
}

void gks_wiss_dispatch(int fctid, int wkid, int segn)
{
  interp(p->buffer, segn);
}
