/*****************************************************************************
FILE: setup_ias_l1g_metadata.c

PURPOSE: Contains functions for setting up IAS L1G I/O file and band metadata 
         structures using information from the ESPA XML file.

*****************************************************************************/
#include <unistd.h>
#include <string.h>
#include "gctp.h"
#include "ias_l1g.h"
#include "ias_geo.h"
#include "ias_miscellaneous.h"
#include "espa_metadata.h"


/******************************************************************************
MODULE:  setup_file_metadata

PURPOSE: Initializes IAS L1G I/O File Metadata

RETURNS: SUCCESS/ERROR
******************************************************************************/
int setup_file_metadata
(
    const Espa_internal_meta_t *xml_metadata, /* I: Source XML metadata */
    IAS_L1G_FILE_METADATA *fmd                /* O: File Metadata */
)
{
    char errmsg[STR_SIZE];      /* error message */
    char FUNC_NAME[] = "setup_file_metadata";

    /* Initialize the structure */
    memset(fmd, 0, sizeof(*fmd));

    /* The projection codes for ESPA match GCTP, so no conversion is
       necessary */
    fmd->projection_code = xml_metadata->global.proj_info.proj_type;

    /* Make sure the projection code is one of the supported ones */
    if (fmd->projection_code != GEO && fmd->projection_code != UTM
        && fmd->projection_code != ALBERS && fmd->projection_code != PS)
    {
        sprintf(errmsg, "Unsupported projection code: %d",
                fmd->projection_code);
        error_handler(true, FUNC_NAME, errmsg);
        return ERROR;
    }

    fmd->zone_code = xml_metadata->global.proj_info.utm_zone;
    if (xml_metadata->global.proj_info.datum_type == ESPA_WGS84)
        snprintf(fmd->datum, sizeof(fmd->datum), "WGS84");
    else
    {
        sprintf(errmsg, "Unsupported datum: %d",
            xml_metadata->global.proj_info.datum_type);
        error_handler(true, FUNC_NAME, errmsg);
        return ERROR;
    }

    /* Since only WGS84 is supported, hard code the WGS84 spheroid since
       it isn't stored in the xml metadata */
    fmd->spheroid_code = GCTP_WGS84;
    snprintf(fmd->projection_units, sizeof(fmd->projection_units),
             xml_metadata->global.proj_info.units);

    /* Set the projection parameters */
    if (fmd->projection_code == PS)
    {
        /* Convert the projection parameters from degrees to DMS */
        if ((ias_geo_convert_deg2dms(
                xml_metadata->global.proj_info.longitude_pole,
                &fmd->projection_parameters[4], "LON") != SUCCESS)
            || (ias_geo_convert_deg2dms(
                xml_metadata->global.proj_info.latitude_true_scale,
                &fmd->projection_parameters[5], "LAT") != SUCCESS))
        {
            error_handler(true, FUNC_NAME,
                "Converting projection parameters from degrees to DMS");
            return ERROR;
        }
    }
    else if (fmd->projection_code == ALBERS)
    {
        /* Convert the projection parameters from degrees to DMS */
        if ((ias_geo_convert_deg2dms(
                xml_metadata->global.proj_info.standard_parallel1,
                &fmd->projection_parameters[2], "LAT") != SUCCESS)
            || (ias_geo_convert_deg2dms(
                xml_metadata->global.proj_info.standard_parallel2,
                &fmd->projection_parameters[3], "LAT") != SUCCESS)
            || (ias_geo_convert_deg2dms(
                xml_metadata->global.proj_info.central_meridian,
                &fmd->projection_parameters[4], "LON") != SUCCESS)
            || (ias_geo_convert_deg2dms(
                xml_metadata->global.proj_info.origin_latitude,
                &fmd->projection_parameters[5], "LAT") != SUCCESS))
        {
            error_handler(true, FUNC_NAME,
                "Converting projection parameters from degrees to DMS");
            return ERROR;
        }
    }
    if (fmd->projection_code == PS || fmd->projection_code == ALBERS)
    {
        fmd->projection_parameters[6] =
            xml_metadata->global.proj_info.false_easting;
        fmd->projection_parameters[7] =
            xml_metadata->global.proj_info.false_northing;
    }

    /* Make sure the corners are center based.  If not, exit with an
       error since we're expecting them to all be center based. */
    if (strcmp(xml_metadata->global.proj_info.grid_origin, "CENTER") != 0)
    {
        sprintf(errmsg, "Unsupported corner grid origin: %s",
            xml_metadata->global.proj_info.grid_origin);
        error_handler(true, FUNC_NAME, errmsg);
        return ERROR;
    }

    fmd->wrs_path = xml_metadata->global.wrs_path;
    fmd->wrs_row = xml_metadata->global.wrs_row;
    fmd->sun_azimuth = xml_metadata->global.solar_azimuth;
    fmd->sun_elevation = 90 - xml_metadata->global.solar_zenith;
    fmd->sun_angles_valid = 1;
    fmd->earth_sun_distance = xml_metadata->global.earth_sun_dist;
    strcpy(fmd->sun_angle_correction, "PER_PIXEL");
    strncpy(fmd->software_version, ias_misc_get_software_version(),
        sizeof(fmd->software_version)-1);
    strncpy(fmd->spacecraft, xml_metadata->global.satellite, 
        sizeof(fmd->spacecraft)-1);
    strncpy(fmd->capture_date, xml_metadata->global.acquisition_date, 
        sizeof(fmd->capture_date)-1);
    strncpy(fmd->capture_time, xml_metadata->global.scene_center_time, 
        sizeof(fmd->capture_time)-1);

    return SUCCESS;
}

