#include <time.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <float.h>

# define FINITE	finite
# define ISNAN	isnan
# define QUIET_NAN	quiet_nan

#include "gpk_std.h"
#include "gpklib.h"	/* int2alloc and int2free */
#include "gpklib/image.h"
#include "gpklib/NaN.h"
#include "gpklib/innerloop4.h"
#include "gpklib/ieee754.h"

#define LARGESTIMAGE	2e8


PLAIN_C
void multi_image_destr(struct multi_image *tthis)
{
 int i;
 assert(tthis);
 assert(tthis->n_image >= 0);
 assert(multi_image_check(tthis));

 for(i=0;i<tthis->n_image;i++)
	image_destr(&tthis->image[i]);
 tthis->n_image = 0;
}



PLAIN_C
void multi_image_empty(struct multi_image *tthis)
{
 int i;
 assert(tthis);
 for(i=0;i<NPL;i++)  {
	image_empty(&tthis->image[i]);
	/* plot_empty(&tthis->plot[i]); */
	}
 tthis->n_image = 0;
}


PLAIN_C
void image_empty(struct image *tthis)
{
 assert(tthis);
 tthis->H = 0; tthis->h = 0;
 tthis->prop = 0;
 tthis->xscale = tthis->yscale = tthis->zscale = quiet_nan(0);
 tthis->nlines = tthis->npts = 0;
 tthis->zshift = tthis->xcenter = tthis->ycenter = quiet_nan(0);
 tthis->i_noise = 0.0;
 assert(image_check(tthis));
}


PLAIN_C
BOOL image_is_empty(C struct image *tthis)
{
	return tthis->H==0 && tthis->h==0 && tthis->prop==0
		&& tthis->npts==0 && tthis->nlines==0;
}


PLAIN_C
void multi_image_constr(struct multi_image *tthis, int n)
{
 int i;

 assert(tthis);
 assert(n > 0);

 tthis->n_image = n;
 for(i=0;i<tthis->n_image;i++)	{
	image_empty(&tthis->image[i]);
	/* plot_empty(&tthis->plot[i]); */
	}
}



PLAIN_C
void image_destr(struct image *tthis)
{
 assert(image_check(tthis));
 if(tthis->h)	{
 	short2free(tthis->h);
	tthis->h = 0;
	}
 if(tthis->H)	{
 	float2free(tthis->H);
 	tthis->H = 0;
 	}

 delete tthis->prop;

 image_empty(tthis);
}



PLAIN_C
BOOL multi_image_alloc(struct multi_image *tthis, int nlines, int npts)
{
 BOOL ok = TRUE;
 int i;

 for(i=0;i<tthis->n_image;i++)
	ok = ok && image_alloc(&tthis->image[i], nlines, npts);
 return ok;
}



PLAIN_C
BOOL multi_image_alloc_float(struct multi_image *tthis, int nlines, int npts)
{
 BOOL ok = TRUE;
 int i;

 for(i=0;i<tthis->n_image;i++)
	ok = ok && image_alloc_float(&tthis->image[i], nlines, npts);
 return ok;
}




PLAIN_C
BOOL image_alloc(struct image *tthis, int nlines, int npts)
{
 assert(tthis);
 assert(image_allocated(tthis));
 assert(!image_has_data(tthis));
 assert(nlines>=0 && npts>=0);
 if((double)nlines*(double)npts >= LARGESTIMAGE) {
	fprintf(stderr, "ERR: image.c: image_alloc: requested allocation(%dx%d) is unreasonably big.\n",
			nlines, npts);
	exit(1);
 }

 tthis->h = short2alloc(tthis->nlines = nlines, tthis->npts = npts);
 tthis->H = 0;
 if(!tthis->h)	{
	tthis->nlines = tthis->npts = 0;
	return FALSE;
 	}
 return TRUE;
}



