#include <stdio.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>

#include "gpc.h"
#include "svg.h"

// outside dimensions of tray - eventually these may be command-line parameters...

float wood = 4.65; //mm
float KERF = 0.57; //mm  really tight fit, but comes loose after a few removals and reinsertions
float HALF_KERF;

#define W 30 /* left-right */
//#define H 380 /* top-bottom */
#define H 30 /* top-bottom */
#define D 30  /* front-back */

// --------------------------------------------------------
int mm(int m) {
  return m*100;
}

int in(int m) {
  return m*2540;
}

int ft(int m) {
  return in(m*12);
}

int mm_f(float m) {
  return (int)roundf(m*100.0);
}

int in_f(float m) {
  return (int)roundf(m*2540.0);
}

int ft_f(float m) {
  return in_f(m*12.0);
}

#define RED "#FF0000"
#define GREEN "#00FF00"
#define BLUE "#0000FF"
#define PINK "#FFAAAA"
#define WHITE "#FFFFFF"
#define BLACK "#000000"
#define BACKGROUND "#DDDDFF"

#define ENGRAVE_TEXT BLACK
#define COMMENT_TEXT BLUE

#define HAIRLINE_f 0.01
#define VISIBLE_LINE_f 0.2

#define LIVE_FILL WHITE
#define PREVIEW_FILL PINK

static svg* psvg;

int PREVIEW;
// value of these depends on PREVIEW
float linewidth_f;
char *fill;
float stage_width = 0.0, stage_height = 0.0;

void hole_mm_f(float w, float h, float x, float y) {
  if (x+w > stage_width) stage_width = x+w;
  if (y+h > stage_height) stage_height = y+h;

  if (PREVIEW) {
    svg_rectangle(psvg, /* size */ mm_f(w), mm_f(h), /* at */ mm_f(x), mm_f(y),
                  BACKGROUND, /* outline */ BACKGROUND, /* border-width */mm_f(linewidth_f),
                  /* radius x,y */ 0,0);
  } else {
    svg_rectangle(psvg, /* size */ mm_f(w), mm_f(h), /* at */ mm_f(x), mm_f(y),
                  WHITE, /* outline */ RED, /* border-width */mm_f(linewidth_f),
                  /* radius x,y */ 0,0);
  }
}

void face(int w, int h, int x, int y) {
  if (x+w > stage_width) stage_width = x+w;
  if (y+h > stage_height) stage_height = y+h;

  svg_rectangle(psvg, /* size */ mm(w), mm(h), /* at */ mm(x), mm(y),
                fill, /* outline */ RED, /* border-width */mm_f(linewidth_f),
                /* radius x,y */ 0,0);
}

#ifdef NEVER
  svg_text(psvg, /* at */ mm(x+10), mm(y+25+1),
           "sans-serif",
           mm(3),
           /* fill colour */ COMMENT_TEXT, /* stroke colour */ COMMENT_TEXT, "5cm x 5cm square", "");
#endif

void toothcomb(float center_x, float center_y, int cuts, float spacing, int cut_depth) {
  int i;
  float start_x;

  if ((cuts & 1) == 0) {
    // even number of cuts
    start_x = center_x - spacing/2 - ((cuts-1)>>1)*spacing;
  } else {
    // odd number of cuts
    start_x = center_x             - (cuts>>1)*spacing;
  }

  for (i = 0; i < cuts; i++) {
    svg_line(psvg, RED, /* width */ mm_f(linewidth_f),
	     /* from */ mm_f(start_x), mm_f(center_y),
      /* to */ mm_f(start_x), mm_f(center_y+cut_depth));
    start_x += spacing;
  }
}

void front_face(int x, int y) {
  int order;
  int steps = (W - (wood + /* 10 + 10 +*/ wood))/2 ; // NO /*1 cm*/ gap from internal sides
  for (order = 0; order <= 1; order++) { // preview actions then live actions
    // cut before the face falls out
    if (order == (PREVIEW&1)) {
      hole_mm_f(wood, H/3.0 - 2.0*KERF, /* at */ x+5 /*+ wood*/, y+5 + H/2.0 - H/6.0 + KERF);
      hole_mm_f(wood, H/3.0 - 2.0*KERF, /* at */ x+5 + W-wood/*-wood*/, y+5 + H/2.0 - H/6.0 + KERF);
    }
    if (order == 0) face(W, H, x+5, y+5);
  }
}