/******************************************************************************
MODULE:  setup_band_metadata

PURPOSE: Populates the band metadata structure with information
    from the Espa xml metadata.  This routine does NOT set
    the band_number or band_name.

RETURNS: SUCCESS/ERROR
******************************************************************************/
int setup_band_metadata
(
    const Espa_internal_meta_t *xml_metadata, /* I: Source XML metadata */
    int band_index,                           /* I: Index into xml_metadata of
                                                 band to use */
    IAS_L1G_BAND_METADATA *bmd                /* I/O: Band Metadata */
)
{
    /* Set up the available band metadata fields that will be written
       to the output file.  Per the comments in the espa_metadata.h
       file, the corners are relative to the center of the pixel, so no
       adjustments are needed to the corners. */
    bmd->upper_left_x = xml_metadata->global.proj_info.ul_corner[0];
    bmd->upper_left_y = xml_metadata->global.proj_info.ul_corner[1];
    bmd->upper_right_x = xml_metadata->global.proj_info.lr_corner[0];
    bmd->upper_right_y = xml_metadata->global.proj_info.ul_corner[1];
    bmd->lower_left_x = xml_metadata->global.proj_info.ul_corner[0];
    bmd->lower_left_y = xml_metadata->global.proj_info.lr_corner[1];
    bmd->lower_right_x = xml_metadata->global.proj_info.lr_corner[0];
    bmd->lower_right_y = xml_metadata->global.proj_info.lr_corner[1];
    bmd->projection_distance_x = xml_metadata->band[band_index].pixel_size[0];
    bmd->projection_distance_y = xml_metadata->band[band_index].pixel_size[1];

    /* If either scale_factor or add_offset are supplied, use them
     * for valid reflectance scaling factors.  Often scale_factor
     * is supplied but add_offset is not (assumed to be 0). */
    if ((xml_metadata->band[band_index].scale_factor != ESPA_FLOAT_META_FILL)
     || (xml_metadata->band[band_index].add_offset   != ESPA_FLOAT_META_FILL))
    {
        bmd->reflectance_valid = 1;

        if (xml_metadata->band[band_index].scale_factor == ESPA_FLOAT_META_FILL)
            bmd->reflectance_scaling_gain = 1.0;
        else
            bmd->reflectance_scaling_gain 
                = xml_metadata->band[band_index].scale_factor;

        if (xml_metadata->band[band_index].add_offset == ESPA_FLOAT_META_FILL)
            bmd->reflectance_scaling_offset = 0.0;
        else
            bmd->reflectance_scaling_offset 
                = xml_metadata->band[band_index].add_offset;
    }

    if ((xml_metadata->band[band_index].valid_range[0] != ESPA_FLOAT_META_FILL)
     && (xml_metadata->band[band_index].valid_range[1] != ESPA_FLOAT_META_FILL))
    {
        bmd->minimum_pixel_value 
            = xml_metadata->band[band_index].valid_range[0];
        bmd->maximum_pixel_value 
            = xml_metadata->band[band_index].valid_range[1];
        bmd->pixel_range_valid = 1;
    }
    strncpy(bmd->instrument_source, xml_metadata->band[band_index].long_name, 
        sizeof(bmd->instrument_source));
    bmd->instrument_source[sizeof(bmd->instrument_source)-1] = '\0';

    return SUCCESS;
}

/******************************************************************************
MODULE:  convert_to_ias_data_type

PURPOSE: Converts the internal ESPA data type to an IAS data type

RETURN VALUE:
Type = IAS_DATA_TYPE

******************************************************************************/
IAS_DATA_TYPE convert_to_ias_data_type
(
    const int espa_data_type   /* I: input ESPA data type */
)
{
    IAS_DATA_TYPE ias_data_type;          /* converted data type */

    switch (espa_data_type)
    {
        case ESPA_INT8:
            ias_data_type = IAS_CHAR;
            break;
        case ESPA_UINT8:
            ias_data_type = IAS_BYTE;
            break;
        case ESPA_INT16:
            ias_data_type = IAS_I2;
            break;
        case ESPA_UINT16:
            ias_data_type = IAS_UI2;
            break;
        case ESPA_INT32:
            ias_data_type = IAS_I4;
            break;
        case ESPA_UINT32:
            ias_data_type = IAS_UI4;
            break;
        case ESPA_FLOAT32:
            ias_data_type = IAS_R4;
            break;
        case ESPA_FLOAT64:
            ias_data_type = IAS_R8;
            break;
        default:
            ias_data_type = type_error;
            break;
    }
    
    /* Successful conversion */
    return ias_data_type;
}

