/*
 *	Convert rasterfile to Postgres chunks.
 *	
 *	tom@izf.tno.nl
 *
 */


#include <stdio.h>
#include <malloc.h>

#include "rasterfile.h"

#define	CHUNK_X		32
#define	CHUNK_Y		32


double	atof();

typedef unsigned char	byte;

void	chunks_out();
void	map_colors();

char	*progname;
int	update;

#define round(x)	(((x)+1) & ~1)


main (argc, argv)

int	argc;
char	**argv;
{
  FILE 			*f;
  char 			*fname;
  char			*data;
  struct rasterfile	rf;
  long			im_len;
  long			col_len;
  char			*red, *green, *blue;
  double		xmin, xmax, ymin, ymax;
  char			*relname;

  progname= argv[0];

  if (argc > 8 || argc < 6) {
    fprintf(stderr, "Usage: %s [-u] xmin xmax ymin ymax relname [file]\n", progname);
    exit(1);
  }

  if (argv[1][0] == '-') {
    switch (argv[1][1]) {
    case 'u':
      update= 1;
      break;
    }

    argc--;
    argv++;
  }

  xmin= atof(argv[1]);
  xmax= atof(argv[2]);
  ymin= atof(argv[3]);
  ymax= atof(argv[4]);
  relname= argv[5];

  argc-= 5;
  argv+= 5;

  if (argc > 1) {
    fname= argv[1];
    if ((f= fopen(fname, "r")) == NULL) {
      perror(fname);
      exit(2);
    }
    argv++;
    argc--;
  } else {
    f= stdin;
    fname= "standard input";
  }

  if (fread(&rf, sizeof(rf), 1, f) != 1) {
    fprintf(stderr, "%s: Cannot read rasterfile header from %s\n",
      progname, fname);
    exit(3);
  }

  if (rf.ras_magic != RAS_MAGIC) {
    fprintf(stderr, "%s: Incorrect raster magic number in %s\n",
      progname, fname);
      exit(3);
  }

  if (rf.ras_depth != 8) {
    fprintf(stderr, "%s: Incorrect raster depth (%d != 8) in %s\n",
      progname, rf.ras_depth, fname);
      exit(4);
  }
  if (rf.ras_type != RT_STANDARD && rf.ras_type != RT_OLD) {
    fprintf(stderr, "%s: Incorrect raster type (%d) in %s\n",
      progname, rf.ras_type, fname);
      exit(4);
  }
  if (rf.ras_maptype != RMT_EQUAL_RGB) {
    fprintf(stderr, "%s: Incorrect raster maptype (%d) in %s\n",
      progname, rf.ras_maptype, fname);
      exit(4);
  }

  if (rf.ras_maplength > 3 * 256) {
    fprintf(stderr, "%s: Incorrect raster maplength (%d > 3 * 256) in %s\n",
      progname, rf.ras_maplength, fname);
      exit(4);
  }
  col_len= rf.ras_maplength / 3;

  if ((im_len= rf.ras_length) == 0)
    im_len= (round(rf.ras_width) * rf.ras_height * rf.ras_depth) / 8;

  fprintf(stderr, "x: %d (+%d)  y: %d (+%d)\n",
	rf.ras_width, rf.ras_width % CHUNK_X,
	rf.ras_height, rf.ras_height % CHUNK_Y);

  /* Correct ranges for non visible part: */
  xmax+= (xmax-xmin) / (rf.ras_width/CHUNK_X)
	* (rf.ras_width%CHUNK_X) / CHUNK_X;
#if 0
  ymax+= (ymax-ymin) / (rf.ras_height/CHUNK_Y)
	* (rf.ras_height%CHUNK_Y) / CHUNK_Y;
#else
  ymin-= (ymax-ymin) / (rf.ras_height/CHUNK_Y)
	* (rf.ras_height%CHUNK_Y) / CHUNK_Y;
#endif

  if (!(red= malloc(col_len))
     || !(green= malloc(col_len))
     || !(blue= malloc(col_len))
     || !(data= malloc(im_len))) {
       fprintf(stderr, "%s: Memory allocation problem\n", progname);
       exit(5);
  }

  if (fread(red, col_len, 1, f) != 1
     || fread(green, col_len, 1, f) != 1
     || fread(blue, col_len, 1, f) != 1) {
    fprintf(stderr, "%s: Incorrect color maps in %s\n",
      progname, fname);
      exit(4);
  }

  if (fread(data, im_len, 1, f) != 1) {
    fprintf(stderr, "%s: Incorrect data in %s\n",
      progname, fname);
      exit(4);
  }

  fprintf(stderr, "Nr colors: %d\n", col_len);
  map_colors(stdout, red, green, blue, data, im_len);

#if 0
  colors_out(stdout, col_len, red, green, blue);
#endif

  chunks_out(stdout, relname, data, rf.ras_width, rf.ras_height,
	xmin, xmax, ymin, ymax);

  exit(0);
}