void back_face(int x, int y) {
  int order;
  int steps = (W - (wood + /* 10 + 10 +*/ wood))/2 ; // NO /*1 cm*/ gap from internal sides
  for (order = 0; order <= 1; order++) { // preview actions then live actions
    if (order == (PREVIEW&1)) {
      hole_mm_f(wood, H/3.0 - 2.0*KERF, /* at */ x+5+W+5 /*+ wood*/, y+5 + H/2.0 - H/6.0 + KERF);
      hole_mm_f(wood, H/3.0 - 2.0*KERF, /* at */ x+5+W+5 + W-wood/*-wood*/, y+5 + H/2.0 - H/6.0 + KERF);
    }
    if (order == 0) face(W, H, x+5+W+5, y+5);
  }
}

void left_face(int x, int y) {
  int order;
  int steps = (D - (wood + /* 10 + 10 +*/ wood))/2 ; // NO /*1 cm*/ gap from internal sides
  for (order = 0; order <= 1; order++) { // preview actions then live actions
    if (order == (PREVIEW&1)) {
      hole_mm_f(wood, H/3.0, /* at */ x+5+W+5+W+5 /*+ wood*/, y+5);
      hole_mm_f(wood, H/3.0, /* at */ x+5+W+5+W+5 + D-wood/*-wood*/, y+5);

      hole_mm_f(wood, H/3.0, /* at */ x+5+W+5+W+5 /*+ wood*/, y+5 - H/3.0 + H);
      hole_mm_f(wood, H/3.0, /* at */ x+5+W+5+W+5 + D-wood/*-wood*/, y+5 - H/3.0 + H);
    }
    if (order == 0) face(D, H, x+5+W+5+W+5, y+5);
  }
}

void right_face(int x, int y) {
  int order;
  int steps = (D - (wood + /* 10 + 10 +*/ wood))/2 ; // NO /*1 cm*/ gap from internal sides
  for (order = 0; order <= 1; order++) { // preview actions then live actions
    if (order == (PREVIEW&1)) {
      hole_mm_f(wood, H/3.0, /* at */ x+5+W+5+W+5+D+5 /*+ wood*/, y+5);
      hole_mm_f(wood, H/3.0, /* at */ x+5+W+5+W+5+D+5 + D-wood/*-wood*/, y+5);

      hole_mm_f(wood, H/3.0, /* at */ x+5+W+5+W+5+D+5 /*+ wood*/, y+5 - H/3.0 + H);
      hole_mm_f(wood, H/3.0, /* at */ x+5+W+5+W+5+D+5 + D-wood/*-wood*/, y+5 - H/3.0 + H);
    }
    if (order == 0) face(D, H, x+5+W+5+W+5+D+5, y+5);
  }
}

void base(int x, int y) {
  face(D, W, x+5+W+5+W+5+D+5+D+5, y+5);
}

void ruler(int x, int y) {
  svg_line(psvg, RED, /* width */ mm_f(linewidth_f), /* from */ mm(x), mm(y), /* to */ mm(x+50), mm(y));
  svg_line(psvg, RED, /* width */ mm_f(linewidth_f), /* from */ mm(x), mm(y), /* to */ mm(x), mm(y-5));
  svg_line(psvg, RED, /* width */ mm_f(linewidth_f), /* from */ mm(x+50), mm(y), /* to */ mm(x+50), mm(y-5));
  svg_text(psvg, /* at */ mm(x+10), mm(y-1),
           "sans-serif",
           mm(3),
           /* fill colour */ BLACK, /* stroke colour */ BLACK, "5cm line", "");

}

void tray(int x, int y) {
  // base(x,y); skip base for threading test...
  front_face(x,y);
  back_face(x,y);
  left_face(x,y);
  right_face(x,y);
}

int main(void) {
  HALF_KERF = KERF/2.0;
  stage_width = 3600.0-5.0; stage_height = 2400.0-5.0;

  for (PREVIEW = 1; PREVIEW >= -1; PREVIEW--) { // do preview first to get size
    linewidth_f = PREVIEW ? VISIBLE_LINE_f : HAIRLINE_f;
    fill = PREVIEW ? PREVIEW_FILL : LIVE_FILL;

    psvg = svg_create(mm_f(stage_width+5), mm_f(stage_height+5)); // size of laser cutter bed
    stage_width = 0.0; stage_height = 0.0;

    if (psvg == NULL) {
      puts("psvg is NULL");
      exit(EXIT_FAILURE);
    } else {
      if (PREVIEW) svg_fill(psvg, BACKGROUND);
    }

    tray(0,0);

    if (PREVIEW) svg_text(psvg,
             /* at */ mm(2), mm(4),
             "sans-serif", mm(3),
             /* fill colour */ COMMENT_TEXT, /* stroke colour */ COMMENT_TEXT,
			  "THIS IS A PREVIEW-OPTIMISED VERSION.  CUT THE OTHER FILE.", "");

    svg_finalize(psvg);
    svg_save(psvg, PREVIEW ? "box-preview.svg" : "box.svg");
    svg_free(psvg);
  }

  exit(EXIT_SUCCESS);
  return EXIT_FAILURE;
}