/*****************************************************************************
FILE: input.c
  
PURPOSE: Contains functions for handling of the input data files for this
application.

PROJECT:  Land Satellites Data System Science Research and Development (LSRD)
at the USGS EROS

LICENSE TYPE:  NASA Open Source Agreement Version 1.3

NOTES:
*****************************************************************************/

#include "input.h"

/******************************************************************************
MODULE:  open_input

PURPOSE:  Sets up the input data structure, opens the input reflectance file
for read access, allocates space, and stores some of the metadata for later
reference.

RETURN VALUE:
Type = Input_t*
Value      Description
-----      -----------
NULL       Error occurred opening or reading the file
non-NULL   Successful completion

NOTES:
  1. This routine opens the input L8-9 files.  It also allocates memory for
     pointers in the input structure.  It is up to the caller to use
     close_input and free_input to close the files and free up the memory when
     done using the input data structure.
******************************************************************************/
Input_t *open_input
(
    Espa_internal_meta_t *metadata     /* I: input metadata */
)
{
    char FUNC_NAME[] = "open_input";   /* function name */
    char errmsg[STR_SIZE];    /* error message */
    Input_t *this = NULL;     /* input data structure to be initialized,
                                 populated, and returned to the caller */
    int ib;                   /* loop counter for bands */

    /* Create the Input data structure */
    this = malloc (sizeof (Input_t));
    if (this == NULL) 
    {
        strcpy (errmsg, "Error allocating memory for Input data structure");
        error_handler (true, FUNC_NAME, errmsg);
        return (NULL);
    }

    /* Initialize and get input from metadata file */
    if (get_xml_input (metadata, this) != SUCCESS)
    {
        strcpy (errmsg, "Error getting input information from the metadata "
            "file.");
        free (this);
        error_handler (true, FUNC_NAME, errmsg);
        return (NULL);
    }

    /* Open files for access. Note: Do not need to open band 8 */
    for (ib = 0; ib < this->nband; ib++)
    {
        this->fp_bin[ib] = open_raw_binary (this->file_name[ib], "rb");
        if (this->fp_bin[ib] == NULL)
        {
            sprintf (errmsg, "Opening reflectance raw binary file: %s",
                this->file_name[ib]);
            error_handler (true, FUNC_NAME, errmsg);
            free_input (this);
            return (NULL);
        }
        this->open[ib] = true;
    }

    for (ib = 0; ib < this->nband_th; ib++)
    {  /* NOTE: nband_th will be 0 for OLI-only scenes */
        this->fp_bin_th[ib] = open_raw_binary (this->file_name_th[ib], "rb");
        if (this->fp_bin_th[ib] == NULL)
        {
            sprintf (errmsg, "Opening thermal raw binary file: %s",
                this->file_name_th[ib]);
            error_handler (true, FUNC_NAME, errmsg);
            free_input (this);
            return (NULL);
        }
        this->open_th[ib] = true;
    }

    for (ib = 0; ib < this->nband_qa; ib++)
    {
        this->fp_bin_qa[ib] = open_raw_binary (this->file_name_qa[ib], "rb");
        if (this->fp_bin_qa[ib] == NULL)
        {
            sprintf (errmsg, "Opening QA raw binary file: %s",
                this->file_name_qa[ib]);
            error_handler (true, FUNC_NAME, errmsg);
            free_input (this);
            return (NULL);
        }
        this->open_qa[ib] = true;
    }

    this->fp_bin_sza = open_raw_binary (this->file_name_sza, "rb");
    if (this->fp_bin_sza == NULL)
    {
        sprintf (errmsg, "Opening solar zenith raw binary file: %s",
            this->file_name_sza);
        error_handler (true, FUNC_NAME, errmsg);
        free_input (this);
        return (NULL);
    }

    this->open_ppa = true;

    /* Do a cursory check to make sure the bands and QA band exist and have
       been opened */
    if (!this->open[0])
    {
        sprintf (errmsg, "Reflectance band 1 is not open.");
        error_handler (true, FUNC_NAME, errmsg);
        free_input (this);
        return (NULL);
    }

    if (this->nband_th != 0 && !this->open_th[0])
    {
        sprintf (errmsg, "Thermal band 10 is not open.");
        error_handler (true, FUNC_NAME, errmsg);
        free_input (this);
        return (NULL);
    }

    if (!this->open_qa[0])
    {
        sprintf (errmsg, "QA band is not open.");
        error_handler (true, FUNC_NAME, errmsg);
        free_input (this);
        return (NULL);
    }

    if (!this->open_ppa)
    {
        sprintf (errmsg, "Per-pixel angle bands are not open.");
        error_handler (true, FUNC_NAME, errmsg);
        free_input (this);
        return (NULL);
    }

    return this;
}