PLAIN_C
BOOL image_alloc_float(struct image *tthis, int nlines, int npts)
{
 assert(tthis);
 assert(image_allocated(tthis));
 assert(!image_has_data(tthis));
 assert(nlines>=0 && npts>=0);
 assert((double)nlines*(double)npts < LARGESTIMAGE);

 tthis->H = float2alloc(tthis->nlines = nlines, tthis->npts = npts);
 tthis->h = 0;
 if(!tthis->H)	{
	tthis->nlines = tthis->npts = 0;
	return FALSE;
 	}
 return TRUE;
}



PLAIN_C
BOOL image_alloc_1(struct image *tthis, int nlines, int npts, short **d)
{
 assert(nlines<LARGESTIMAGE && npts<LARGESTIMAGE && nlines>=0 && npts>=0);
 if(d)	{
 	tthis->nlines = nlines;
 	tthis->npts = npts;
 	tthis->h = d;
 	}
else	{
	tthis->nlines = tthis->npts = 0;
	tthis->h = 0;
	}

 return d!=0;
}



PLAIN_C
void image_constr(struct image *tthis, int angle, double scale,
						C char *xyu, C char *imagetype)
{
 image_constr_all(tthis, 0.0, 0.0, scale, xyu, scale, xyu, imagetype);
 {
 char buf[100];
 sprintf(buf, "%d", angle);
 tthis->prop->add("angle", buf);
 }
}



PLAIN_C
void image_constr_all(struct image *tthis, double xc, double yc, double xs,
				C char *xu, double ys, C char *yu, C char * imagetype)
{
 image_empty(tthis);
 tthis->prop = new proplist;
 tthis->prop->add("type", imagetype);

 tthis->xscale = xs;
 tthis->yscale = ys;
 tthis->xcenter = xc;
 tthis->ycenter = yc;

 tthis->prop->add("xunits", xu);
 tthis->prop->add("yunits", yu);
 tthis->constr_time = time(0);
}



void image_constr_from(struct image *tthis, C struct image *source)
{
 assert(source);
 *tthis = *source;
 tthis->h = 0;
 tthis->H = 0;
 tthis->nlines = tthis->npts = 0;
 tthis->constr_time = time(0);
 tthis->prop = new proplist(*(source->prop));
}


PLAIN_C
void image_setzscale(struct image *tthis, double value, C char * units, double offset)
{
 tthis->zscale = value;
 tthis->zshift = offset;
 if(units)
	tthis->prop->add("zunits", units);
}



PLAIN_C
void image_addlabel(struct image *tthis, C char *label)
{
 assert(label);
 tthis->prop->add("label", label);
}



PLAIN_C
BOOL multi_image_allocated(C struct multi_image *tthis)
{
 int i;
 assert(tthis);

 if(tthis->n_image == 0)
 	return FALSE;

 for(i=0;i<tthis->n_image;i++)
 	if(!image_allocated(&tthis->image[i]))
		return FALSE;
 return TRUE;
}


PLAIN_C
BOOL image_has_data(C struct image *tt)
{
 if(tt->h || tt->H)
	return TRUE;
 return FALSE;
}


PLAIN_C
BOOL image_allocated(C struct image *tt)
{
 /* This image check can cause trouble when you are creating an
 image by hand (see gpkio/ascii_read.cc).  Because image_allocated()
 is called by image_alloc(), leaving this check call in prevents
 you from allocating an image that is missing a zscale or zshift. */
 /* assert(image_check(tt)); */
 if(image_is_empty(tt))
	return FALSE;
 return tt->prop ? TRUE : FALSE;
}


PLAIN_C
void multi_image_set_delay(struct multi_image *tthis, double delay)
{
 int i;
 char buf[100];
 sprintf(buf, "%g", delay);
 for(i=0;i<tthis->n_image;i++)
	tthis->image[i].prop->add("delay", buf);
}


