#include <stdio.h>

// encoded strings for printing to screen:
static unsigned char SCORE_STR96[] = {5, 29, 13, 25, 28, 15};
static unsigned char HIGH_SCORE_STR96[] = {10, 18,19,17,18,0,29,13,25,28,15};
static unsigned char CREDITS_STR128[] = {8, 13,28,15,14,19,30,29,0};
static unsigned char INSERT_COIN_STR128[] = {11, 19,24,29,15,28,30,0,13,25,19,24};
static unsigned char PRESS_START_STR128[] = {11, 26,28,15,29,29,0,29,30,11,28,30}; // Hmmm... I think it actually said PUSH start...

// font data:

static unsigned char font_points[] = {
 /* 0 */ 0xae, 0xe4, 0x40, 0x0a,
 /* 1 */ 0x2c,
 /* 2 */ 0xae, 0xe9, 0x95, 0x50, 0x04,
 /* 3 */ 0x04, 0x79, 0x4e, 0xea,
 /* 4 */ 0xa5, 0x59, 0x72, // originally 0x5a, 0x59, 0x4e,
 /* 5 */ 0x04, 0x49, 0x95, 0x5a, 0xae,
 /* 6 */ 0x59, 0x94, 0x40, 0x0a,
 /* 7 */ 0x2e, 0xea,
 /* 8 */ 0x04, 0xae, 0x59, 0xe4, 0xa0,
 /* 9 */ 0xea, 0xa5, 0x59, 0xe4,
 /* A */ 0x4e, 0xae, 0x59, 0xa0,
 /* B */ 0x69, 0x04, 0x4e, 0xea, 0xb1,
 /* C */ 0xae, 0x40, 0x0a,
 /* D */ 0xad, 0xd9, 0x93, 0x30, 0x0a, // originally 0xae, 0xe4, 0x40, 0x1b, (note fewer segments - changes length and index tables)
 /* E */ 0x40, 0x0a, 0x57, 0xae,
 /* F */ 0x0a, 0x57, 0xae,
 /* G */ 0x79, 0x94, 0x40, 0x0a, 0xae,
 /* H */ 0x0a, 0x59, 0x4e,
 /* I */ 0x2c,
 /* J */ 0x50, 0x03, 0x3d, 0xbe,
 /* K */ 0x0a, 0xe5, 0x54,
 /* L */ 0x0a, 0x04,
 /* M */ 0x0a, 0xa7, 0x7e, 0xe4,
 /* N */ 0x0a, 0xa4, 0x4e,
 /* O */ 0xae, 0xe4, 0x40, 0x0a,
 /* P */ 0x0a, 0xae, 0xe9, 0x95,
 /* Q */ 0x0a, 0xae, 0xe4, 0x40, 0x48,
 /* R */ 0x48, 0x59, 0x9e, 0xea, 0xa0,
 /* S */ 0x04, 0x49, 0x95, 0x5a, 0xae,
 /* T */ 0xae, 0xc2,
 /* U */ 0x0a, 0x04, 0x4e,
 /* V */ 0xa2, 0x2e,
 /* W */ 0xa1, 0x17, 0x73, 0x3e,
 /* X */ 0x0e, 0xa4,
 /* Y */ 0x27, 0x7a, 0x7e,
 /* Z */ 0xae, 0xe0, 0x04,
};

static unsigned char font_length[] = {
 /* 0 */ 4, /* 1 */ 1, /* 2 */ 5, /* 3 */ 4, /* 4 */ 3, /* 5 */ 5,
 /* 6 */ 4, /* 7 */ 2, /* 8 */ 5, /* 9 */ 4, /* A */ 4, /* B */ 5,
 /* C */ 3, /* D */ 5, /* E */ 4, /* F */ 3, /* G */ 5, /* H */ 3,
 /* I */ 1, /* J */ 4, /* K */ 3, /* L */ 2, /* M */ 4, /* N */ 3,
 /* O */ 4, /* P */ 4, /* Q */ 5, /* R */ 5, /* S */ 5, /* T */ 2,
 /* U */ 3, /* V */ 2, /* W */ 4, /* X */ 2, /* Y */ 3, /* Z */ 3,
};

static unsigned char font_index[] = {
  /* 0 */ 0,    /* 1 */ 4,    /* 2 */ 5,    /* 3 */ 10,   /* 4 */ 14,
  /* 5 */ 17,   /* 6 */ 22,   /* 7 */ 26,   /* 8 */ 28,   /* 9 */ 33,
  /* A */ 37,   /* B */ 41,   /* C */ 46,   /* D */ 49,   /* E */ 54,
  /* F */ 58,   /* G */ 61,   /* H */ 66,   /* I */ 69,   /* J */ 70,
  /* K */ 74,   /* L */ 77,   /* M */ 79,   /* N */ 83,   /* O */ 86,
  /* P */ 90,   /* Q */ 94,   /* R */ 99,   /* S */ 104,  /* T */ 109,
  /* U */ 111,  /* V */ 114,  /* W */ 116,  /* X */ 120,  /* Y */ 122,
  /* Z */ 125,
};

