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

konvsbig.c (C-Munipack project)
Conversion functions for SBIG files
Copyright (C) 2003 David Motl, dmotl@volny.cz

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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

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

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <fitsio.h>

#include "config.h"
#include "trajd.h"
#include "console.h"
#include "comfun.h"
#include "cmpack_common.h"
#include "iost.h"
#include "konvsbig.h"

/* Pixel value bias */
#define BIAS       	32768
/* Header length of the SBIG image file in bytes */
#define HEADSIZE  	2048             
/* Length of string buffers */
#define MAXLINE		1024

/* Uppercases the string */
static void strup(char *s)
{
  for( ; *s != '\0'; s++ )
    if( *s >= 'a' && *s <= 'z' )
      *s = *s - ('a' - 'A');
}

/* Reads observation date */
static int stgetdate(stfile *st, int *yr, int *mon, int *day)
{
    int y=0, y2k=0, m=0, d=0, res;
    char *datestr;

	if (stgkys(st, "Date", &datestr)!=0)
		return CMPACK_ERR_INVALID_DATE;
    if (stgkyi(st, "Y2KYear", &y2k)!=0) 
		y2k = 0;

	/* Parse input date and time */
	res = sscanf(datestr, "%2d%*1s%2d%*1s%4d", &m, &d, &y);
	cmpack_free(datestr);
	if (res != 3)
		return CMPACK_ERR_INVALID_DATE;

	/* Compute the year */
	*mon = m;
	*day = d;
	if (y2k>0)
		*yr = y2k;
	else if ((y>50)&&(y<=999))
		*yr = y + 1900;
	else if ((y>=0)&&(y<50))
		*yr = y + 2000;
	else if ((y>=1900)&&(y<1950))
		*yr = y + 100;
	else
		*yr = y;

	/* Check values */
	if ((*yr>1900)&&(*yr<=9999)&&(*mon>=1)&&(*mon<=12)&&(*day>=1)&&(*day<=31))
		return 0;
	else
		return CMPACK_ERR_INVALID_DATE;
}

/* Reads observation time */
static int stgettime(stfile *st, int *hr, int *min, int *sec)
{
	int res;
    char *timestr;

	if (stgkys(st, "Time", &timestr)!=0)
		return CMPACK_ERR_INVALID_DATE;

	/* Parse input date and time */
	res = sscanf(timestr,"%2d%*1s%2d%*1s%2d",hr,min,sec);
	cmpack_free(timestr);
	if (res != 3)
		return CMPACK_ERR_INVALID_DATE;

	/* Check values */
	if ((*hr>=0)&&(*hr<=23)&&(*min>=0)&&(*min<=59)&&(*sec>=0)&&(*sec<=59))
		return 0;
	else
		return CMPACK_ERR_INVALID_DATE;
}

/* Returns 1 if the file is in SBIG format */
int sbig_test(const char *block, size_t length, size_t filesize)
{
	return (filesize>HEADSIZE) && 
		(memstr(block, "ST-", length)==block || memstr(block, "SBIG", length)==block || memstr(block, "PixCel", length)==block);
}

/* Open the file and read the header into memory */
int sbig_open(tHandle *fs, const char *filename, CmpackOpenMode mode, unsigned flags)
{
	return stopen((stfile**)fs, filename);
}

/* Close a file and free allocated memory */
void sbig_close(tHandle fs)
{
	stclos((stfile*)fs);
}

/* Reads string value from header */
int sbig_gets(tHandle fs, const char *key, char **buf)
{
	return stgkys((stfile*)fs, key, buf);
}

/* Get file format designation */
char *sbig_getmagic(tHandle fs)
{
	char *value = NULL;
	stgkyn((stfile*)fs, 0, &value, NULL);
	return value;
}

/* Get optical filter name */
char *sbig_getfilter(tHandle fs, CmpackChannel channel)
{
	char *value = NULL;
	stgkys((stfile*)fs, "Filter", &value);
	return value;
}