PLAIN_C
void multi_image_set_time(struct multi_image *tthis, long t)
{
 int i;
 for(i=0;i<tthis->n_image;i++)
	image_set_time(&tthis->image[i], t);
}



PLAIN_C
void image_set_time(struct image *tthis, long t)
{
 tthis->constr_time = t;
}




PLAIN_C
void image_set_cur(struct image *tthis, double noise, double crrnt)
{
 char buf[100];
 tthis->i_noise = noise;
 sprintf(buf, "%g", crrnt);
 tthis->prop->add("current", buf);
}


PLAIN_C
void multi_image_set_cur(struct multi_image *tthis, double noise, double crrnt)
{
 int i;
 for(i=0;i<tthis->n_image;i++)
	image_set_cur(&tthis->image[i], noise, crrnt);
}



PLAIN_C
BOOL image_check(C struct image *p)
{
 int tmp;
 BOOL ok = TRUE;
 if(!p)	{
	fprintf(stderr, "#WARN: imagecheck:null ptr\n");
	ok = FALSE;
	}

 if(image_is_empty(p))
	return ok;

 if(!p->prop)	{
	fprintf(stderr, "#WARN: imagecheck: no property list.\n");
	ok = FALSE;
	}

 if(p->npts<0 || p->nlines<0)	{
	fprintf(stderr, "#WARN: imagecheck: bad size: %dx%d\n", p->nlines, p->npts);
	ok = FALSE;
	}

 if(p->h && p->H)	{
	fprintf(stderr, "#WARN: imagecheck: duplicate data.\n");
	ok = FALSE;
	}

 {
 struct alloc_size s;
 if(p->h)
 	s = short2size(p->h);
 else if(p->H)
 	s = float2size(p->H);
 else {
	s.rows = s.cols = 0;
 	}
 if((p->h || p->H) && (s.rows < p->nlines || s.cols < p->npts)) {
	fprintf(stderr,
		"#WARN: imagecheck: allocated space too small: (%dx%d) vs (%dx%d)\n",
		s.rows, s.cols, p->nlines, p->npts);
	ok = FALSE;
	}
 }

 if(p->h && (tmp=short2test(p->h))!=0)	{
	fprintf(stderr, "#WARN: imagecheck:h=%d\n", tmp);
	ok = FALSE;
	}

 if(p->H && (tmp=float2test(p->H))!=0)	{
	fprintf(stderr, "#WARN: imagecheck:H=%d\n", tmp);
	ok = FALSE;
	}


 if(!isnormal(p->zscale))	{
	fprintf(stderr, "#WARN: imagecheck:IEEE !normal(zscale): %f\n", p->zscale);
	ok = FALSE;
	}
 if(!finite(p->zshift))	{
	fprintf(stderr, "#WARN: imagecheck:IEEE !finite(zshift): %g\n", p->zshift);
	ok = FALSE;
	}
 if(!finite(p->i_noise))	{
	fprintf(stderr, "#WARN: imagecheck:IEEE !finite(i_noise): %g\n", p->i_noise);
	ok = FALSE;
	}
 if(p->zscale==0 || p->xscale==0 || p->yscale==0)	{
	fprintf(stderr, "#WARN: imagecheck: scale zero (%g,%g,%g)\n", p->xscale, p->yscale, p->zscale);
	ok = FALSE;
	}
 if(p->i_noise < 0) {
	fprintf(stderr, "#WARN: imagecheck:neg\n");
	ok = FALSE;
	}

 return ok;
}




PLAIN_C
BOOL multi_image_check(C struct multi_image *p)
{
 BOOL ok = TRUE;
 int i;
 if(!p)	{
	fprintf(stderr, "multi_imagecheck:bad ptr\n");
	ok = FALSE;
	}
 if(p->n_image < 0)	{
	fprintf(stderr, "multi_imagecheck:n_image<0\n");
	ok = FALSE;
	}
 else if(p->n_image > NPL)	{
	fprintf(stderr, "multi_imagecheck:n_image>NPL=%d\n", NPL);
	ok = FALSE;
	}
 for(i=0;i<p->n_image;i++)	{
	BOOL tmp = image_check(&(p->image[i]));
	if(!tmp)
		fprintf(stderr, "#INFO:failure on image %d of %d in multi_image_check()\n",
					i, p->n_image);
	ok = ok && tmp;
	}
 return ok;
}



