/*****************************************************************************

				FOCAS_WRITE.C
				Writes Tyson FOCAS format 2-dimensional image files.

Copyright (C) 2002 Greg Kochanski, gpk@pribble.com .

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*****************************************************************************/

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

#include "gpk_std.h"
#include "gpklib.h"
#include "gpklib/assert.h"
#include "rbfile.h"
#include "internals.h"

#include "gpklib/ieee754.h"
# define FINITE	finite
# define ISNAN	isnan
# define FABS	fabs
#include "gpklib.h"
#include "gpklib/NaN.h"
#include "gpklib/image.h"
#include "rw_misc.h"

#define D if(0)


LOCAL void write_focas_short(short a, FILE *fp)
{
	putc(((unsigned)a>>8)&0377, fp);
	putc((unsigned)a&0377, fp);
}

typedef int fourbyte;
#define FOURBYTE_NAN	INT_NAN
#define FOURBYTE_Max	INT_Max
#define FOURBYTE_Min	INT_Min


LOCAL void write_focas_fourbyte(fourbyte a, FILE *fp)
{
	C fourbyte ah = a>>16;
	putc((ah>>8)&0377, fp);
	putc(ah&0377, fp);
	putc((a>>8)&0377, fp);
	putc(a&0377, fp);
}


LOCAL void write_focas_float(float a, FILE *fp)
{
	float aa = a;
	assert(sizeof(aa)==4);
	fwrite((char *)&aa, 1, sizeof(aa), fp);
}



LOCAL void putsl(const char *s, int n, FILE *f, BOOL merge)
{
	int i;
	for(i=0; s && *s && i<n; i++, s++)	{
		if(!merge && (*s == '\n' || *s=='\r'))
			putc('\0', f);
		else
			putc(*s, f);
	}
	for(; i<n; i++)
		putc(0, f);
}


LOCAL void putprop(const proplist*x, const char *prop, int n, FILE *f, BOOL merge=FALSE)
{
	putsl(x->gets(prop), n, f, merge);
}


BOOL focas_writefile(C struct image *p, FILE *Out, C proplist& control)
{

 assert(p->prop);
 proplist q(*p->prop);
 normalize_proplist(&q, p);
 q += control;
 int bitpix = q.geti("BITPIX", -32);
 if(bitpix == 0)	{
	q.add("BITPIX", -32);
	bitpix = q.geti("BITPIX", -32);
	}

 double bscale, bzero, rawmin, rawmax;
 scale_image_for_bitpix(p, bitpix, &bscale, &bzero, &rawmin, &rawmax, &q, TRUE);

	assert(sizeof(fourbyte)==4);
	assert(FOURBYTE_NAN == (sizeof(int)==4 ? INT_NAN : LONG_NAN));

	fourbyte blank;
	if(bitpix == 32)
		blank = FOURBYTE_NAN;
	else if(bitpix == 16)
		blank = SHRT_NAN;
	else if(bitpix == 8)
		blank = SCHAR_NAN;
	else	blank = 0;	/* Will not be used. */


	write_focas_short(0, Out); /* blksiz */
	write_focas_short(bitpix, Out); /* bitpix */
	write_focas_short(2, Out); /* naxis */
	write_focas_short(p->npts, Out);
	write_focas_short(p->nlines, Out);
	write_focas_short(0, Out); /* dflags */
	write_focas_short(0, Out); /* maptyp */
	write_focas_short(0, Out); /* bunit */
	write_focas_short(0, Out); /* ctype1 */
	write_focas_short(0, Out); /* ctype2 */
	if(bitpix == 32)	{
		write_focas_fourbyte(roundL(rawmax), Out);
		write_focas_fourbyte(roundL(rawmin), Out);
		}
	else if(bitpix == 16)	{
		write_focas_fourbyte(roundS(rawmax), Out);
		write_focas_fourbyte(roundS(rawmin), Out);
		}
	else	{
		write_focas_float(rawmax, Out);
		write_focas_float(rawmin, Out);
		}
	write_focas_float(q.getd("BSCALE", 1), Out);	/* bscale */
	write_focas_float(q.getd("BZERO", 0), Out);	/* bzero */

	write_focas_float(0.5*p->npts, Out);	/* crpix1 */
	write_focas_float(p->xcenter, Out);	/* crval1 */
	write_focas_float(p->xscale, Out);	/* cdelt1 */
	write_focas_float(0.0 , Out);	/* crota1 */
	write_focas_float(0.5*p->nlines , Out);	/* crpix2 */
	write_focas_float(p->ycenter, Out);	/* crval2 */
	write_focas_float(p->yscale, Out);	/* cdelt2 */
	write_focas_float(0.0 , Out);	/* crota2 */
	write_focas_fourbyte(blank, Out);
	putc('T', Out);	putc(' ', Out);
	write_focas_short(abs(bitpix)/8, Out);	/* bytepix */
	write_focas_float(rawmax!=rawmin ? 500.0/(rawmax-rawmin)
										: 1.0, Out);	/* dscale */
	write_focas_float(-0.5*(rawmin+rawmax), Out);	/* dzero */
	{
	int ii;
	for(ii=0;ii<12;ii++)
		putc(0, Out);				/* dummy */
	}
	putprop(&q, "%LABEL", 32, Out);
	putprop(&q, "%ORIGIN", 32, Out);

	if(!q.get("%DATE"))	{
		time_t ct = time(0);
		struct tm *tb = gmtime(&ct);
		char buf[100], buf2[100];
		sprintf(buf, "%02d/%02d/%02d", tb->tm_mday, 1+tb->tm_mon, 1900+tb->tm_year);
		sprintf(buf2, "%ld sec since 1/1/1970", ct);
		q.add("%DATE", buf, buf2);
		}
	putprop(&q, "%DATE", 32, Out);

	putprop(&q, "%OBSERVER", 32, Out);
	putprop(&q, "%NEXTPIC", 32, Out);
	putprop(&q, "%COMMENT", 256, Out);

 return write_out_data(Out, p, bitpix, LOCAL_ORDER, bscale, bzero);
}