/* Get observer's name */
char *sbig_getobserver(tHandle fs)
{
	char *value = NULL;
	stgkys((stfile*)fs, "Observer", &value);
	return value;
}

/* Reads integer value from header */
int sbig_geti(tHandle fs, const char *key, int *value)
{
	return stgkyi((stfile*)fs, key, value);
}

int sbig_getsize(tHandle fs, int *width, int *height)
{
	if (width)
		stgkyi((stfile*)fs, "Width", width);
	if (height)
		stgkyi((stfile*)fs, "Height", height);
	return 0;
}

/* Reads floating point value from header */
int sbig_getd(tHandle fs, const char *key, double *value)
{
	return stgkyd((stfile*)fs, key, value);
}

/* Get date and time of observation */
int sbig_getdatetime(tHandle fs, CmpackDateTime *dt)
{
	memset(dt, 0, sizeof(CmpackDateTime));
	stgetdate((stfile*)fs, &dt->date.year, &dt->date.month, &dt->date.day);
	stgettime((stfile*)fs, &dt->time.hour, &dt->time.minute, &dt->time.second);
	return 0;
}

/* Get exposure duration */
int sbig_getexptime(tHandle fs, double *val)
{
	int res;
	res = stgkyd((stfile*)fs, "Exposure", val);
	if (res==0)
		*val = 0.01 * (*val);
	return res;
}

/* Get CCD temperature */
int sbig_getccdtemp(tHandle fs, double *val)
{
	return stgkyd((stfile*)fs, "Temperature", val);
}

/* Get key name and value by index. Comm is set always to "" */
int sbig_gkyn(tHandle fs, int nkey, char **key, char **val, char **com)
{
	if (com)
		*com = NULL;
	return stgkyn((stfile*)fs, nkey+1, key, val);
}

/* Get image data type */
CmpackBitpix sbig_getbitpix(tHandle fs)
{
	return CMPACK_BITPIX_USHORT;
}

/* Get image data type */
int sbig_getrange(tHandle fs, double *minvalue, double *maxvalue)
{
	if (minvalue)
		*minvalue = 0.0;
	if (maxvalue)
		*maxvalue = 65535.0;
	return 0;
}

/* Read image data */
int sbig_getimage(tHandle fs, void *buf, int bufsize, CmpackChannel channel)
{
	return stgimg((stfile*)fs, (uint16_t*)buf, bufsize/sizeof(int16_t));
}

