 /*
  * Khoros: $Id: fits.c,v 1.3 1992/03/20 23:35:20 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: fits.c,v 1.3 1992/03/20 23:35:20 dkhoros Exp $";
#endif

 /*
  * $Log: fits.c,v $
 * Revision 1.3  1992/03/20  23:35:20  dkhoros
 * VirtualPatch5
 *
  */ 

/* Copyright 1990, Pennsylvania State University. You can do
 * anything you like with this code except remove this notice.
 *
 * PSU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.   */

/* This routine was based on big.c and hence is also:	*/
/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "vinclude.h"	
#include "file_formats/fits.h"	
#define BLOCK 2880
static int put_value();
static int get_value();


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	   file name: fits.c                                  <<<<
   >>>>                                                       <<<<
   >>>> description: utilities to read and write fits images  <<<<
   >>>>                                                       <<<<
   >>>>      routines: write_fits()			      <<<<
   >>>>			read_fits()
   >>>>                                                       <<<<
   >>>> modifications:					      <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

/**************************************************************
*
* MODULE NAME:  write_fits
*
*     PURPOSE:  writes out a fits image file format.
*
*       INPUT:  char *filename - file name
*		struct fits *fits_image - pointer to fits image
*
*      OUTPUT:  
*
* ROUTINES CALLED: put_value
*
**************************************************************/

write_fits(filename, imageptr)
struct fits *imageptr;
char *filename;
{
    int imgsize, header_size,file;
    int i, npad;
    unsigned long type;
    char            block[BLOCK], keyword[8];

    /* Open the output file */
    if ( (file = kopen(filename, O_WRONLY|O_TRUNC|O_CREAT, 0664)) < 0)
      {
        fprintf(stderr,"write_fits: unable to access output file\n");
        return(0);
      }
/* write basic FITS header to block */
/* first initialise header to blanks */
	for (i=0; i < BLOCK; i++) block[i] = ' ';
	sprintf(block, "SIMPLE  ="); sprintf(block+29,"T /");
	sprintf(block+80, "END     ");
/* These basic keywords must be in this order */
	put_value(block, "BITPIX  ", imageptr->bitpix);
	put_value(block, "NAXIS   ", 3);
	put_value(block, "NAXIS1  ", imageptr->naxis1);
	put_value(block, "NAXIS2  ", imageptr->naxis2);
	put_value(block, "NAXIS3  ", imageptr->naxis3);
	

    imgsize = imageptr->naxis1 * imageptr->naxis2
		* imageptr->naxis3 * imageptr->bitpix/8; 

/* a rather nasty kludge to turn nulls into spaces */
	for (i=0; i < BLOCK; i++) if (block[i] == 0) block[i] = ' ';

    if ((kwrite(file, block, BLOCK)) != BLOCK)
    {
      fprintf(stderr,"write_fits: Unable to write image header\n");
      kclose(file);
      return(0);
    } 

         /* write image data */
    if (kwrite(file,imageptr->imagedata,imgsize) != imgsize)
    {
        fprintf(stderr,"write_fits: Unable to write image data\n");
        kclose(file);
        return(0);
    }
	/* Now pad it out to a multiple of 2880 */
	npad = BLOCK - (imgsize -  BLOCK * (imgsize/BLOCK));
	for (i=0; i < npad; i++) kwrite(file, " ", 1);
 
    kclose(file);
    return(1);
}


/**************************************************************
*
* MODULE NAME:  read_fits()
*
*     PURPOSE:  Reads a fits image file format.
*
*       INPUT:  filename - filename of the input image file.
*
*      OUTPUT:  struct fits *imageptr - pointer to fits image read
*
* ROUTINES CALLED: block_read(), get_value()
*
**************************************************************/

