/*
 * © Copyright 1996-2012 ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

#include <ctype.h>
#include <grib_api.h>
#include <stdio.h>

#include "mars.h"


static void upper_case(char* p) {
    while (*p) {
        if (islower(*p))
            *p = toupper(*p);
        p++;
    }
}

err handle_to_request(request* r, grib_handle* g, mars_field_index* idx) {
    grib_keys_iterator* ks;
    char name[80];
    char value[80];
    size_t len = sizeof(value);
    long local;
    int e;
    const char* p;
    const char* stream = get_value(r, "STREAM", 0);
    const char* number = get_value(r, "NUMBER", 0);

    if (!g)
        return -1;


    /* printf("------------\n"); */
    ks = grib_keys_iterator_new(g, GRIB_KEYS_ITERATOR_ALL_KEYS, "mars");

    while (grib_keys_iterator_next(ks)) {

        strcpy(name, grib_keys_iterator_get_name(ks));

        if ((e = grib_keys_iterator_get_string(ks, value, &len)) != 0)
            marslog(LOG_EROR, "Cannot get %s as string %d (%s)", name, e,
                    grib_get_error_message(e));

        /* printf("MARS -> %s ... %s\n",name,c); */

        if (idx) {
            double d;
            long l;
            boolean d_ok, l_ok;

            len  = 1;
            d_ok = (grib_keys_iterator_get_double(ks, &d, &len) == 0);

            len  = 1;
            l_ok = (grib_keys_iterator_get_long(ks, &l, &len) == 0);

            mars_field_index_add(idx, name, 1, value, l_ok, l, d_ok, d);
        }

        upper_case(name);

        if (!EQ(name, "EXPVER"))
            upper_case(value);


        set_value(r, name, "%s", value);
        len = sizeof(value);
    }

    strcpy(name, "identifier");
    len = sizeof(value);
    if ((e = grib_get_string(g, name, value, &len)) != 0) {
        marslog(LOG_EXIT, "Cannot get %s as string %d (%s)", name, e,
                grib_get_error_message(e));
        mars.pseudogrib = 0;
    }
    else {
        if (strcmp(value, "HDF5") == 0) {
            // marslog(LOG_INFO,"Message is NetCDF");
        }
        else {
            mars.pseudogrib = (strcmp(value, "BUDG") == 0) || (strcmp(value, "TIDE") == 0);
            if (mars.pseudogrib) {
                marslog(LOG_WARN, "Pseudo GRIB encountered (%s)", value);
                if (stream == NULL)
                    stream = getenv("MARS_PSEUDOGRIB_STREAM");

                if (stream != NULL) {
                    marslog(LOG_DBUG, "Setting STREAM to '%s'", stream);
                    set_value(r, "STREAM", "%s", stream);
                }

                if (number != NULL) {
                    marslog(LOG_DBUG, "Setting NUMBER to '%s'", number);
                    set_value(r, "NUMBER", "%s", number);
                }
            }
            else {
                if (strcmp(value, "GRIB") != 0)
                    marslog(LOG_EXIT, "Unexpected message type (%s)", value);
                else {
                    /* Get the edition */
                    long edition = 0;
                    if ((e = grib_get_long(g, "edition", &edition)) != 0) {
                        marslog(LOG_EXIT, "Cannot get edition as long: %d (%s)", e,
                                grib_get_error_message(e));
                    }
                    set_value(r, "_EDITION", "%ld", edition);
                }
            }
        }
    }

    if (grib_get_long(g, "localDefinitionNumber", &local) == 0 && local == 191) /* TODO: Not grib2 compatible, but speed-up process */
        if (grib_get_size(g, "freeFormData", &len) == 0 && len != 0) {
            unsigned char buffer[10240];
            len = sizeof(buffer);
            if ((e = grib_get_bytes(g, "freeFormData", buffer, &len)) != 0)
                marslog(LOG_EROR, "Cannot get freeFormData %d (%s)", name, e,
                        grib_get_error_message(e));
            else {
                request* s = decode_free_format_request(buffer, len);

                if (mars.debug) {
                    marslog(LOG_DBUG, "Free format request:");
                    print_all_requests(s);
                }
                /* set_value(r,"PARAM","%d.%d",s1->parameter,s1->version); */

                reset_language(mars_language());
                mars.expflags = EXPAND_MARS | EXPAND_NO_DEFAULT;
                s             = expand_mars_request(s);
                if (s == NULL) {
                    /* if(mars.exit_on_failed_expand) */
                    {
                        e = -2;
                        marslog(LOG_EROR, "Failed to expand request");
                    }
                }
                mars.expflags = EXPAND_MARS;
                reqcpy(r, s);
                free_all_requests(s);
            }
        }

    grib_keys_iterator_delete(ks);
    return e;
}

err grib_to_request_index(request* r, char* buffer, long length, mars_field_index* idx) {
    err e;
    grib_handle* g = grib_handle_new_from_message(0, buffer, length);
    e              = handle_to_request(r, g, idx);
    grib_handle_delete(g);
    return e;
}

err grib_to_request(request* r, char* buffer, long length) {
    return grib_to_request_index(r, buffer, length, NULL);
}