BOOL multi_image_force_float(struct multi_image *p)
{
 int i;
 BOOL ok = TRUE;
 for(i=0;i<p->n_image;i++)
	ok = ok && image_force_float(&p->image[i]);
 return ok;
}



BOOL multi_image_force_short(struct multi_image *p)
{
 int i;
 BOOL ok = TRUE;
 for(i=0;i<p->n_image;i++)
	ok = ok && image_force_short(&p->image[i]);
 return ok;
}



BOOL image_force_float(struct image *p)
{
 assert(image_check(p));
 assert(image_allocated(p));

 if(!image_has_data(p))
	return TRUE;
 if(p->H)
	return TRUE;

 p->H = float2alloc(p->nlines, p->npts);
 assert(p->H);
 {
 C static float qn = QUIET_NAN(0);
 int i;
 /* OPENMP(omp parallel for collapse(2)) */
 OPENMP(omp parallel for schedule(guided, 64))
 for(i=0; i<p->nlines; i++)	{
	C short *x = p->h[i];
	float *xf = p->H[i];
	int j;
	OPENMP(omp parallel for schedule(guided, 256))
	for(j=0; j<p->npts; j++)
		xf[j] = x[j]!=SHRT_NAN ? x[j] : qn;
	/* INNERLOOP(j, 0, p->npts, xf[j] = x[j]!=SHRT_NAN ? x[j] : qn); */
	}
 short2free(p->h);
 p->h = 0;
 }
 assert(image_check(p));
 return TRUE;
}



BOOL image_force_short(struct image *p)
{
 assert(image_check(p));
 assert(image_allocated(p));

 if(!image_has_data(p))
	return TRUE;
 if(p->h)
	return TRUE;

 p->h = short2alloc(p->nlines, p->npts);
 assert(p->h);
 {
 float min = -infinity();
 float max = infinity();
 int i;
 C int np = p->npts;
 /* Map infinity into NaN. */
 /* OPENMP(omp parallel for private(i) collapse(2)) */
 OPENMP(omp parallel for private(i) schedule(guided, 32))
 for(i=0; i < p->nlines; i++)	{
	int j;
	C float *H = p->H[i];
	OPENMP(omp parallel for private(i) schedule(guided, 256))
	for(j=0; j<np; j++)	{
		OPENMP(omp critical(image_force_short_min))
		if(H[j]<min && FINITE(H[j]))	min = H[j];
		OPENMP(omp critical(image_force_short_max))
		if(H[j]>max && FINITE(H[j]))	max = H[j];
		}
	}
 C float scale = ((double)SHRT_Max-(double)SHRT_Min)/(max-min);
 /* OPENMP(omp parallel for collapse(2) private(i)) */
 OPENMP(omp parallel for private(i) schedule(guided, 4))
 for(i=0; i<p->nlines; i++)	{
	C float *H = p->H[i];
	short *h = p->h[i];
	int j;
 	OPENMP(omp parallel for private(i) schedule(guided, 128))
	for(j=0; j<np; j++)
		h[j] = roundS((H[j]-min)*scale+SHRT_Min);
	}
 p->zscale /= scale;
 p->i_noise = hypot(p->i_noise, 1/sqrt(12.0))/scale;
 p->zshift += min*scale*p->zscale - SHRT_Min*p->zscale;
 float2free(p->H);
 p->H = 0;
 }
 assert(image_check(p));
 return TRUE;
}