/******************************************************************************
MODULE:  close_input

PURPOSE:  Ends SDS access and closes the input file.

RETURN VALUE:
Type = None

NOTES:
******************************************************************************/
void close_input
(
    Input_t *this    /* I: pointer to input data structure */
)
{
    int ib;      /* loop counter for bands */
  
    if (!this) return;

    /* Close the reflectance files */
    for (ib = 0; ib < this->nband; ib++)
    {
        if (this->open[ib])
        {
            close_raw_binary (this->fp_bin[ib]);
            this->open[ib] = false;
        }
    }

    /* Close the thermal files */
    for (ib = 0; ib < this->nband_th; ib++)
    {
        if (this->open_th[ib])
        {
            close_raw_binary (this->fp_bin_th[ib]);
            this->open_th[ib] = false;
        }
    }

    /* Close the QA files */
    for (ib = 0; ib < this->nband_qa; ib++)
    {
        if (this->open_qa[ib])
        {
            close_raw_binary (this->fp_bin_qa[ib]);
            this->open_qa[ib] = false;
        }
    }

    /* Close the per-pixel angle band files */
    if (this->open_ppa)
    {
        close_raw_binary (this->fp_bin_sza);
        this->open_ppa = false;
    }
}


/******************************************************************************
MODULE:  free_input

PURPOSE:  Frees memory in the input data structure.

RETURN VALUE:
Type = None

NOTES:
******************************************************************************/
void free_input
(
    Input_t *this    /* I: pointer to input data structure */
)
{
    char FUNC_NAME[] = "free_input";   /* function name */
    char errmsg[STR_SIZE];             /* error message */
    int ib;                            /* loop counter for bands */
   
    if (this != NULL)
    {
        if (this->open[0] || this->open_th[0])
        {
            strcpy (errmsg, "Freeing input data structure, but reflectance or "
                "thermal file(s) is/are still open. Use close_input to close "
                "the file");
            error_handler (false, FUNC_NAME, errmsg);
        }
  
        /* Free image band pointers */
        for (ib = 0; ib < this->nband; ib++)
            free (this->file_name[ib]);
        for (ib = 0; ib < this->nband_th; ib++)
            free (this->file_name_th[ib]);
        for (ib = 0; ib < this->nband_qa; ib++)
            free (this->file_name_qa[ib]);

        /* Free the data structure */
        free (this);
    } /* end if */
}


