
/*
 *  photom: a package to perform photometric calibration
 *  Copyright (C) 2001  Michael William Richmond
 *
 *  Contact: Michael William Richmond
 *           Physics Department
 *           Rochester Institute of Technology
 *           85 Lomb Memorial Drive
 *           Rochester, NY  14623-5603
 *           E-mail: mwrsps@rit.edu
 *
 *  
 *  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.
 *
 */




   /*
    * functions which read data from ASCII multi-column files
    */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include "misc.h"
#include "photom.h"
#include "readlist.h"


static int is_blank(char *line);
static int get_value(char *str, double *val);



/*********************************************************************
 * ROUTINE: read_detected_file
 *
 * Given the name of a file, some information about the image, 
 * and integers which specify the
 * columns in which data of interest appear, go through
 * the file, creating an "s_det" structure for each line.
 * Place all "s_det" structures in a big array, and return a pointer
 * to the head of the array, and the number of stars in the array
 *
 * usage: read_detected_file     racol deccol jdcol airmasscol flagcol 
 *                                   num_filters 
 *                                   filter_array magcol_array magerrcol_array
 *                                   num_stars star_array
 *
 * where
 *            racol           is the column containing RA values
 *            deccol          is the column containing Dec values
 *            jdcol           is the column containing JD values
 *            airmasscol      is the column containing airmass values
 *            flagcol         is the column containing "quality flag" values
 *            
 *            num_filters     is the number of filters with data
 *            filter_array    is an array with columns containing 
 *                                           names of filters
 *            magcol_array    is an array with columns containing 
 *                                           instrumental mag values
 *            magerrcol_array is an array with columns containing 
 *                                           uncertainty in mag
 *
 *            num_stars       will hold number of stars read from file
 *            star_array      will hold an array of all the stars
 *
 * Ignore any line which starts with a COMMENT_CHAR, and any
 * completely empty line (one with whitespace only).
 *
 * Note that columns are numbered starting at 0.  Thus, 
 * given a file with format like this:
 *   
 *    #    RA     Dec     mag    magerr
 *       234.43  54.33   12.23    0.20
 *
 * we have racol = 0, deccol = 1, etc.
 *
 * RETURNS:
 *      SH_SUCCESS         if all goes well
 *      SH_GENERIC_ERROR   if not
 */

