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

#define FLAGOP 0x36df3d7
#define DRAWOP 0x3300300
#define FILLOP 0x2492000

double *x = NULL, *y = NULL;
int n;
int brushmode = 0, arcmode = 0, ellipsemode = 0,
  splinemode, polygonmode = 0, ticksmode = 0;
int sides = 5, dpi = 192, tex_x, tex_y, tex_w, tex_h, ascent, opacity;
int tt = 1, tn = 5, ts = 500;
double angle = 23, ngonparam = 3236, arrowparam = 125;
char *filename = NULL;
FILE *fo;
char *path_desc[] = { "tick", "cross", "spot", "ring" };

char dkw_preamble1[] = {
  "<fonts> 0...5\n"
  "Droid Sans Mono\n"
  "Liberation Mono\n"
  "Liberation Sans Narrow\n"
  "Liberation Serif\n"
  "Comic Sans MS\n"
  "Unpilgi\n"
  "<colors>\n"
  "bc #ffffff\n"
  "ec #ff0000\n"
  "fc #e5e5e5\n"
  "hc #ffff00\n"
  "mc #000000\n"
  "nc #add8e6\n"
  "pc #ff0000\n"
  "sc #7f7f7f\n"
  "tc #000000\n"
  "uc #e6e6fa\n"
  "<dash> 16|8\n"
  "<dash> 6|6\n"
};

char dkw_preamble2[] = {
  "<menu>\n"
  "page 1 1/2 10\n"
  "font 3\n"
  "frame(x,y) 0/1 0/1\n"
  "size(draw,brush,erase,text) 1 15 8 13\n"
  "<page> 1\n"
};

void printcoords(int op)
{
  int i;
  double u, v, t, a;
  if (op == 8 && arcmode > 0) {
    a = -0.01 * M_PI / (64 * 180.0);
    x[1] = x[1] * 0.5;
    y[1] = y[1] * 0.5;
    x[0] = x[0] + x[1];
    y[0] = y[0] + y[1];
    y[2] = x[2] + y[2];
    for (i=0; i<=100; i++) {
      t = (i * y[2] + (100 - i)*x[2]) * a;
      u = x[0] + x[1] * cos(t);
      v = y[0] + y[1] * sin(t);      
      fprintf(fo, "%lg %lg\n", u, v);
    }
    n = 0;
    return;
  }
  if (op == 12 || op == 13) {
    fprintf(fo, "%lg %lg\n", x[0], y[0]);
    fprintf(fo, "%lg %lg\n", x[1], y[0]);
    fprintf(fo, "%lg %lg\n", x[1], y[1]);
    fprintf(fo, "%lg %lg\n", x[0], y[1]);
    fprintf(fo, "%lg %lg\n", x[0], y[0]);
    n = 0;
    return;
  }
  if (op == 15 || op == 16) {
    n = ((y[1]-y[0])>0);
    /*    
    if (ellipsemode == 2) {
      x[0] = 2 * x[0] - x[1];
      y[0] = 2 * y[0] - y[1];      
    }
    */
    fprintf(fo, "%lg %lg\n", (x[0]+x[1])*0.5, y[0]);
    fprintf(fo, "draw: ellipse %d\n", 1-n);    
    fprintf(fo, "%lg %lg\n", x[1], (y[0]+y[1])*0.5);
    fprintf(fo, "draw: ellipse %d\n", n);    
    fprintf(fo, "%lg %lg\n", (x[0]+x[1])*0.5, y[1]);
    fprintf(fo, "draw: ellipse %d\n", n);    
    fprintf(fo, "%lg %lg\n", x[0], (y[0]+y[1])*0.5);
    fprintf(fo, "draw: ellipse %d\n", 1-n);        
    fprintf(fo, "%lg %lg\n", (x[0]+x[1])/2, y[0]);
    n = 0;
    return;
  }
  for (i=0; i<n; i++) {
    if (i == 0) {
      if (polygonmode && (op == 21 || op == 22)) {
	u = x[0];
	v = y[0];
	x[0] = x[1];
	y[0] = y[1];
	x[1] = 2 * u - x[0];
	y[1] = 2 * v - y[0];	  
      }
    }
    if (isnan(x[i])) {
      if (op == 24 || op == 25)
	fprintf(fo, "draw: spline %d\n", splinemode);
      continue;
    }  
    if (i == 1) {
      if (op == 6 && ticksmode) {
	fprintf(fo, "draw: %s %d %d\n", path_desc[tt-1], tn, ts);
	ticksmode = 0;
      } else          
      if (op == 8) fprintf(fo, "draw: arc\n");
      else
      if (op == 9) fprintf(fo, "draw: vector %lg %lg\n", angle, arrowparam);
      else
      if (op == 21 || op == 22) {
	if (polygonmode == 2)
	  fprintf(fo, "draw: n-gon %d %lg\n", sides, ngonparam);
	else
	if (polygonmode == 3)
	  fprintf(fo, "draw: n-star %d %lg\n", sides, ngonparam);
      }
      else
      if (op == 24 || op == 25)
	fprintf(fo, "draw: spline %d\n", splinemode);
    }
    fprintf(fo, "%lg %lg\n", x[i], y[i]);
  }
  n = 0;
}