/******************************************************************************
MODULE:  get_input_refl_lines

PURPOSE:  Reads the reflectance data for the current refl band and lines, and
populates the output buffer.

RETURN VALUE:
Type = int
Value      Description
-----      -----------
ERROR      Error occurred reading data for this band
SUCCESS    Successful completion

NOTES:
  1. The Input_t data structure needs to be populated and memory allocated
     before calling this routine.  Use open_input to do that.
******************************************************************************/
int get_input_refl_lines
(
    Input_t *this,   /* I: pointer to input data structure */
    int iband,       /* I: current refl band to read (0-based) */
    int iline,       /* I: current line to read (0-based) */
    int nlines,      /* I: number of lines to read */
    uint16 *out_arr  /* O: output array to populate */
)
{
    char FUNC_NAME[] = "get_input_refl_line";   /* function name */
    char errmsg[STR_SIZE];    /* error message */
    long loc;                 /* current location in the input file */
  
    /* Check the parameters */
    if (this == NULL) 
    {
        strcpy (errmsg, "Input structure has not been opened/initialized");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    if (!this->open[iband])
    {
        strcpy (errmsg, "Reflectance band has not been opened");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    if (iband < 0 || iband >= this->nband)
    {
        strcpy (errmsg, "Invalid reflectance band number for the input date");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    if (iline < 0 || iline >= this->size.nlines)
    {
        strcpy (errmsg, "Invalid line number for reflectance band");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
  
    /* Read the data, but first seek to the correct line */
    loc = (long) iline * this->size.nsamps * sizeof (uint16);
    if (fseek (this->fp_bin[iband], loc, SEEK_SET))
    {
        strcpy (errmsg, "Seeking to the current line in the input file");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    if (read_raw_binary (this->fp_bin[iband], nlines, this->size.nsamps,
        sizeof (uint16), out_arr) != SUCCESS)
    {
        sprintf (errmsg, "Reading %d lines from reflectance band %d starting "
            "at line %d", nlines, iband, iline);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
  
    return (SUCCESS);
}


/******************************************************************************
MODULE:  get_input_th_lines

PURPOSE:  Reads the thermal data for the current thermal band and lines, and
populates the output buffer.

RETURN VALUE:
Type = int
Value      Description
-----      -----------
ERROR      Error occurred reading data for this band
SUCCESS    Successful completion

NOTES:
  1. The Input_t data structure needs to be populated and memory allocated
     before calling this routine.  Use open_input to do that.
******************************************************************************/
int get_input_th_lines
(
    Input_t *this,   /* I: pointer to input data structure */
    int iband,       /* I: current thermal band to read (0-based) */
    int iline,       /* I: current line to read (0-based) */
    int nlines,      /* I: number of lines to read */
    uint16 *out_arr  /* O: output array to populate */
)
{
    char FUNC_NAME[] = "get_input_th_line";   /* function name */
    char errmsg[STR_SIZE];    /* error message */
    long loc;                 /* current location in the input file */
  
    /* Check the parameters */
    if (this == NULL) 
    {
        strcpy (errmsg, "Input structure has not been opened/initialized");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    if (!this->open_th[iband])
    {
        strcpy (errmsg, "Thermal band has not been opened");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    if (iband < 0 || iband >= this->nband_th)
    {
        strcpy (errmsg, "Invalid thermal band number for the input data");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    if (iline < 0 || iline >= this->size_th.nlines)
    {
        strcpy (errmsg, "Invalid line number for thermal band");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
  
    /* Read the data, but first seek to the correct line */
    loc = (long) iline * this->size_th.nsamps * sizeof (uint16);
    if (fseek (this->fp_bin_th[iband], loc, SEEK_SET))
    {
        strcpy (errmsg, "Seeking to the current line in the input file");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    if (read_raw_binary (this->fp_bin_th[iband], nlines, this->size_th.nsamps,
        sizeof (uint16), out_arr) != SUCCESS)
    {
        sprintf (errmsg, "Reading %d lines from thermal band %d starting at "
            "line %d", nlines, iband, iline);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
  
    return (SUCCESS);
}


/******************************************************************************
MODULE:  get_input_qa_lines

PURPOSE:  Reads the QA data for the current QA band and lines, and populates
the output buffer.

RETURN VALUE:
Type = int
Value      Description
-----      -----------
ERROR      Error occurred reading data for this band
SUCCESS    Successful completion

NOTES:
  1. The Input_t data structure needs to be populated and memory allocated
     before calling this routine.  Use open_input to do that.
******************************************************************************/
int get_input_qa_lines
(
    Input_t *this,   /* I: pointer to input data structure */
    int iband,       /* I: current QA band to read (0-based) */
    int iline,       /* I: current line to read (0-based) */
    int nlines,      /* I: number of lines to read */
    uint16 *out_arr  /* O: output array to populate */
)
{
    char FUNC_NAME[] = "get_input_qa_line";   /* function name */
    char errmsg[STR_SIZE];    /* error message */
    long loc;                 /* current location in the input file */
  
    /* Check the parameters */
    if (this == NULL) 
    {
        strcpy (errmsg, "Input structure has not been opened/initialized");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    if (!this->open_qa[iband])
    {
        strcpy (errmsg, "QA band has not been opened");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    if (iband < 0 || iband >= this->nband_qa)
    {
        strcpy (errmsg, "Invalid QA band number for the input data");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    if (iline < 0 || iline >= this->size_qa.nlines)
    {
        strcpy (errmsg, "Invalid line number for QA band");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
  
    /* Read the data, but first seek to the correct line */
    loc = (long) iline * this->size_qa.nsamps * sizeof (uint16);
    if (fseek (this->fp_bin_qa[iband], loc, SEEK_SET))
    {
        strcpy (errmsg, "Seeking to the current line in the input file");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    if (read_raw_binary (this->fp_bin_qa[iband], nlines, this->size_qa.nsamps,
        sizeof (uint16), out_arr) != SUCCESS)
    {
        sprintf (errmsg, "Reading %d lines from QA band %d starting at "
            "line %d", nlines, iband, iline);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
  
    return (SUCCESS);
}


/******************************************************************************
MODULE:  get_input_ppa_lines

PURPOSE:  Reads the per-pixel angle data for the current solar/view angle bands
and populates the output buffer.

RETURN VALUE:
Type = int
Value      Description
-----      -----------
ERROR      Error occurred reading data for these bands
SUCCESS    Successful completion

NOTES:
  1. The Input_t data structure needs to be populated and memory allocated
     before calling this routine.  Use open_input to do that.
******************************************************************************/
int get_input_ppa_lines
(
    Input_t *this,   /* I: pointer to input data structure */
    int iline,       /* I: current line to read (0-based) */
    int nlines,      /* I: number of lines to read */
    int16 *sza_arr   /* O: output solar zenith array to populate */
)
{
    char FUNC_NAME[] = "get_input_ppa_lines";   /* function name */
    char errmsg[STR_SIZE];    /* error message */
    long loc;                 /* current location in the input file */
  
    /* Check the parameters */
    if (this == NULL) 
    {
        strcpy (errmsg, "Input structure has not been opened/initialized");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    if (!this->open_ppa)
    {
        strcpy (errmsg, "Per-pixel solar zenith angle band has not been "
            "opened");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
    if (iline < 0 || iline >= this->size_ppa.nlines)
    {
        strcpy (errmsg, "Invalid line number for per-pixel angle bands");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
  
    /* Read the solar zenith data, but first seek to the correct line */
    loc = (long) iline * this->size_ppa.nsamps * sizeof (int16);
    if (fseek (this->fp_bin_sza, loc, SEEK_SET))
    {
        strcpy (errmsg, "Seeking to the current line in the sza input file");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    if (read_raw_binary (this->fp_bin_sza, nlines, this->size_ppa.nsamps,
        sizeof (int16), sza_arr) != SUCCESS)
    {
        sprintf (errmsg, "Reading %d lines from solar zenith band starting "
            "at line %d", nlines, iline);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }
  
    return (SUCCESS);
}


#define DATE_STRING_LEN (50)
#define TIME_STRING_LEN (50)

/******************************************************************************
MODULE:  get_xml_input

PURPOSE:  Pulls input values from the XML structure.

RETURN VALUE:
Type = int
Value        Description
-------      -----------
ERROR        Error occurred opening or reading the file
SUCCESS      Successful completion

NOTES:
******************************************************************************/
int get_xml_input
(
    Espa_internal_meta_t *metadata,  /* I: XML metadata */
    Input_t *this                    /* O: data structure for the input file */
)
{
    char FUNC_NAME[] = "get_xml_input";   /* function name */
    char errmsg[STR_SIZE];    /* error message */
    int ib;                   /* looping variable for bands */
    char acq_date[DATE_STRING_LEN + 1];    /* acquisition date */
    char prod_date[DATE_STRING_LEN + 1];   /* production date */
    char acq_time[TIME_STRING_LEN + 1];    /* acquisition time */
    char temp[STR_SIZE]; /* temporary string */
    int i;               /* looping variable */
    int refl_indx=-9;    /* band index in XML file for the reflectance band */
    int th_indx=-9;      /* band index in XML file for the thermal band */
    int qa_indx=-9;      /* band index in XML file for the QA band */
    int sza_indx=-9;     /* band index in XML file for the solar zenith band */
    Espa_global_meta_t *gmeta = &metadata->global; /* pointer to global meta */

    /* Initialize the input fields */
    this->meta.sat = SAT_NULL;
    this->meta.inst = INST_NULL;
    this->meta.acq_date.fill = true;
    this->meta.time_fill = true;
    this->meta.prod_date.fill = true;
    this->meta.sun_zen = ANGLE_FILL;
    this->meta.sun_az = ANGLE_FILL;
    this->meta.wrs_sys = (Wrs_t)WRS_NULL;
    this->meta.ipath = -1;
    this->meta.irow = -1;
    this->meta.fill = INPUT_FILL;
    this->size.nsamps = this->size.nlines = -1;
    this->meta.gain_set = false;

    this->nband = 0;
    for (ib = 0; ib < NBAND_REFL_MAX; ib++)
    {
        this->meta.iband[ib] = -1;
        this->meta.gain[ib] = GAIN_BIAS_FILL;
        this->meta.bias[ib] = GAIN_BIAS_FILL;
        this->file_name[ib] = NULL;
        this->open[ib] = false;
        this->fp_bin[ib] = NULL;
    }

    this->nband_th = 0;
    for (ib = 0; ib < NBAND_THM_MAX; ib++)
    {
        this->meta.iband_th[ib] = -1;
        this->meta.gain_th[ib] = GAIN_BIAS_FILL;
        this->meta.bias_th[ib] = GAIN_BIAS_FILL;
        this->file_name_th[ib] = NULL;
        this->open_th[ib] = false;
        this->fp_bin_th[ib] = NULL;
    }

    this->nband_qa = 0;
    for (ib = 0; ib < NBAND_QA_MAX; ib++)
    {
        this->meta.iband_qa[ib] = -1;
        this->file_name_qa[ib] = NULL;
        this->open_qa[ib] = false;
        this->fp_bin_qa[ib] = NULL;
    }

    this->file_name_sza = NULL;
    this->open_ppa = NULL;
    this->fp_bin_sza = NULL;

    /* Pull the appropriate data from the XML file */
    acq_date[0] = acq_time[0] = '\0';
    prod_date[0] = '\0';
    if (!strcmp (gmeta->satellite, "LANDSAT_8"))
        this->meta.sat = SAT_LANDSAT_8;
    else if (!strcmp (gmeta->satellite, "LANDSAT_9"))
        this->meta.sat = SAT_LANDSAT_9;
    else
    {
        sprintf (errmsg, "Unsupported satellite: %s", gmeta->satellite);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    if (!strcmp (gmeta->instrument, "OLI_TIRS"))
        this->meta.inst = INST_OLI_TIRS;
    else if (!strcmp (gmeta->instrument, "OLI"))
        this->meta.inst = INST_OLI;
    else
    {
        sprintf (errmsg, "Unsupported instrument: %s", gmeta->instrument);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    strcpy (acq_date, gmeta->acquisition_date);
    strcpy (acq_time, gmeta->scene_center_time);
    this->meta.time_fill = false;

    /* Make sure the acquisition time is not too long (i.e. contains too
       many decimal points for the date/time routines).  The time should be
       hh:mm:ss.ssssssZ (see DATE_FORMAT_DATEA_TIME in date.h) which is 16
       characters long.  If the time is longer than that, just chop it off. */
    if (strlen (acq_time) > 16)
        sprintf (&acq_time[15], "Z");

    this->meta.sun_zen = gmeta->solar_zenith;
    if (this->meta.sun_zen < -90.0 || this->meta.sun_zen > 90.0)
    {
        sprintf (errmsg, "Solar zenith angle is out of range: %f",
            this->meta.sun_zen);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    this->meta.sun_az = gmeta->solar_azimuth;
    if (this->meta.sun_az < -360.0 || this->meta.sun_az > 360.0)
    {
        sprintf (errmsg, "Solar azimuth angle is out of range: %f",
            this->meta.sun_az);
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    switch (gmeta->wrs_system)
    {
        case 1: this->meta.wrs_sys = WRS_1; break;
        case 2: this->meta.wrs_sys = WRS_2; break;
        default:
            sprintf (errmsg, "Invalid WRS system: %d", gmeta->wrs_system);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
    }
    this->meta.ipath = gmeta->wrs_path;
    this->meta.irow = gmeta->wrs_row;

    if (this->meta.inst == INST_OLI_TIRS)
    {
        this->nband = NBAND_REFL_MAX;   /* number of reflectance bands */
        this->nband_th = NBAND_THM_MAX; /* number of thermal bands */
        this->nband_qa = NBAND_QA_MAX;  /* number of QA bands */
    }
    else if (this->meta.inst == INST_OLI)
    {
        this->nband = NBAND_REFL_MAX;   /* number of reflectance bands */
        this->nband_th = 0;             /* number of thermal bands */
        this->nband_qa = NBAND_QA_MAX;  /* number of QA bands */
    }

    /* Find band 1 and band 10 in the input XML file to obtain
       band-related information for the reflectance and thermal bands */
    for (i = 0; i < metadata->nbands; i++)
    {
        int input_i;         /* index into Input_meta_t structure */
        int band_no;         /* level 1 band number */

        if (!strcmp (metadata->band[i].name, "b8"))
        {
            /* Band 8 is not used in TOA or SR */
            continue;
        }

        /* Parse the band number out of the level 1 band name */
        if (sscanf(metadata->band[i].name, "b%d", &band_no) != 1)
            band_no = -1;

        if (band_no == 1)
        {
            /* this is the index we'll use for reflectance band info */
            refl_indx = i;
            /* get the production date but only the date portion
               (yyyy-mm-dd) */
            strncpy (prod_date, metadata->band[i].production_date, 10);
            prod_date[10] = '\0';
        }

        /* Set the index for where we want to store this band in the
           Input_meta_t arrays */
        input_i = -1;
        if (band_no > -1 && band_no <= 7)
            input_i = band_no - 1;
        else if (band_no == 9)
            input_i = 7;

        /* Store information about a band we want to use */
        if (input_i != -1 && band_no != -1)
        {
            this->meta.gain[input_i]  = metadata->band[i].refl_gain;
            this->meta.bias[input_i]  = metadata->band[i].refl_bias;
            this->meta.iband[input_i] = band_no;
            if ((this->file_name[input_i] = strdup(metadata->band[i].file_name))
                == NULL)
            {
                sprintf (errmsg, "Error setting file name for band %d",band_no);
                error_handler (true, FUNC_NAME, errmsg);
                return (ERROR);
            }
            continue;
        }

        /* NOTE: band10 and band11 won't exist in the input XML file
           for OLI-only products */
        if (band_no == 10)
        {
            /* this is the index we'll use for thermal band info */
            th_indx = i;

            /* get the band10 info */
            this->meta.gain_th[0] = metadata->band[i].rad_gain;
            this->meta.bias_th[0] = metadata->band[i].rad_bias;
            this->meta.k1_const[0] = metadata->band[i].k1_const;
            this->meta.k2_const[0] = metadata->band[i].k2_const;
            this->meta.iband_th[0] = band_no;
            if ((this->file_name_th[0] = strdup (metadata->band[i].file_name))
                == NULL)
            {
                sprintf (errmsg, "Error setting file name for thermal band %d",
                    band_no);
                error_handler (true, FUNC_NAME, errmsg);
                return (ERROR);
            }
        }
        else if (band_no == 11)
        {
            /* get the band11 info */
            this->meta.gain_th[1] = metadata->band[i].rad_gain;
            this->meta.bias_th[1] = metadata->band[i].rad_bias;
            this->meta.k1_const[1] = metadata->band[i].k1_const;
            this->meta.k2_const[1] = metadata->band[i].k2_const;
            this->meta.iband_th[1] = band_no;
            if ((this->file_name_th[1] = strdup (metadata->band[i].file_name))
                == NULL)
            {
                sprintf (errmsg, "Error setting file name for thermal band %d",
                    band_no);
                error_handler (true, FUNC_NAME, errmsg);
                return (ERROR);
            }
        }
        else if (!strcmp (metadata->band[i].name, "bqa_pixel"))
        {
            /* this is the index we'll use for qa band info */
            qa_indx = i;

            /* get the QA band info */
            if ((this->file_name_qa[0] = strdup (metadata->band[i].file_name))
                == NULL)
            {
                error_handler (true, FUNC_NAME,
                    "Error setting file name for QA band 0");
                return (ERROR);
            }
            this->meta.iband_qa[0] = qa_indx+1;
        }
        else if (!strcmp (metadata->band[i].name, "solar_zenith_band4"))
        {
            /* this is the index we'll use for sza band info */
            sza_indx = i;

            /* get the solar zenith band info */
            if ((this->file_name_sza = strdup (metadata->band[i].file_name))
                == NULL)
            {
                error_handler (true, FUNC_NAME,
                    "Error setting file name for solar zenith angle band");
                return (ERROR);
            }
        }
    }  /* for i */

    /* Make sure the bands were found in the XML file */
    if (refl_indx == -9)
    {
        sprintf (errmsg, "Band 1 (b1) was not found in the XML file");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    if (this->meta.inst == INST_OLI_TIRS && th_indx == -9)
    {
        sprintf (errmsg, "Band 10 (b10) was not found in the XML file");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    if (qa_indx == -9)
    {
        sprintf (errmsg, "QA band (bqa) was not found in the XML file");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    if (sza_indx == -9)
    {
        sprintf (errmsg, "Solar zenith band was not found in the XML file");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    /* Get the size of the reflectance, thermal, etc. bands by using
       the representative band in the XML file */
    this->size.nsamps = metadata->band[refl_indx].nsamps;
    this->size.nlines = metadata->band[refl_indx].nlines;
    this->size.pixsize[0] = metadata->band[refl_indx].pixel_size[0];
    this->size.pixsize[1] = metadata->band[refl_indx].pixel_size[1];
    this->scale_factor = metadata->band[refl_indx].scale_factor;

    if (this->meta.inst == INST_OLI_TIRS)
    {  /* skip for OLI */
        this->size_th.nsamps = metadata->band[th_indx].nsamps;
        this->size_th.nlines = metadata->band[th_indx].nlines;
        this->size_th.pixsize[0] = metadata->band[th_indx].pixel_size[0];
        this->size_th.pixsize[1] = metadata->band[th_indx].pixel_size[1];
        this->scale_factor_th = metadata->band[th_indx].scale_factor;
    }
    else
    {  /* set to 0s */
        this->size_th.nsamps = 0;
        this->size_th.nlines = 0;
        this->size_th.pixsize[0] = 0;
        this->size_th.pixsize[1] = 0;
        this->scale_factor_th = 0;
    }

    this->size_qa.nsamps = metadata->band[qa_indx].nsamps;
    this->size_qa.nlines = metadata->band[qa_indx].nlines;
    this->size_qa.pixsize[0] = metadata->band[qa_indx].pixel_size[0];
    this->size_qa.pixsize[1] = metadata->band[qa_indx].pixel_size[1];

    /*per-pixel angle bands size and resolution */
    this->size_ppa.nsamps = metadata->band[sza_indx].nsamps;
    this->size_ppa.nlines = metadata->band[sza_indx].nlines;
    this->size_ppa.pixsize[0] = metadata->band[sza_indx].pixel_size[0];
    this->size_ppa.pixsize[1] = metadata->band[sza_indx].pixel_size[1];

    /* Check WRS path/rows */
    if (this->meta.wrs_sys == WRS_1)
    {
        if (this->meta.ipath > 251)
        {
            sprintf (errmsg, "WRS path number out of range: %d",
                this->meta.ipath);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
        else if (this->meta.irow > 248)
        {
            sprintf (errmsg, "WRS row number out of range: %d",
                this->meta.irow);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
    }
    else if (this->meta.wrs_sys == WRS_2)
    {
        if (this->meta.ipath > 233)
        {
            sprintf (errmsg, "WRS path number out of range: %d",
                this->meta.ipath);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
        else if (this->meta.irow > 248)
        {
            sprintf (errmsg, "WRS row number out of range: %d",
                this->meta.irow);
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
    }

    /* Check satellite/instrument combination */
    if (this->meta.inst == INST_OLI_TIRS ||
        this->meta.inst == INST_OLI)
    {
        if ((this->meta.sat != SAT_LANDSAT_8)
            && (this->meta.sat != SAT_LANDSAT_9))
        {
            sprintf (errmsg, "Invalid instrument/satellite combination");
            error_handler (true, FUNC_NAME, errmsg);
            return (ERROR);
        }
    }

    /* Convert the acquisition date/time values from string to date struct */
    sprintf (temp, "%sT%s", acq_date, acq_time);
    if (!date_init (&this->meta.acq_date, temp, DATE_FORMAT_DATEA_TIME))
    {
        sprintf (errmsg, "Converting the acquisition date and time");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    /* Convert the production date value from string to date struct */
    if (!date_init (&this->meta.prod_date, prod_date, DATE_FORMAT_DATEA))
    {
        sprintf (errmsg, "Converting the production date and time");
        error_handler (true, FUNC_NAME, errmsg);
        return (ERROR);
    }

    return (SUCCESS);
}