#define	MAX_COL		64
#define	COL_OFFSET	32

void chunks_out(out, relname, data, width, height, xmin, xmax, ymin, ymax)

FILE	*out;
char	*relname;
byte	*data;
int	width;
int	height;

double	xmin, xmax, ymin, ymax;
{
  int		rwidth= round(width);

  double	xstep= (xmax-xmin) * CHUNK_X / width;
  double	ystep= (ymax-ymin) * CHUNK_Y / height;

  int		ximax= width / CHUNK_X;
  int		yimax= height / CHUNK_Y;

  double	x, y;
  int		xi, yi;

  register byte	*p;
  register int	pxi;
  register int	pyi;

  char		tmpname[1000];
  char		curdir[1000];
  FILE		*copy;

  getwd(curdir);

  sprintf(tmpname, "%s/copy%d", curdir, getpid());
  if (! (copy= fopen(tmpname, "w"))) {
    perror(tmpname);
    exit(10);
  }

  for (xi= 0, x= xmin; xi < ximax; x+= xstep, xi++) {
   for (yi= 0, y= ymax; yi < yimax; y-= ystep, yi++) {
#if 0
     fprintf(out, "append %s(sizex= %d, sizey= %d, ",
	relname, CHUNK_X, CHUNK_Y);
     fprintf(out, "area=\"(%f,%f,%f,%f)\", ",
       x+xstep, y, x, y-ystep);
     fprintf(out, "data=\"");
#else
     fprintf(copy, "%d\t%d\t(%f,%f,%f,%f)\t",
       CHUNK_X, CHUNK_Y, x+xstep, y, x, y-ystep);
#endif

     for (pyi= 0; pyi < CHUNK_Y; pyi++) {
      for (p= data + (yi*CHUNK_Y+pyi)*rwidth + xi*CHUNK_X, pxi= 0; 
         pxi < CHUNK_X; pxi++, p++) {
		int c= *p + COL_OFFSET;
		if (c >= MAX_COL + COL_OFFSET) {
		  fprintf(stderr, "%s: Bad color value: %d\n",
		    progname, c);
		  exit(10);
		}
#if 0
		if (c == '"' || c == '*') {
		  fputc('\\', out);
		  fputc('\\', out);
		} else if (c == '\\') {
		  fputc('\\', out);
		  fputc('\\', out);
		  fputc('\\', out);
		}
	 	fputc(c, out);
#else
		if (c == '\\')
		  fputc('\\', copy);
	 	fputc(c, copy);
#endif
      }
     }

#if 0
     fprintf(out, "\") \\g\n");
#else
     fputc('\n', copy);
#endif
   }
  }

#if 1
  fflush(copy);
  fprintf(out, "copy %s from \"%s\" \\g\n", relname, tmpname);
  fflush(out);
  /* unlink(tmpname); */
#endif
}



#define	COL_START	64
#define	N_COLS		256

void map_colors(out, red, green, blue, data, len)

FILE	*out;
byte	*red, *green, *blue;
byte	*data;
int	len;
{
  static int	mapping[N_COLS];
  int		nr_cols= 0;
  int		i;
  register byte	*p;

  for (i= 0; i < N_COLS; i++)
    mapping[i]= -1;

  for (p= data; len > 0; len--, p++) {
    if (mapping[*p] == -1)
      mapping[*p]= nr_cols++;
    *p= mapping[*p];
  }

  fprintf(stderr, "Nr of unique colors: %d\n", nr_cols);

  if (update)
	return;

  for (i= 0; i < nr_cols; i++) {
    int mapped_i;
    for (mapped_i= 0; mapping[mapped_i] != i; mapped_i++)
	;
    fprintf(out, "append geo_colors (colind= %d, red= %d, green= %d, blue= %d) \\g\n",
	COL_START+i, red[mapped_i], green[mapped_i], blue[mapped_i]);
  }
}