struct image image_copy(C struct image& in)
{
 return image_gcopy(in, 0, 0, in.nlines, in.npts, quiet_nan(0));
}



static int min(int a, int b) { return a<b ? a : b; }

static int max(int a, int b) { return a>b ? a : b; }



struct image image_gcopy(C struct image& in, int l0, int p0, int l1, int p1,
							float value)
{
 struct image rv;
 assert(image_check(&in));
 assert(l1>=l0 && p1>=p0);

 image_constr_from(&rv, &in);
 BOOL ok = in.h ? image_alloc(&rv, l1-l0, p1-p0)
				: image_alloc_float(&rv, l1-l0, p1-p0);
 assert(ok);
 assert(image_check(&rv));
 rv.xcenter = in.xcenter + 0.5*((p1+p0)-(0+in.npts))*in.xscale;
 rv.ycenter = in.ycenter + 0.5*((l1+l0)-(0+in.nlines))*in.yscale;
 assert(image_check(&rv));

 short *tmph = 0;
 float *tmpH = 0;


 if(l0<0 || l1>=in.nlines || p0<0 || p1>=in.npts)	{
	if(in.h)	{
		C short ivalue = roundS((value-rv.zshift)/rv.zscale);
		tmph = short1alloc(rv.npts);
		assert(tmph);
		int i;
		for(i=0; i<rv.npts; i++)
			tmph[i] = ivalue;
		}
	if(in.H)	{
		tmpH = float1alloc(rv.npts);
		assert(tmpH);
		int i;
		for(i=0; i<rv.npts; i++)
			tmpH[i] = value;
		}
	}

 assert(image_check(&rv));
 assert(image_check(&in));

 int i;
 C int p0p = max(p0, 0);
 assert(p0p >= 0);
 C int p0n = -min(p0, 0);
 assert(p0n >= 0);
 C int np = min(p1, in.npts) - p0p;
 C int fstart = p0n + np;
 C int nf = rv.npts - fstart;
 /* We copy in reverse order to improve processor cache hit rates.   We assume that most
  functions work the image in forward order, so that the end of the image (largest line index)
  is most likely to be in the processor cache.   We then use that first, before it gets flushed. */
 for(i=rv.nlines-1; i>=0; i--)	{
	if(i+l0<0 || i+l0>=in.nlines)	{
		if(rv.h)
			memmove(rv.h[i], tmph, rv.npts*sizeof(**in.h));
		else
			memmove(rv.H[i], tmpH, rv.npts*sizeof(**in.H));
		}
	else if(np > 0)	{
		if(rv.h)	{
			if(p0n > 0)	{
				assert(p0n <= rv.npts);
				memmove(rv.h[i], tmph, p0n*sizeof(**in.h));
				}
			assert(np+p0p <= in.npts  && np+p0n<=rv.npts);
			assert(p0n>=0 && p0p>=0);
			memmove(&rv.h[i][p0n], &in.h[i+l0][p0p], np*sizeof(**in.h));
			if(nf > 0)	{
				assert(fstart>=0 && fstart+nf <= rv.npts);
				memmove(&rv.h[i][fstart], tmph, nf*sizeof(**in.h));
				}
			}
		else	{
			if(p0n > 0)	{
				assert(p0n <= rv.npts);
				memmove(rv.H[i], tmpH, p0n*sizeof(**in.H));
				}
			assert(np+p0p <= in.npts  && np+p0n<=rv.npts);
			assert(p0n>=0 && p0p>=0);
			memmove(&rv.H[i][p0n], &in.H[i+l0][p0p], np*sizeof(**in.H));
			if(nf > 0)	{
				assert(fstart>=0 && fstart+nf <= rv.npts);
				memmove(&rv.H[i][fstart], tmpH, nf*sizeof(**in.H));
				}
			}
		}
	}
 assert(image_check(&in));
 assert(image_check(&rv));

 if(tmph)
	short1free(tmph);
 if(tmpH)
	float1free(tmpH);
 assert(image_check(&rv));
 return rv;
}