int sbig_copyheader(tHandle fs, CmpackImageHeader *hdr, CmpackChannel channel, CmpackConsole *con)
{
	double	f;
	char	msg[MAXLINE], *filter, *history, *observer;
	int		i, sstat;
	char	datestr[64], timestr[64];
	CmpackDateTime dt;
	stfile	*src = (stfile*)fs;
	fitsfile *dst = (fitsfile*)hdr->fits;
	
	/* Set date and time of observation */
	memset(&dt, 0, sizeof(CmpackDateTime));
	stgetdate(src, &dt.date.year, &dt.date.month, &dt.date.day);
	stgettime(src, &dt.time.hour, &dt.time.minute, &dt.time.second);
	sprintf(datestr, "%04d-%02d-%02d", dt.date.year, dt.date.month, dt.date.day);
	ffukys(dst,"DATE-OBS", (char*) datestr, "UT DATE OF START", &hdr->status);
	sprintf(timestr, "%02d:%02d:%02d.%03d", dt.time.hour, dt.time.minute, dt.time.second, dt.time.milisecond);
	ffukys(dst,"TIME-OBS", (char*) timestr, "UT TIME OF START", &hdr->status);

	/* Other parameters */
	sstat = stgkyi(src,"Exposure",&i);
	if (sstat==0) ffpkyg(dst,"EXPTIME",1.0*i/100,2,"EXPOSURE IN SECONDS",&hdr->status);
	sstat = stgkyi(src,"Number_exposures",&i);
	if (sstat==0) ffpkyj(dst,"SNAPSHOT",i,"NUMBER OF SNAPSHOT",&hdr->status);
	sstat = stgkyi(src,"Each_exposure",&i);
	if (sstat==0) ffpkyg(dst,"EACHSNAP",1.0*i/100,2,"SNAPSHOT IN SECONDS",&hdr->status);
	sstat = stgkyd(src,"X_pixel_size",&f);
	if (sstat==0) ffpkyd(dst,"PIXWIDTH",f,3,"PIXEL WIDTH IN MM",&hdr->status);
	sstat = stgkyd(src,"Y_pixel_size",&f);
	if (sstat==0) ffpkyd(dst,"PIXHEIGH",f,3,"PIXEL HEIGHT IN MM",&hdr->status);
	sstat = stgkyi(src,"Readout_mode",&i);
	if (sstat==0) ffpkyj(dst,"RESMODE",i,"RESOLUTION MODE",&hdr->status);
	sstat = stgkyi(src,"Exposure_state",&i);
	if (sstat==0) {
		int li = i;
		sprintf(msg,"%x",li);
		strup(msg);
		ffpkys(dst,"EXPSTATE",msg,"EXPOSURE STATE (HEX)",&hdr->status);
	}
	sstat = stgkyd(src,"Temperature",&f);
	if (sstat==0) ffpkyg(dst,"CCD-TEMP",f,2,"TEMPERATURE IN DEGREES C",&hdr->status);
	sstat = stgkyd(src,"Response_factor",&f);
	if (sstat==0) ffpkyg(dst,"RESPONSE",f,3,"CCD RESPONSE FACTOR",&hdr->status);
	sstat = stgkyd(src,"E_Gain",&f);
	if (sstat==0) ffpkyg(dst,"EPERADU",f,2,"ELECTRONS PER ADU",&hdr->status);
	sstat = stgkyd(src,"Focal_length",&f);
	if (sstat==0) ffpkyd(dst,"FOCALLEN",f,3,"FOCAL LENGTH IN INCHES",&hdr->status);
	sstat = stgkyd(src,"Aperture",&f);
	if (sstat==0) ffpkyd(dst,"APERTURE",f,4,"APERTURE AREA IN SQ-INCHES",&hdr->status);
	sstat = stgkys(src,"Filter",&filter);
	if (sstat==0) ffpkys(dst,"FILTER",filter,"OPTICAL FILTER NAME",&hdr->status);
	cmpack_free(filter);
	sstat = stgkyi(src,"Background",&i);
	if (sstat==0) ffpkyj(dst,"BACKGRND",i,"BACKGROUND FOR DISPLAY",&hdr->status);
	sstat = stgkyi(src,"Range",&i);
	if (sstat==0) ffpkyj(dst,"RANGE",i,"RANGE FOR DISPLAY",&hdr->status);
	sstat = stgkys(src,"History",&history);
	if (sstat==0) ffphis(dst,history,&hdr->status);
	cmpack_free(history);
	/* Can fail if the string contains characters <32 or >126 */
	sstat = stgkys(src,"Observer",&observer);
	if (sstat==0) ffpkys(dst,"OBSERVER",observer,"OBSERVERS NAME",&hdr->status);
	cmpack_free(observer);
	hdr->status = 0;
	sstat = stgkyi(src,"Pedestal",&i);
	if (sstat==0) ffpkyj(dst,"PEDESTAL",i,"PEDESTAL OFFSET",&hdr->status);
	sstat = stgkyi(src,"Track_time",&i);
	if (sstat==0) ffpkyj(dst,"TRAKTIME",i,"TRACK PERIOD IN SECONDS",&hdr->status);
	sstat = stgkyi(src,"Sat_level",&i);
	if (sstat==0) ffpkyj(dst,"SATURATE",i,"SATURATION LEVEL",&hdr->status);	

	return (hdr->status!=0 ? CMPACK_ERR_WRITE_ERROR : 0);
}