int
read_detected_file
   (
   char *filename,           /* I: name of file */
   int racol,                /* I: column in which RA data is found */
   int deccol,               /* I: column in which Dec data is found */
   int jdcol,                /* I: column containing Julian Date of obs */
   int airmasscol,           /* I: column containing airmass of obs */
   int flagcol,              /* I: column containing 'quality flag' */
   int num_filt,             /* I: for how many filters is there mag data? */
   int *filtercol_array,     /* I: columns in which filter names are found */
   int *magcol_array,        /* I: columns in which 'mag' data is found */
   int *magerrcol_array,     /* I: columns in which 'magerr' data is found */
   int *num_stars,           /* O: number of stars in array goes here */
   S_DET **det_array         /* O: head of array will be placed here */
   )
{
   FILE *fp;
   char line[LINELEN];
   char *filter_name[MAX_PASSBANDS];
   char col[MAX_DATA_COL + 1][MAX_COL_LENGTH + 1];
   int i, nlines, num, ncol;
   int last_column = -1;
   int magcol, magerrcol, filtercol;
   unsigned int flagval;
   S_DET *star;
   double raval, decval, jdval, airmassval, temp_flagval;
   double magval[MAX_PASSBANDS], magerrval[MAX_PASSBANDS];

   /* sanity checks */
   shAssert(racol >= 0);
   shAssert((deccol >= 0) && (deccol != racol));
   shAssert(jdcol >= 0);
   shAssert(airmasscol >= 0);
   shAssert(flagcol >= 0);
   shAssert(num_filt > 0);
   shAssert(filtercol_array != NULL);
   shAssert(magcol_array != NULL);
   shAssert(magerrcol_array != NULL);
   for (i = 0; i < num_filt; i++) {
      shAssert(filtercol_array[i] >= 0);
      shAssert(magcol_array[i] >= 0);
      shAssert(magerrcol_array[i] >= 0);
   }

   /* allocate space for the "filter_name" array */
   for (i = 0; i < MAX_PASSBANDS; i++) {
      filter_name[i] = (char *) shMalloc(sizeof(char)*(FILTER_LENGTH + 1));
   }

   if ((fp = fopen(filename, "r")) == NULL) {
      shError("read_detected_file: can't open file %s\n", filename);
      return(SH_GENERIC_ERROR);
   }

   /* count the number of lines in the file */
   if ((nlines = lines_in_file(fp)) < 0) {
      shError("read_detected_file: no lines in file %s\n", filename);
      return(SH_GENERIC_ERROR);
   }

   /* 
    * allocate space for the array 
    *   we allocate 'nlines' structures, even though we probably need
    *   fewer (since some lines in file may be comments)
    */
   *det_array = (S_DET *) shMalloc(nlines*sizeof(S_DET));
   

   /* find the highest-numbered column we need to read */
   last_column = racol;
   if (deccol > last_column) {
     last_column = deccol;
   }
   if (jdcol > last_column) {
     last_column = jdcol;
   }
   if (airmasscol > last_column) {
     last_column = airmasscol;
   }
   if (flagcol > last_column) {
     last_column = flagcol;
   }
   for (i = 0; i < num_filt; i++) {
     if (filtercol_array[i] > last_column) {
       last_column = filtercol_array[i];
     }
     if (magcol_array[i] > last_column) {
       last_column = magcol_array[i];
     }
     if (magerrcol_array[i] > last_column) {
       last_column = magerrcol_array[i];
     }
   }
   shAssert(last_column >= 3);
   if (last_column > MAX_DATA_COL) {
      shError("read_detected_file: only %d columns allowed", MAX_DATA_COL);
      return(SH_GENERIC_ERROR);
   }

   num = 0;
   while (fgets(line, LINELEN, fp) != NULL) {
      if (line[0] == COMMENT_CHAR) {
         continue;
      }
      if (is_blank(line)) {
         continue;
      }
      ncol = sscanf(line, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s", 
              &(col[0][0]),  &(col[1][0]),  &(col[2][0]),  &(col[3][0]), 
              &(col[4][0]),  &(col[5][0]),  &(col[6][0]),  &(col[7][0]), 
              &(col[8][0]),  &(col[9][0]),
              &(col[10][0]), &(col[11][0]), &(col[12][0]), &(col[13][0]), 
              &(col[14][0]), &(col[15][0]), &(col[16][0]), &(col[17][0]), 
              &(col[18][0]), &(col[19][0]));
      if (last_column > ncol) {
         shError("read_detected_file: not enough entries in following line; skipping");
         shError("  %s", line);
         continue;
      }
        
      /* now read values from each column */
      if (get_value(col[racol], &raval) != SH_SUCCESS) {
         shError("read_detected_file: can't read RA value from %s; skipping", 
                  col[racol]);
         continue;
      }
      if (get_value(col[deccol], &decval) != SH_SUCCESS) {
         shError("read_detected_file: can't read Dec value from %s; skipping", 
                  col[deccol]);
         continue;
      }
      if (get_value(col[jdcol], &jdval) != SH_SUCCESS) {
         shError("read_detected_file: can't read JD value from %s; skipping", 
                  col[jdcol]);
         continue;
      }
      if (get_value(col[airmasscol], &airmassval) != SH_SUCCESS) {
         shError("read_detected_file: can't read airmass value from %s; skipping", 
                  col[airmasscol]);
         continue;
      }
      if (get_value(col[flagcol], &temp_flagval) != SH_SUCCESS) {
         shError("read_detected_file: can't read flag value from %s; skipping", 
                  col[flagcol]);
         continue;
      }
      flagval = (unsigned int) temp_flagval;

      for (i = 0; i < num_filt; i++) {

         /* 
          * copy the filter name from the appropriate column in "filter_name"
          * array, and make sure that the "filter_name" value is terminated
          * with a '\0' character.
          */
         filtercol = filtercol_array[i];
         strncpy(filter_name[i], col[filtercol], FILTER_LENGTH);
         filter_name[i][FILTER_LENGTH] = '\0';

         magcol = magcol_array[i];
         if (get_value(col[magcol], &(magval[i])) != SH_SUCCESS) {
            shError("read_detected_file: can't read mag value from %s; skipping", 
                     col[magcol]);
            continue;
         }
         magerrcol = magerrcol_array[i];
         if (get_value(col[magerrcol], &(magerrval[i])) != SH_SUCCESS) {
            shError("read_detected_file: can't read magerr value from %s; skipping", 
                     col[magerrcol]);
            continue;
         }
      }

      /* okay, it's safe to fill in an S_DET struct with info from this line */
      star = &((*det_array)[num]);
      sdetFill(star, raval, decval, jdval, airmassval, flagval, num_filt, 
                  filter_name, magval, magerrval);
      num++;
   }

   *num_stars = num;

   /* free space from the "filter_name" array */
   for (i = 0; i < MAX_PASSBANDS; i++) {
      shFree(filter_name[i]);
   }

   return(SH_SUCCESS);
}