void seg(int segtype, int y, int x) {
}

int cur_abs_x = 0, cur_abs_y = 0, start_abs_x = 0, lastwas = 1;
int last_dumped_abs_x = 0, last_dumped_abs_y = 0;

static void move_rel(int y, int x) {
  if (x == 0 && y == 0) return;
  cur_abs_x += x; cur_abs_y += y;
  lastwas = 1;
}

static void line_rel(int y, int x) {
  if (y == 0 && x == 0) return;
  if (lastwas == 1) {
    // dump a move
    if (   (cur_abs_x != last_dumped_abs_x)
	|| (cur_abs_y != last_dumped_abs_y)
	) fprintf(stdout, "  move_rel_XY(%d,%d); // to %d,%d\n",
                  cur_abs_x-last_dumped_abs_x, cur_abs_y-last_dumped_abs_y,
		  cur_abs_x, cur_abs_y);
    // we are now reliably at the start position
    last_dumped_abs_x = cur_abs_x; last_dumped_abs_y = cur_abs_y;
  }
  cur_abs_x += x; cur_abs_y += y;
  if (cur_abs_x != last_dumped_abs_x || cur_abs_y != last_dumped_abs_y) fprintf(stdout, "  line_rel_XY(%d,%d); // to %d,%d\n", x,y, cur_abs_x, cur_abs_y);
  last_dumped_abs_x = cur_abs_x; last_dumped_abs_y = cur_abs_y;
  lastwas = 0;
}

static void move_abs(int y, int x) {
  if (   (cur_abs_x != last_dumped_abs_x)
      || (cur_abs_y != last_dumped_abs_y)
	 ) {
    move_rel(cur_abs_x-last_dumped_abs_x, cur_abs_y-last_dumped_abs_y);
    //fprintf(stdout, "  move_rel_XY(%d,%d) # to %d,%d\n", cur_abs_x-last_dumped_abs_x, cur_abs_y-last_dumped_abs_y,
    //		cur_abs_x, cur_abs_y);
    //last_dumped_abs_x = cur_abs_x; last_dumped_abs_y = cur_abs_y;
  }
  cur_abs_x = x; cur_abs_y = y;
  lastwas = 1;
}

static void segment(unsigned char coords)
{
  short fromx;
  short fromy;
  short tox;
  short toy;
  short from, to;

  // remember to use shifts instead of divides (unless GCC does it for us?)

  // clever packing may be undone by overhead of div&modulo 5 ... reconsider using less dense tables?
  to = coords & 15;
  tox = ((to % 5) *  4);
  toy = ((to / 5) * 12);

  from = coords >> 4;
  fromx = ((from % 5) *  4);
  fromy = ((from / 5) * 12);

  // assumes starts at 0,0 relative to current letter:
  move_rel((char)fromy, (char)fromx);
  line_rel((char)(toy-fromy), (char)(tox-fromx));
  move_rel((char)-toy, (char)-tox); // back to origin
}

static void ch(unsigned char charno, short scale)
{
  if (charno /* > 0U */) { // 0 is blank space
    {unsigned char i, limit;
      // If the array indexes, and calculations, in the for loop test comparison are recalculated on every loop, perhaps
      // we should pre-calculate them before entering the loop, and use the cached values?
      i = font_index[charno-1];
      limit = font_index[charno-1]+font_length[charno-1];
      while (i < limit) {
        segment(font_points[i++]);
      }
    }
  }
  // add move back here once debugged
}

void text(char *name, unsigned char *s, int scale)
{
  int i;
  fprintf(stdout, "void SHOW_%s(char absx, char absy, char scale) {\n", name);
  fprintf(stdout, "  reset_beam();\n");
  fprintf(stdout, "  set_scale(0x7f);\n");
  fprintf(stdout, "  move_rel_XY(absx, absy);\n");
  fprintf(stdout, "  set_scale(scale);\n");
  start_abs_x = 0;
  cur_abs_x = cur_abs_y = 0;
  last_dumped_abs_x = 0; last_dumped_abs_y = 0;
  for (i = 1; i <= s[0]; i++) {
    move_abs(0, start_abs_x);    // start of next letter
    ch(s[i], scale); // leave at 0,0 relative to current letter only
    start_abs_x += 24;       // all letters are 16 wide
  }
  fprintf(stdout, "}\n\n");
}

int main(int argc, char **argv) {
  int i;
  text("SCORE", SCORE_STR96, 96);
  text("HIGH_SCORE", HIGH_SCORE_STR96, 96);
  text("CREDITS", CREDITS_STR128, 128);
  text("INSERT_COIN", INSERT_COIN_STR128, 128);
  text("PRESS_START", PRESS_START_STR128, 128);
}