/*
TO DO:

this code doesn't understand colour images.  It treats an RGB file as a B/W file, with the high order byte
being the brightest white, so blue (x<<16) will always take precedence over green (x<<8), and both of those
take precedence over red (x<<0).

To fix this, the initial picture load needs to convert r/g/b to a grey value.  This depends on gamuts
and is not a simple averaging.

It should still be possible to treat r/g/b seperately (just don't shift them) but slightly more
complex to handle combinations of 2 colours.

 */


#include "imatrix.h"
#include "ETF.h"
#include "myvec.h"
#include "fdog.h"

#ifdef DEMO
#include "lena.h"
#else
#include <assert.h>
#endif

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

int debug = 0;

extern FILE *popen(const char *command, const char *type);
extern int pclose(FILE *stream);

/* It's easy enough to change back to using malloc (just find 'claim' and replace with 'malloc')
   but using this Pascal-style mark/release scheme is far more efficient than using a heap manager. */
#include "stackmem.h"

#ifdef MEMDEBUG
/* compiling with -DMEMDEBUG adds a layer over malloc/free to keep track of heap leaks.
   Currently we do not cleanly free the memory we use unless the claim/release code is used (and
   then it's just one single malloc, so it's easy to keep track of).
   This code also catches writes past the end of an array, and already caught one real bug. */ 
#include "mnemosyne.h"
#endif

