#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __APPLE__
  #include <mach/error.h>
#else
  #include <error.h>
#endif
#include <errno.h>

#ifndef THRESH
#define THRESH 128
#endif

static int debug_level = 0;

static int max3(int a, int b, int c) {
  if ((a > b) && (a > c)) return a;
  if (b > c) return b;
  return c;
}

#define SP ' '
#define PX '@'
#define XS SP // '.'
#define NO SP // 'C'

typedef struct CHAR {
  char *output;
  char *fname;
  char *desc;
} CHAR;

int main(int argc, char **argv) {
  int i, j;
  const CHAR *f[128];
  for (i = 0; i < 128; i++) f[i] = NULL;

  // This is an initial phase of recognition where one glyph is manually
  // chosen by inspection from the html map, to be used for initial
  // identification.

  // We will then use that to collect multiple instances of each glyph
  // (which will almot certainly require manual filtering to remove
  //  misidentified matches).
  // Those can then be used for two purposes:
  // 1) training a neural net recogniser
  // 2) composing an 'ideal' glyph by averaging multiple (aligned)
  //    instances of a glyph.  I'm hoping that this will remove a
  //    lot of the noise and produce a cleaner master.  Manual setting
  //    of the threshold level may be needed to extract the best image.

  // one of each character manually entered from first page for demo
  // These initial approximations are replaced later by ideal characters
  // created by merging multiple instances of those characters.

  int next = 0;
  // At this point the empty cells are handled slightly differently
  // and the space character has to be listed here first.
  f[next++] = & (CHAR) { " ", "../testdata/hershey/tiles/P-075/line004/col016.png", "space" };
  f[next++] = & (CHAR) { "0", "../testdata/hershey/tiles/P-075/line004/col014.png", "0" };
  f[next++] = & (CHAR) { "1", "../testdata/hershey/tiles/P-075/line008/col018.png", "1" };
  f[next++] = & (CHAR) { "2", "../testdata/hershey/tiles/P-075/line006/col022.png", "2" };
  f[next++] = & (CHAR) { "3", "../testdata/hershey/tiles/P-075/line011/col038.png", "3" };
  f[next++] = & (CHAR) { "4", "../testdata/hershey/tiles/P-075/line009/col022.png", "4" };
  f[next++] = & (CHAR) { "5", "../testdata/hershey/tiles/P-075/line005/col022.png", "5" };
  f[next++] = & (CHAR) { "6", "../testdata/hershey/tiles/P-075/line010/col013.png", "6" };
  f[next++] = & (CHAR) { "7", "../testdata/hershey/tiles/P-075/line004/col022.png", "7" };
  f[next++] = & (CHAR) { "8", "../testdata/hershey/tiles/P-075/line005/col026.png", "8" };
  f[next++] = & (CHAR) { "9", "../testdata/hershey/tiles/P-075/line005/col034.png", "9" };
  f[next++] = & (CHAR) { ":", "../testdata/hershey/tiles/P-075/line005/col011.png", ":" };
  f[next++] = & (CHAR) { "-", "../testdata/hershey/tiles/P-075/line005/col021.png", "-" };
  f[next] = NULL;
  
  printf("#ifndef NULL\n");
  printf("#define NULL 0\n");
  printf("#endif\n\n");

  printf("typedef struct asciimap {\n");
  printf("  const char *ch;\n"); // updated structure required for IPA example.
                                 // Backporting to initial implementation and updating ALGOL-W example.
  printf("  const char *f;\n");
  printf("  const char *desc;\n");
  printf("  const char *line[100]; // *UP TO* 45 lines.\n");
  printf("} asciimap;\n\n");

  printf("const asciimap C[128] = {\n");
  for (i = 0; i < next; i++) {
    printf("  {\n");
    printf("    \"%s\",\n", f[i]->output);
    printf("    \"%s\",\n", f[i]->fname);
    printf("    \"%s\",\n", f[i]->desc);
    {
      FILE *png;
      static char fname[1024];
      sprintf(fname, "convert %s txt:-", f[i]->fname);
      png = popen(fname, "r");
      if (png == NULL) {
        printf("      {\n");
        //for (j = 0; j < 45; j++) {
        //  printf("    \"                                                      \",\n");
        //}
        printf("        NULL,\n");
        printf("      },\n");
      } else {
        static char line[128];
        int c;
        int maxx, maxy, maxbyte, x, y, r, g, b;
        // # ImageMagick pixel enumeration: 40,67,255,gray
        // 0,0: (255,255,255)  #FFFFFF  gray(255)
        int p;
        printf("    {\n");
        for (;;) {
          p = 0;          
          for (;;) {
            c = fgetc(png);
            if (c == EOF || c == '\n' || ferror(png)) break;
            line[p++] = c;
          }
          line[p] = '\0';
          if (c != '\n') break;
          if (line[0] == '#') {
            // "# ImageMagick pixel enumeration: 40,67,255,gray"
            int rc = sscanf(line, "# ImageMagick pixel enumeration: %d,%d,%d,"/*gray*/,
                            &maxx, &maxy, &maxbyte);
            if (rc == 3) {
              if (debug_level >= 1) fprintf(stderr, "%d x %d (%d)\n", maxx, maxy, maxbyte);
              //P.width = maxx; P.height = maxy;
            } else {
              exit(1); 
            }
          } else {
            // "0,0: (255)  #FFFFFF  gray(255)"
            int rc = sscanf(line, "%d,%d: (%d,%d,%d)"/*  #FFFFFF  gray(255)*/, &x, &y, &r, &g, &b);
            if (rc == 5) {
              if (debug_level >= 2) printf("x=%d y=%d: r=%d/g=%d/b=%d\n", x, y, r, g, b);
              if ((x >= maxx || x < 0) || (y >= maxy || y < 0)) {
                // index out of range
                if (debug_level >= 2) fprintf(stderr, "png2h: pixel (%d,%d) out of range (0:%d,0:%d):  %s\n\n", x,y, maxx-1,maxy-1, line);
              } else {
                if (x == 0) printf("      \"");
                if (max3(r,g,b) > THRESH) putchar('@'); else putchar(' ');
                if (x == maxx-1)  printf("\",\n");
              }
            } else {
              rc = sscanf(line, "%d,%d: (%d)"/*  #FFFFFF  gray(255)*/, &x, &y, &g);
              if (rc == 3) {
                if (debug_level >= 2) printf("x=%d y=%d: g=%d\n", x, y, g);
                if ((x >= maxx || x < 0) || (y >= maxy || y < 0)) {
                  // index out of range
                  if (debug_level >= 2) fprintf(stderr, "png2h: pixel (%d,%d) out of range (0:%d,0:%d):  %s\n\n", x,y, maxx-1,maxy-1, line);
                } else {
                  if (x == 0) printf("      \"");
                  if (g > THRESH) putchar('@'); else putchar(' ');
                  if (x == maxx-1)  printf("\",\n");
                }
              } else {
                exit(1);
              }
            }
          }
          
        }
        fclose(png);
        printf("      NULL,\n    },\n");
      }
    }
    printf("  },\n");
  }
  printf("};\n");
}