struct fits
*read_fits(filename)
char *filename;
{
    char block[BLOCK], keyword[8],*malloc();
    struct fits *imageptr;
    int numread,headersize,imgsize,file; 
    unsigned long type;

    /* Open the output file */
    if ( (file = kopen(filename, O_RDONLY)) < 0)
      {
        fprintf(stderr,"read_fits: unable to access input file\n");
        return(0);
      }

    /* Grab space for the image structure */

    imageptr = (struct fits *)malloc(sizeof(struct fits));
    if (imageptr == NULL) {
        (void) fprintf(stderr,"\nread_fits: Not enough memory ");
        (void) fprintf(stderr,"for FITS image header\n");
        kclose(file);
        return(NULL);
    }


    /* only want to read in the first 2880 bytes of the header */
    kread(file, block, 2880);

    /* Decode the NAXIS keyword to see if we have a 2D image */
    imageptr->naxis = get_value(block, "NAXIS   ");

    if (imageptr->naxis > 3) {
        (void)fprintf(stderr,"\nread_fits: Sorry, this program \
				is too stupid to cope with \
				%d dimensional images\n", imageptr->naxis);
        freeimage(imageptr);
        kclose(file);
        return(NULL);
    }
    imageptr->naxis1 = get_value(block, "NAXIS1  ");
    imageptr->naxis2 = get_value(block, "NAXIS2  ");
    imageptr->naxis3 = get_value(block, "NAXIS3  ");  
    imageptr->bitpix = get_value(block, "BITPIX  ");

    imgsize = imageptr->naxis1*(imageptr->bitpix)/8;
    if(imageptr->naxis >=2) imgsize = imgsize* imageptr->naxis2;  
    if(imageptr->naxis == 3) imgsize = imgsize*imageptr->naxis3; 

    /* Get space for image data */
    imageptr->imagedata = (char *)malloc(imgsize);
    if (imageptr->imagedata == NULL) {
      (void)fprintf(stderr,"\nread_fits: Not enough memory for image data.\n");
      (void)fprintf(stderr,"\nread_fits: wanted %d bytes\n", imgsize);
      freeimage(imageptr);
      kclose(file);
      return(NULL);
    }

    /* read the image */
    numread = block_read(file,imageptr->imagedata,imgsize);
    if (numread != imgsize) {
      (void) fprintf(stderr,"\nread_fits: ");
      (void) fprintf(stderr,"Incorrect byte count reading image data!\n\
				%d bytes read \n \
				%d bytes requested\n", numread, imgsize);
      freeimage(imageptr);
      kclose(file);
      return(NULL);
    }
    kclose(file);
    return(imageptr);
}

/* get_value
 * returns the value of a specified keyword
 * if the keyword is not found then a value of 0 is returned 
 */
static int
get_value(block, keyword)
	char           *block;
	char           *keyword;
{
	int             value;
	int             i;
	/* find keyword */
	for (i = 0; i < BLOCK; i += 80) {
		if (strncmp(block + i, keyword, 8) == 0) {
			sscanf(block + i + 10, "%d", &value);
			return (value);
		}
	}
	/*
	 * well... I guess we didn't find that value - send back a zero (good
	 * choice???)
	 */
	return (0);
}

/* put_value
 * adds the value of a specified keyword
 * to a text block just before the end statement.
 * Returns 1 if it worked, 0 if it didn't.
 */
static int
put_value(block, keyword, value)
	char           *block;
	char           *keyword;
	int		value;
{
	int             i;
	static char ender[] = "/";
	/* find keyword END */
	for (i = 0; i < BLOCK; i += 80) {
		if (strncmp(block + i, "END     ", 8) == 0) {
	/* now write the keyword and value over it */
			sprintf(block + i, "%s=", keyword);
			sprintf(block + i + 10, "%20d", value);
			sprintf(block + i + 31, "%-1.1s", ender);
	/* and put an "END" as the next line */
			sprintf(block + i +80, "%s", "END     ");

			return (1);
		}
	/* now write the keyword and value over it */
	}
	/*
	 * well... I guess we didn't add that value - send back a zero */
	return (0);
}