struct image image_copy_short(C struct image& in)
{
 struct image rv = image_copy(in);
 image_force_short(&rv);
 return rv;
}




struct image image_copy_float(C struct image& in)
{
 struct image rv = image_copy(in);
 image_force_float(&rv);
 return rv;
}



/* This produces an image with a central delta-function. */
struct image delta_fcn_float(int nl, int np)
{
 struct image rv;
 assert(nl>0 and np>0);
 assert(nl%2==1 && np%2==1);
 image_constr_all(&rv,
			0.5*(np-1) - (np-1)/2,
			0.5*(nl-1) - (nl-1)/2,
			1.0, "", 1.0, "",
			"Psf");

 BOOL ok = image_alloc_float(&rv, nl, np);
 assert(ok);
 rv.zscale = 1;
 rv.zshift = 0.0;
 image_set(&rv, 0.0);
 rv.H[(nl-1)/2][(np-1)/2] = 1.0;
 assert(image_check(&rv));
 return rv;
}



/* This produces an image with a central delta-function. */
struct image delta_fcn(int nl, int np)
{
 struct image rv;
 assert(nl>0 and np>0);
 assert(nl%2==1 && np%2==1);
 image_constr_all(&rv,
			0.5*(np-1) - (np-1)/2,
			0.5*(nl-1) - (nl-1)/2,
			1.0, "", 1.0, "",
			"Psf");
 BOOL ok = image_alloc(&rv, nl, np);
 assert(ok);
 rv.zscale = 0.001;
 rv.zshift = 0.0;
 image_set(&rv, 0.0);
 rv.h[(nl-1)/2][(np-1)/2] = 1000;
 assert(image_check(&rv));
 return rv;
}


void multi_image_set(struct multi_image *tthis, float val)
{
 assert(tthis);
 int i;
 for(i=0;i<tthis->n_image;i++)
	image_set(&tthis->image[i], val);
}


void image_set(struct image *tthis, float val)
{
 assert(tthis);
 if(tthis->h)
	short2set(tthis->h, 0);
 else
	float2set(tthis->H, 0);

 tthis->i_noise = 0.0;
 tthis->zshift = val;
 tthis->zscale = 1.0;
}


BOOL multi_image_normalize(struct multi_image *a)
{
 int i;
 BOOL ok = TRUE;
 for(i=0;i<a->n_image;i++)
	ok = ok && image_normalize(&a->image[i]);
 return ok;
}


BOOL image_normalize(struct image *a)
{
 int i;
 if(a->h) {
	BOOL ok = image_force_float(a);
	assert(ok);
	}

 if(a->zshift<=DBL_MIN && a->zshift>=-DBL_MIN
		&& a->zscale-1<=DBL_EPSILON
		&& a->zscale-1>=-DBL_EPSILON) {
	return TRUE;
	}

 C int np = a->npts;
 C float sc = a->zscale;
 C float sh = a->zshift;
 /* OPENMP(omp parallel for private(i,j,p) collapse(2)) */
 OPENMP(omp parallel for schedule(guided, 32))
 for(i=0; i<a->nlines; i++) {
	float *p = a->H[i];
	int j;
	OPENMP(omp parallel for schedule(guided, 32))
	for(j=0; j<np; j++)
		p[j] = p[j]*sc + sh;
	}

 a->i_noise /= fabs(a->zscale);
 a->zscale = 1.0;
 a->zshift = 0.0;

 return TRUE;
}




