// cc -o grid2html grid2html.c  -lnetpbm -lm
// ./grid2html grid/AW-031@400,662@260,558.png > grid/AW-031.html

// This program takes an image which has already been aligned with the
// horizontal axis, using 'deskew', and a given line and character
// spacing in x and y, and determines the x and y starting offset that
// aligns the grid as best as possible between lines and characters.
//
// This is specifically for images of fixed-pitch/fixed character width
// printouts such as old listings of computer printouts.
// Actual segmentation is performed by 'makegrid' (or 'grid2html', in
// the early stages of development)

// alternative to text area below is to use javascript to create tooltips
// - suitable code can be found at https://timseverien.github.io/taggd/v3/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <netpbm/pnm.h>
#include <netpbm/shhopt.h>


#ifndef FALSE
#define FALSE (0 != 0)
#endif
#ifndef TRUE
#define TRUE (0 == 0)
#endif

struct cmdline_info {
  const char *infilename; /* Filespec of input file */
  char *basename;
  unsigned int help, verbose;
};

FILE *ifp;
int rows, cols, format;
int row;

struct cmdline_info cmdline;

static void parse_command_line(int argc, char **argv,
                               struct cmdline_info *cmdlineP) {
  optStruct3 opt;
  unsigned int option_def_index = 0;
  optEntry *option_def = malloc(100 * sizeof(optEntry));

  opt.opt_table = option_def;
  opt.short_allowed = FALSE;
  opt.allowNegNum = TRUE;

  cmdlineP->verbose = FALSE;
  cmdlineP->help = FALSE;

  OPTENT3('h', "help",    OPT_FLAG,   NULL, &cmdlineP->help, 0);
  OPTENT3(  0, "info",    OPT_FLAG,   NULL, &cmdlineP->help, 0);
  OPTENT3('v', "verbose", OPT_FLAG,   NULL, &cmdlineP->verbose, 0);

  pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
  {
    char *p;
    cmdlineP->infilename = argv[1];
    if ((p = strrchr(argv[1], '/')) != NULL) {
      cmdlineP->basename = strdup(p + 1);
    } else {
      cmdlineP->basename = strdup(argv[1]);
    }
    if ((p = strrchr(cmdlineP->basename, '.')) != NULL) *p = '\0';

    if (argc > 2) {
      pm_error("too many arguments (%d).  "
               "The only positional argument is the filespec.",
               argc - 1);
    }
    if (cmdlineP->verbose)
      fprintf(stderr, "Processing %s\n", cmdlineP->infilename);
  }
}

static inline int iround(float num) {
  return (num - floor(num) > 0.5) ? ceil(num) : floor(num);
}

void read_image_size(int *maxx, int *maxy) {
  /* Read a bitmap, return its size;
     Numbers are inclusive, ie bounds are 0:maxx-1, 0:maxy-1 */
  unsigned int maxval;
  int format;
  ifp = pm_openr(cmdline.infilename);

  pnm_readpnminit(ifp, &cols, &rows, &maxval, &format);
  *maxx = cols;
  *maxy = rows;
}

int main(int argc, char **argv) {
  static char fname[1024];
  int maxx, maxy;
  int xstep, ystep, xoff, yoff; // in 10ths of a pixel

  pnm_init(&argc, argv);
  parse_command_line(argc, argv, &cmdline);

  if (cmdline.help) {
    fprintf(stderr, "syntax: grid2html [options] filename.png\n\n");
    exit(EXIT_SUCCESS);
  }

  // convert grid/AW-031@400,662@260,558.png AW-031@400,662@260,558.pnm ; ./grid2html grid/AW-031@400,662@260,558.png > grid/AW-031.html
  // UPDATE: Since getlines was changed from .1 spacing to .01 spacing,
  //         filenames like LA-000@3980,6650@580,2250.png must be interpreted differently...
  char *s = strchr(cmdline.infilename, '@');
  if (!s || sscanf(s, "@%d,%d@%d,%d.", &xstep, &ystep, &xoff, &yoff) != 4) {
    fprintf(stderr, "File parameter should be of the format pagename@x,y@dx,dy.pnm as generated by other tools in this suite.\n");
    fprintf(stderr, "  try something like: convert grid/AW-031@400,662@260,558.png AW-031@400,662@260,558.pnm ; ./grid2html AW-031@400,662@260,558.pnm\n");
    exit(EXIT_FAILURE);
  }
  strcpy(fname, cmdline.infilename);
  s = strrchr(fname, '@');
  if (s) {
    *s = '\0';
    s = strrchr(fname, '@');
    if (s) *s = '\0'; else s = fname;
  } else s = fname;
  s = strrchr(s, '/');
  if (s) {
    memmove(/*dest*/fname, /*source*/s+1, strlen(s+1)+1); // overlapping move is allowed with memmove
  }
  read_image_size(&maxx, &maxy);
  pm_close(ifp);

  if (cmdline.verbose) {
    fprintf(stderr, "Using top-left corner at %d,%d pixels and characters of roughly %dx%d pixels.\n", xoff/100,yoff/100, (xstep+5)/100,(ystep+5)/100);
  }

  // ============================================================================================================

  static char imgname[1024];
  sprintf(imgname, "%s", cmdline.infilename);
  s = strrchr(imgname, '.');
  if (s) sprintf(s, ".png");
  
  fprintf(stdout, "  <html>\n");
  fprintf(stdout, "    <head><title>%s</title></head>\n", fname);
  fprintf(stdout, "    <body>\n");
  fprintf(stdout, "      <img src=\"%s\" alt=\"%s\" usemap=\"#%s-map\">\n", imgname, fname, fname);
  fprintf(stdout, "      <map name=\"%s-map\">\n", fname);
  int y = yoff;
  int lines = 1;
  for (;;) {
    int truncy = (y+5) / 100;
    int x = xoff;
    cols = 1;
    for (;;) {
      int truncx = (x+5) / 100;
      //fprintf(stdout, "        <!--                                                Need a cgi here to allow the letter to be entered -->\n");
      fprintf(stdout, "        <area shape=\"rect\" coords=\"%d,%d,%d,%d\" alt=\"line %d column %d\" href=\"../tiles/%s/line%03d/col%03d.png\">\n",
              truncx,truncy,
              (x+xstep+5)/100-1,(y+ystep+5)/100-1,
              lines,cols,
              fname,
              lines,cols
              );
      //fprintf(stdout, "        <!-- repeat for every char. Or maybe use a cgi and calculate square on host from pixel co-ordinates. -->\n");
      cols += 1;
      x += xstep;
      if (x / 100 >= maxx) break;
    }
    lines += 1;
    y += ystep;
    if (y / 100 >= maxy) break;
  }

  fprintf(stdout, "      </map>\n");
  fprintf(stdout, "    </body>\n");
  fprintf(stdout, "  </html>\n");

  exit(EXIT_SUCCESS);
  return EXIT_FAILURE;
}