/*********************************************************************
 * ROUTINE: read_catalog_file
 *
 * Given the name of a file, and integers which specify the
 * columns in which data of interest appear, go through
 * the file, creating an "s_cat" structure for each line.
 * Place all the stars in an array, and return a pointer
 * to the head of the array, and the number of stars in the array.
 *
 * usage: read_catalog_file   racol deccol num_filt filt_array magcol_array
 *                            num_stars star_array
 *
 * where
 *            racol           is the column containing RA values
 *            deccol          is the column containing Dec values
 *            num_filt        is the number of columns of magnitudes,
 *                                 one per filter, which appear in the file
 *            filt_array      is an array of filter names
 *            magcol_array    is an array of column numbers containing
 *                                 magnitude values
 *
 *            num_stars       will hold number of stars read from file
 *            star_array      will hold an array of all the stars
 *
 * Suppose the file contains values for magnitudes in B and V passbands,
 * with B magnitudes in column 6 and V magnitudes in column 7.
 * Then we would have
 *
 *            num_filt          2
 *            filt_array[0]     "B"
 *            filt_array[1]     "V"
 *            magcol_array[0]   6
 *            magcol_array[1]   7
 *
 *
 * Ignore any line which starts with a COMMENT_CHAR, and any
 * completely empty line (one with whitespace only).
 *
 * Note that columns are numbered starting at 0.  Thus, 
 * given a file with format like this:
 *   
 *    #    RA     Dec     etc.
 *       234.43  54.33   12.23    
 *
 * we have racol = 0, deccol = 1, etc.
 *
 * RETURNS:
 *      SH_SUCCESS         if all goes well
 *      SH_GENERIC_ERROR   if not
 */