void image_insert(struct image *bkgr, C struct image *insert, int l0, int p0)
{
 C int l = max(0, l0);
 C int p = max(0, p0);
 C int le = min(l0+insert->nlines, bkgr->nlines);
 C int pe = min(p0+insert->npts, bkgr->npts);
 C float bsc = bkgr->zscale;
 C float bsh = bkgr->zshift;
 C float isc = insert->zscale;
 C float ish = insert->zshift;

 C float sc = isc/bsc;
 C float sh = ish/bsc - bsh;

 fprintf(stderr, "inserting type=%s sz=%dl x %dp into\n", insert->H?"H":"h",
			insert->nlines, insert->npts);
 fprintf(stderr, "at (%d,%d) onto type=%s sz=(%dl, %dp)\n",
			l0, p0,
			bkgr->H ? "H" :"h",
			bkgr->nlines, bkgr->npts);
 fprintf(stderr, "l=%d, p=%d, nl=%d, np=%d, sc=%g, sh=%g\n",
			l, p, le-l, pe-p, sc, sh);

 int i;
 if(bkgr->H && insert->H)
	for(i=le-1; i>=l; i--)	{
		float *b = bkgr->H[i];
		C float *in = insert->H[i-l0];
		INNERLOOP(j, p, pe, b[j] = in[j-p0]*sc + sh);
		}
 else if(bkgr->h && insert->h)
	for(i=le-1; i>=l; i--)	{
		short *b = bkgr->h[i];
		C short *in = insert->h[i-l0];
		INNERLOOP(j, p, pe, b[j] = in[j]==SHRT_NAN ? SHRT_NAN : roundS(in[j-p0]*sc + sh));
		}
 else if(bkgr->H && insert->h)
	for(i=le-1; i>=l; i--)	{
		float *b = bkgr->H[i];
		C short *in = insert->h[i-l0];
		C float qn = QUIET_NAN(0);
		INNERLOOP(j, p, pe, b[j] = in[j]==SHRT_NAN ? qn : in[j-p0]*sc + sh);
		}
 else if(bkgr->h && insert->H)
	for(i=le-1; i>=l; i--)	{
		short *b = bkgr->h[i];
		C float *in = insert->H[i-l0];
		INNERLOOP(j, p, pe, b[j] = roundS(in[j-p0]*sc + sh));
		}
}

static C char *Tpre[] = {"TTYPE", "TRANGE", "TUNIT", 0};

static BOOL clear_TT(image *o, int c)
{
	char buf[100];
	int i;
	BOOL cleared = FALSE;
	for(i=0; Tpre[i]; i++) {
		sprintf(buf, "%s%d", Tpre[i], c+1);
		if(o->prop->get(buf)) {
			o->prop->add(buf, (char *)0);
			cleared = TRUE;
		}
	}
	return cleared;
	
}

void image_clear_TT(image *o)
{
	int i, c=1;
	for(i=0; i<o->npts || c>0; i++)
		c += 2*clear_TT(o, i) - 1;
}


void image_xfer_TT(image *to, C image& from, int to_col, int from_col)
{
	char f[100], t[100];
	int i;
	if(to_col < 0)
		return;
	if(from_col < 0)
		return;

	if(to_col >= to->npts)
		fprintf(stderr, "WARN: image.c: image_xfer_TT: adding TTYPE%d on a file with %d columns.\n",
			to_col+1, to->npts);

	for(i=0; Tpre[i]; i++) {
		sprintf(f, "%s%d", Tpre[i], from_col+1);
		sprintf(t, "%s%d", Tpre[i], to_col+1);
		property *x = from.prop->get(f);
		if(x)
			to->prop->add(t, x->val, x->comment);
		else if(to->prop->get(t))
			to->prop->add(t, (char *)0);
	}
}


int image_lookup_TTYPE(C struct image &dd, C char *scol)
{
	int i;
	char buf[100];
	if(!scol)
		return -1;

	for(i=0; i<dd.npts; i++) {
		sprintf(buf, "TTYPE%d", i+1);
		if(strcmp(scol, dd.prop->gets(buf, "")) == 0)
			return i;
	}
	C int col = safe_atoi(scol);
	if(col != INT_NAN && col>=0 && col<dd.npts)
		return col;
	return -1;
}