int main (int argc, char *argv[]) 
{
#define R 1
#define G 2
#define B 4
  int channel = 0;
  int width, height;
  int row, col;
  int image_x;
  int image_y;
  double tao;
  double thres;
  ETF *e;
  imatrix *img;
  int r, g, b;

#ifdef MEMDEBUG
  mnem_init(argv[0]);
#endif

#ifndef DEMO

  for (;;) {
    if (argc < 2) {
      fprintf(stderr, "syntax: draw [-h] [-d] [-r|-g|-b]  imagefile\n");
      exit(1);
    }
    if (*argv[1] == '-') {
      /* handle_option argv[1] */
      if (strcmp(argv[1], "-h") == 0) {
        fprintf(stdout, "syntax: draw [-h] [-d] [-rgb]  Imagefile\n");
        fprintf(stdout, "\n");
        fprintf(stdout, "        -h  This help information\n");
        fprintf(stdout, "        -d  Turn on debugging to compare C vs C++ implementations\n");
        fprintf(stdout, "        -r  Use the red channel from the image\n");
        fprintf(stdout, "        -g  Use the green channel from the image\n");
        fprintf(stdout, "        -b  Use the blue channel from the image\n");
        fprintf(stdout, "\n");
        fprintf(stdout, "Note that the ImageMagick 'convert' command must be installed\n");
        fprintf(stdout, "and in the path.");
        fprintf(stdout, "\n");
        fprintf(stdout, "Imagefile may be any format that 'convert' supports, including jpg/gif/png.\n");
        fprintf(stdout, "\n");
        fprintf(stdout, "Output will be in 'convert's text format, and can be converted into\n");
        fprintf(stdout, "a graphics file by piping this through '| convert - outfile.jpg'\n");
        fprintf(stdout, "\n");
        exit(0);
      } else if (strcmp(argv[1], "-r") == 0) { channel |= R;
      } else if (strcmp(argv[1], "-g") == 0) { channel |= G;
      } else if (strcmp(argv[1], "-b") == 0) { channel |= B;
      } else if (strcmp(argv[1], "-rg") == 0 || strcmp(argv[1], "-gr") == 0) { channel |= R|G;
      } else if (strcmp(argv[1], "-rb") == 0 || strcmp(argv[1], "-br") == 0) { channel |= R|B;
      } else if (strcmp(argv[1], "-gb") == 0 || strcmp(argv[1], "-bg") == 0) { channel |= G|B;
      } else if (strcmp(argv[1], "-rgb") == 0) { channel = R|G|B;
      } else {
        fprintf(stderr, "draw: unknown option %s\n", argv[1]);
        exit(1);
      }
      argv += 1; argc -= 1;
      continue;
    } else if (argc == 2) {
      /* image file is argv[1] */
      break;
    } else if (*argv[2] == '-') {
      /* options must precede parameters */
      fprintf(stderr, "draw: options such as '%s' must come before the imagefile parameter '%s'\n", argv[2], argv[1]);
      exit(1);
    } else {
      /* only one parameter */
      fprintf(stderr, "draw: unexpected parameter %s\n", argv[2]);
      exit(1);
    }
  }

  {
    int maxval, x, y;
    char command[1024];
    char rgb[1024], junk1[1024], junk2[1024];
    FILE *imageFile, *test;
    int image_biggest;
    int rc;

    test = fopen(argv[1], "rb");
    if (test == NULL) {
      fprintf(stderr, "draw: cannot open %s\n", argv[1]);
      exit(2);
    } else fclose(test);

    sprintf(command, "convert \"%s\" txt:-", argv[1]); /* external script must ensure this is a clean filename,
							  i.e. a locally-generated one and not one entered by
                                                          some random web user... - beware injection attacks.
                                                          Also we assume we trust the output of convert. */
    imageFile = (FILE *)popen(command, "r");
    if (imageFile == NULL) {
      fprintf(stderr, "draw: cannot open %s - is the ImageMagick 'convert' command installed?\n", argv[1]);
      exit(4);
    }
    rc = fscanf(imageFile, "# ImageMagick pixel enumeration: %d,%d,%d,%s\n", &width, &height, &maxval, rgb);
    if (rc != 4) {
      fprintf(stderr, "draw: cannot open %s - is the ImageMagick 'convert' command installed properly?\n", argv[1]);
      exit(5);
    }
    image_biggest = width > height ? width : height;
    img = imatrix_new(/*height, width*/image_biggest, image_biggest); /* line-finding code seems to need a square matrix */

    if (debug) fprintf(stderr, "Loading a %dx%d %s image from %s (rather slowly)\n", width, height, rgb, argv[1]);
    assert(rgb[0] == 'r' && rgb[1] == 'g' && rgb[2] == 'b' && rgb[3] == '\0');
    /* Load input image into an imatrix named "img".
       Reading the text output from the ImageMagick 'convert' command is a slow
       way to read a graphics file but it's reasonably portable, and easier to
       install than the ImageMagick API/library */
    for (row = 0; row < height; row++) {
      for (col = 0; col < width; col++) {
        img->p[row][col] = 0;
      }
    }
    for (;;) {
      rc = fscanf(imageFile, "%d,%d: (%d,%d,%d)  #%s  %s\n", &x, &y, &r, &g, &b, junk1, junk2);
      if (rc != 7) break;
      assert(x < width); assert(y < height);
      /* Then, add together 30% of the red value, 59% of the green value, and 11% of the blue value */
      if (channel==0) img->p[y][x] = (r*30+g*59+b*11)/100; /* TEMPORARY QUICK HACK */
      if (channel==B) img->p[y][x] = (b&255);
      if (channel==G) img->p[y][x] = (g&255);
      if (channel==R) img->p[y][x] = (r&255);
    }
    pclose(imageFile);  
    if (debug) fprintf(stderr, "Image loaded.\n");
  
    if (width == 0 || height == 0) {
      fprintf(stderr, "draw: bad image in %s\n", argv[1]);
      exit(3);
    }
  
  }

#else

  img = imatrix_new(width = LENA_W, height = LENA_H);

  /* Load input image into an imatrix named "img" */
  for (row = 0; row < LENA_H; row++) {
    for (col = 0; col < LENA_W; col++) {
      r = lena[col*LENA_W + row]&255;
      g = (lena[col*LENA_W + row]>>8)&255;
      b = (lena[col*LENA_W + row]>>16)&255;
      if (channel==0) img->p[col][row] = (r+g+b)/3; /* TEMPORARY QUICK HACK */
      if (channel==B) img->p[col][row] = (b&255);
      if (channel==G) img->p[col][row] = (g&255);
      if (channel==R) img->p[col][row] = (r&255);
    }
  }

#endif

  image_x = imatrix_getRow (img);
  image_y = imatrix_getCol (img);
  
  /* //////////////////////////////////////////// */
  if (debug) fprintf(stderr, "img(%dx%d): %d\n", image_x, image_y, imatrix_crc(img));    
  /* //////////////////////////////////////////// */
  e = New_ETF(image_x, image_y);
  
  /*set(img);*/                 /* get gradients from input image */
  if (debug) fprintf(stderr, "before set2: e %f\n", ETF_crc(e));
  set2 (e, img);		/* get gradients from gradient map */
  if (debug) fprintf(stderr, "e returned from set2 = %f\n", ETF_crc(e));
  Smooth (e, 4, 2);
  if (debug) fprintf(stderr, "after Smooth: e %f\n", ETF_crc(e));
  
  /* //////////////////////////////////////////////// */
    
  /* ///////////////////////////////////////////// */
  tao = 0.99;
  thres = 0.7;
  GetFDoG (img, e, 1.0, 3.0, tao);
  if (debug) fprintf(stderr, "post GetFDog img: %d\n", imatrix_crc(img));
  GrayThresholding (img, thres);
  if (debug) fprintf(stderr, "post GrayThresholding img: %d\n", imatrix_crc(img));
  fprintf(stdout, "# ImageMagick pixel enumeration: %d,%d,255,rgb\n", width, height);

  for (row = 0; row < height; row++) {
    for (col = 0; col < width; col++) {
      /* mod 1 = no grey in output */
      r = (img->p[row][col] >> 16) & 255; g = (img->p[row][col] >> 8) & 255; b = img->p[row][col] & 255;
      /*if (b == 255) {*/
        fprintf(stdout, "%d,%d: (%d,%d,%d) #\n", col, row, b, b, b);
      /*} else {*/
        /*fprintf(stdout, "%d,%d: (0,0,%d)\n", col, row, img->p[row][col]);*/
      /*}*/
    }
  }

  release(NULL); /* free all memory */
  
  /* /////////////////////////////////////// */
  exit(0);
  return 0;
}