void usage()
{
  printf("Usage: vxp2dkw [-i] <inputfile> [-o <outputfile>]\n");
  exit(0);
}

int main(int argc, char **argv)
{
  FILE *fd;
  char buf[1024], output[32], colorstr1[32], colorstr2[32];
  unsigned int tcolor, color1 = 0, color2 = 0, ll;
  int i, width, height, op = -1, np, dash = 0, cap, join, tn = 0;
  double u, w = 1.0;
  char *writing = NULL, *ptr = NULL, **formula = NULL;
  char *inputfile;
  long pos;
  
  inputfile = argv[1];

  if (argc <= 1) {
    printf("No input file has been specified !!\n");
    usage();
  }
  i = 1;
  while (i < argc) {
    if (!strcmp(argv[i], "-h")) usage();
    else    
    if (i == argc - 1) inputfile = argv[i];
    else
    if (!strcmp(argv[i], "-i")) inputfile = argv[++i];
    else
    if (!strcmp(argv[i], "-o")) filename = argv[++i];      
    else
    inputfile = argv[i];
    ++i;
  }

  if (!filename) {
    filename = (char *)malloc(strlen(inputfile)+8);
    strcpy(filename, inputfile);
    ptr = strrchr(filename, '.');
    if (ptr) strcpy(ptr, ".dkw"); else strcat(filename, ".dkw");
  }
  
  fd = fopen(inputfile, "r");
  if (!fd) {
    fprintf(stderr, "File %s does not exist!\n", inputfile);
    exit(1);
  }

  if (strcmp(filename, "-"))
    fo = fopen(filename, "w");
  else
    fo = stdout;
  
  if (!fo) {
    fprintf(stderr, "File %s cannot be created!\n", filename);
    exit(1);
  }
  n = 0;
  
  fgets(buf, 1020, fd);
  if (!strcmp(buf, "#VXP")) {
    fprintf(stderr, "Not a VXP file. Aborting!\n");
    exit(1);
  }

  n = 0;
  fprintf(fo, "##deskwrite\n");  
  while (!feof(fd)) {
    fgets(buf, 1020, fd);    
    i = strlen(buf) - 1;
    if (i >= 0 && buf[i] == '\n') buf[i] = '\0';    
    if (!strncmp(buf, "*canvas ", 8)) {
      pos = ftell(fd);
      sscanf(buf+8, "%d,%d", &width, &height);
      fprintf(fo, "<base> %d %d\n", width, width);
      fprintf(fo, "<pageaspect> %lg\n", (double)height/(double)width);
      fprintf(fo, "%s", dkw_preamble1);
    } else
    if (*buf == '=') {
      formula = (char **) realloc(formula, (n+1) * sizeof(char *));
      formula[n++] = strdup(buf+1);
    }
  }
  if (n) {
    fprintf(fo, "<latex> %d\n", n);
    for (i = 0; i < n; i++) {
      fprintf(fo, "\"%s\n", formula[i]);
      free(formula[i]);
    }
  }
  free(formula);
  ptr = NULL;
  fprintf(fo, "%s", dkw_preamble2);
  fseek(fd, pos, SEEK_SET);

  n = 0;
  while (1) {
    if (feof(fd)) {
      buf[0] = '*';
      buf[1] = 0;
    } else
      fgets(buf, 1020, fd);
    i = strlen(buf) - 1;
    if (i >= 0 && buf[i] == '\n') buf[i] = '\0';    
    if (*buf == ':') {
      free(writing);
      writing = strdup(buf + 1);
    } else
    if (buf[0] == '*') {      
      if (op == 3 && brushmode == 1)
        sprintf(colorstr1, "%06x", color1 | 0xc0c0c0);
      else
        sprintf(colorstr1, "%06x", color1);
      sprintf(colorstr2, "%06x", color2);      
      if (((FLAGOP >> op) & 1) && n > 0) {
	np = n+((DRAWOP>>op)&1);
	if (op == 6 && ticksmode) np = n + 1; else
	if (op == 8 && arcmode > 0) np = 101; else
	if (op == 12 || op == 13) { if (n == 2) np = 5; } else
	if (op == 15 || op == 16) { if (n == 2) np = 9; } else
	if (op == 21 || op == 22) {
	  if (polygonmode) np = n + 1 ; else np = n;
	}
	if ((FILLOP >> op) & 1)
 	  fprintf(fo, "<contour> n=%d w=%lg color=#%s #%s%s\n",
	         np, w, colorstr1, colorstr2, ((dash)?" dash=1":""));
	else
 	  fprintf(fo, "<stroke> n=%d w=%lg color=#%s%s\n",
	         np, w, colorstr1, ((dash)?" dash=1":""));	  
	printcoords(op);
      } else
      if (op == 3 && n > 0) {
	if (brushmode) {
          fprintf(fo, "<brush> n=%d w=%lg color=#%s mode=%d\n",
		  n, 15*w, colorstr1, brushmode);
	}
	else
          fprintf(fo, "<brush> n=%d w=%lg color=#%s\n", n, 15*w, colorstr1);
	printcoords(op);	
      } else
      if (op == 10 && n > 0) {
	fprintf(fo, "<text> n=%d w=%lg color=#%s font=3\n%lg %lg\n\"%s\n",
	       strlen(writing), 14*w, colorstr1, x[0], y[0], writing);
      }
      if (buf[1] == 0) break;
      if (buf[1] >= '0' && buf[1] <= '9') {
	op = atoi(buf+1);
	if (op == 6 && !strcmp(buf+3, "ticks")) ticksmode = 1;
      } else
	op = -1;
      n = 0;
      if (!strncmp(buf, "*color1 ", 8)) {
        sprintf(output, "0x%s", buf+8);
        color1 = strtol(output, NULL, 16);
      } else
      if (!strncmp(buf, "*color2 ", 8)) {
        sprintf(output, "0x%s", buf+8);
        color2 = strtol(output, NULL, 16);
      } else
      if (!strncmp(buf, "*brushmode ", 11)) {
	brushmode = atoi(buf+11);
      } else
      if (!strncmp(buf, "*arcmode ", 9)) {
	arcmode = atoi(buf+9);
      } else
      if (!strncmp(buf, "*ellipsemode ", 13)) {
	ellipsemode = atoi(buf+13);	
      } else
      if (!strncmp(buf, "*splinemode ", 12)) {
	splinemode = atoi(buf+12);
      } else	
      if (!strncmp(buf, "*polygonmode ", 13)) {
	polygonmode = atoi(buf+13);	
      } else
      if (!strncmp(buf, "*polygonparams ", 15)) {
	sscanf(buf+15, "%d %lg", &sides, &u);
	ngonparam = 8472 * u;
      } else
      if (!strncmp(buf, "*arrowheadparams ", 17)) {
	sscanf(buf+17, "%d %lg %lg", &ll, &u, &angle);
	arrowparam = 8 * u;
      } else	
      if (!strncmp(buf, "*tickparams ", 12)) {
	int a, b;
	double c, d;
	sscanf(buf+12, "%d %d %d %d %lg %lg", &tt, &a, &b, &tn, &c, &d);
        ts = (int)(18 * c);
      } else	
      if (!strncmp(buf, "*switchpatterns", 15)) {
	ll = color2;
	color2 = color1;
	color1 = ll;
      } else
      if (!strncmp(buf, "*texinput ", 10)) {
	sscanf(buf+10, "%d %d %d %06x", &dpi, &ascent, &opacity, &tcolor);
      } else
      if (!strncmp(buf, "*texoutput ", 11)) {
	sscanf(buf+11, "%d,%d %d,%d", &tex_x, &tex_y, &tex_w, &tex_h);
	fprintf(fo, "<text> n=%d w=%g color=#%06x latex\n%g %g\n",
		tn, dpi/15.0, tcolor, (double)tex_x, (double)(tex_y + ascent));
	++tn;		
      } else
      if (!strncmp(buf, "*setlinestyle ", 14)) {
	ptr = strdup(buf+14);
	sscanf(buf+14, "%lg %d %d %[^\t\n]", &w, &cap, &join, ptr);
	if (ptr && *ptr) dash = (strcmp(ptr, "=") != 0);
	free(ptr);
      }
    } else {
      i = n + 1;
      x = (double *)realloc(x, i * sizeof(double));
      y = (double *)realloc(y, i * sizeof(double));
      if (buf[0] == '0' && buf[1] == '!') {
	x[n] = y[n] = NAN;
	n = i;
      } else  
      if (sscanf(buf, "%lg,%lg", &x[n], &y[n]) == 2) n = i;      
    }    
  }
  fprintf(fo, "<end>\n");
  fclose(fo);
  return 0;
}