int
read_catalog_file
   (
   char *filename,           /* I: name of file */
   int racol,                /* I: column in which RA data is found */
   int deccol,               /* I: column in which Dec data is found */
   int num_filt,             /* I: number of passbands of data we'll  */
                             /*        read from the file */
   char **filt_array,        /* I: an array of 'num_filt' filter names */
   int *magcol_array,        /* I: an array of 'num_filt' integers, */
                             /*        describing the columns in which */
                             /*        magnitude values are to be found */
   int *num_stars,           /* O: number of stars in new array goes here */
   S_CAT **cat_array         /* O: head of new star array will be placed here */
   )
{
   FILE *fp;
   char line[LINELEN];
   char col[MAX_DATA_COL + 1][MAX_COL_LENGTH + 1];
   int i, nlines, num, ncol;
   int last_column = -1;
   S_CAT *star;
   double raval, decval, magval[MAX_PASSBANDS];

   /* sanity checks */
   shAssert(racol >= 0);
   shAssert((deccol >= 0) && (deccol != racol));
   shAssert(num_filt > 0);
   shAssert(magcol_array != NULL);
   for (i = 0; i < num_filt; i++) {
      shAssert(filt_array[i] != NULL);
      shAssert((magcol_array[i] >= 0) && (magcol_array[i] != racol) &&
               (magcol_array[i] != deccol));
   }


   if ((fp = fopen(filename, "r")) == NULL) {
      shError("read_catalog_file: can't open file %s\n", filename);
      return(SH_GENERIC_ERROR);
   }

   /* count the number of lines in the file */
   if ((nlines = lines_in_file(fp)) < 0) {
      shError("read_detected_file: no lines in file %s\n", filename);
      return(SH_GENERIC_ERROR);
   }

   /* 
    * allocate space for the array 
    *   we allocate 'nlines' structures, even though we probably need
    *   fewer (since some lines in file may be comments)
    */
   *cat_array = (S_CAT *) shMalloc(nlines*sizeof(S_CAT));
   


   /* find the highest-numbered column we need to read */
   last_column = racol;
   if (deccol > last_column) {
     last_column = deccol;
   }
   for (i = 0; i < num_filt; i++) {
     if (magcol_array[i] > last_column) {
       last_column = magcol_array[i];
     }
   }
   shAssert(last_column >= 2);
   if (last_column > MAX_DATA_COL) {
      shError("read_catalog_file: only %d columns allowed", MAX_DATA_COL);
      return(SH_GENERIC_ERROR);
   }

   num = 0;
   while (fgets(line, LINELEN, fp) != NULL) {
      if (line[0] == COMMENT_CHAR) {
         continue;
      }
      if (is_blank(line)) {
         continue;
      }
      ncol = sscanf(line, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s", 
              &(col[0][0]),  &(col[1][0]),  &(col[2][0]),  &(col[3][0]), 
              &(col[4][0]),  &(col[5][0]),  &(col[6][0]),  &(col[7][0]), 
              &(col[8][0]),  &(col[9][0]),
              &(col[10][0]), &(col[11][0]), &(col[12][0]), &(col[13][0]), 
              &(col[14][0]), &(col[15][0]), &(col[16][0]), &(col[17][0]), 
              &(col[18][0]), &(col[19][0]));
      if (last_column > ncol) {
         shError("read_catalog_file: not enough entries in following line; skipping");
         shError("  %s", line);
         continue;
      }
        
      /* now read values from each column */
      if (get_value(col[racol], &raval) != SH_SUCCESS) {
         shError("read_catalog_file: can't read RA value from %s; skipping", 
                  col[racol]);
         continue;
      }
      if (get_value(col[deccol], &decval) != SH_SUCCESS) {
         shError("read_catalog_file: can't read Dec value from %s; skipping", 
                  col[deccol]);
         continue;
      }
      for (i = 0; i < num_filt; i++) {
        if (get_value(col[magcol_array[i]], &(magval[i])) != SH_SUCCESS) {
           shError("read_catalog_file: can't read mag value from %s; skipping", 
                    col[magcol_array[i]]);
           continue;
        }
      }

      /* okay, it's safe to create a new star for this line */
      star = &((*cat_array)[num]);
      scatFill(star, raval, decval, num_filt, filt_array, magval);
      num++;
   }

   *num_stars = num;

   return(SH_SUCCESS);
}




/**********************************************************************
 * ROUTINE: is_blank
 *
 * If the given string consists only of whitespace, return 1.
 * Otherwise, return 0.
 */

static int 
is_blank
   (
   char *line                /* I: string to be checked */
   )
{
   char *p;

   for (p = line; (*p != '\0') && (isspace(*p)); p++) {
      ;
   }
   if (p == '\0') {
      return(1);
   }
   else {
      return(0);
   }
}




/**********************************************************************
 * ROUTINE: get_value
 *
 * Given a string containing a numerical value, read the numerical
 * value and place it into the given double argument.  
 *
 * Return 0 if all goes well.
 * Return 1 if there is an error.
 */

static int 
get_value
   (
   char *str,                /* I: string to be converted to double */
   double *val               /* O: place value here */
   )
{
   if (sscanf(str, "%lf", val) != 1) {
      return(1);
   } 
   else {
      return(0);
   }
}
 



