/*
 * © 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 <limits.h>
#include <math.h>
#include "mars.h"

/*
 LLMATRIX
 AREA
 GRID
 NORTH
 WEST
 EAST
 SOUTH
 NLAT
 NLON
 DATA
*/


err llmatrix_to_grib(const char* in, const char* out) {
    fortint ksec0[ISECTION_0];
    gribsec1 ksec1;
    gribsec2_ll ksec2;
    fortint ksec3[ISECTION_3];
    fortint ksec4[ISECTION_4];

    fortfloat psec2[RSECTION_2];
    fortfloat psec3[RSECTION_3];
    fortfloat missing = FLT_MAX;


    err e    = 0;
    int miss = 0;
    fortint nlat, nlon, nbits;
    fortfloat north, west, south, east, ew, ns;
    char* buffer = NULL;
    fortint buflen;
    fortfloat* psec4 = NULL;
    fortint i, npoints;
    int n = 0;
    char line[1024];
    char* tmp = marstmp();
    FILE *f, *g;
    request* r;
    const char* p;

    CLEAR(ksec0);
    CLEAR(ksec1);
    CLEAR(ksec2);
    CLEAR(ksec3);
    CLEAR(ksec4);
    CLEAR(psec2);
    CLEAR(psec3);

    f = fopen(in, "r");
    if (!f) {
        marslog(LOG_EROR | LOG_PERR, "Cannot open %s", in);
        return -1;
    }

    g = fopen(tmp, "w");
    if (!g) {
        marslog(LOG_EROR | LOG_PERR, "Cannot open %s", tmp);
        fclose(f);
        return -1;
    }


    while (fgets(line, sizeof(line), f)) {
        if (*line != '#') {
            int l = strlen(line) - 1;

            while (l >= 0 && (line[l] == ' ' || line[l] == '\n' || line[l] == ',' || line[l] == '\t'))
                line[l--] = 0;


            if (n == 0) {
                /* Look for a = */
                char* p = line;
                int flg = 0;
                while (*p)
                    if (*p++ == '=')
                        flg++;
                /* If a =, add a verb */
                if (flg) {
                    fprintf(g, "LLMATRIX");
                    fprintf(g, ",%s", line);
                }
                else
                    fprintf(g, "%s", line);
            }
            else
                fprintf(g, ",%s", line);
            n++;
        }
        if (strncmp(line, "#DATA", 5) == 0)
            break;
    }

    fclose(g);

    r = read_request_file(tmp);
    unlink(tmp);
    print_all_requests(r);

    north   = atof((p = get_value(r, "NORTH", 0)) ? p : "0");
    west    = atof((p = get_value(r, "WEST", 0)) ? p : "0");
    ew      = atof((p = get_value(r, "GRID", 0)) ? p : "0");
    ns      = atof((p = get_value(r, "GRID", 1)) ? p : "0");
    nlat    = atol((p = get_value(r, "NLAT", 0)) ? p : "0");
    nlon    = atol((p = get_value(r, "NLON", 0)) ? p : "0");
    missing = (p = get_value(r, "MISSING", 0)) ? atof(p) : missing;

    if (ew == 0 || ns == 0 || nlat == 0 || nlon == 0) {
        marslog(LOG_EROR, "Invalid ll-matrix");
        fclose(f);
        return -1;
    }

    npoints = nlat * nlon;

    south = north - (nlat - 1) * ns;
    east  = west + (nlon - 1) * ew;

    /* ============================================================ */

    psec4 = NEW_ARRAY(fortfloat, npoints);

    n = 0;
    for (i = 0; i < npoints; i++) {
#ifndef R64
        if (fscanf(f, "%f", &psec4[i]) > 0)
#else
        if (fscanf(f, "%lf", &psec4[i]) > 0)
#endif
        {
            n++;
            if (psec4[i] == missing)
                miss++;
        }
    }
    fclose(f);

    if (n != npoints) {
        marslog(LOG_EROR, "File %s, read %d values out of %d expected",
                in, n, npoints);
        e = -1;
        goto error;
    }

    /* 1 k header + 32 bit packing */

    buflen = (npoints + 1024) * 4;
    buffer = (char*)MALLOC(buflen);

    /* ============================================================ */

    ksec1.version         = 128;
    ksec1.center          = 98;
    ksec1.generation      = mars.computeflg;
    ksec1.grid_definition = 255;
    ksec1.flags           = miss ? 192 : 128;


    ksec1.parameter  = 255;
    ksec1.level_type = GRIB_SURFACE;

    ksec1.year    = 94;
    ksec1.month   = 1;
    ksec1.day     = 1;
    ksec1.century = 20;


    ksec1.time_unit            = 1;
    ksec1.local_use            = 1;
    ksec1.local.ecmwf_local_id = GRIB_ENSEMBLE_FORECAST;
    ksec1.local.mars_class     = GRIB_CLASS_OD;
    ksec1.local.mars_type      = 3;          /* IA */
    ksec1.local.mars_stream    = 1025;       /* DA */
    ksec1.local.mars_expver    = 0x30303031; /* 01 */

    ksec2.data_rep        = GRIB_LAT_LONG;
    ksec2.points_parallel = nlon;
    ksec2.points_meridian = nlat;

    ksec2.limit_north = (fortint)(north * GRIB_FACTOR);
    ksec2.limit_west  = (fortint)(west * GRIB_FACTOR);
    ksec2.resolution  = 128;
    ksec2.limit_south = (fortint)(south * GRIB_FACTOR);
    ksec2.limit_east  = (fortint)(east * GRIB_FACTOR);
    ksec2.grid_ew     = (fortint)(ew * GRIB_FACTOR);
    ksec2.grid_ns     = (fortint)(ns * GRIB_FACTOR);


    /*  Missing value */

    ksec3[0] = 0;
    ksec3[1] = INT_MAX;
    psec3[1] = missing;

    /*  Data */

    ksec4[0] = npoints;
    ksec4[1] = nbits = best_packing(ksec4[1]);

    printf("nbits   = %d\n", nbits);
    printf("missing = %g\n", missing);

    if (cgribex(ksec0, (fortint*)&ksec1, (fortint*)&ksec2, psec2,
                ksec3, psec3, ksec4, psec4,
                npoints, buffer, &buflen, "C")
        != 0) {
        marslog(LOG_EROR, "Error encoding GRIB");
        e = -1;
        goto error;
    }

    /*
        psec3[1] = 9999;
        e = cgribex( ksec0,(fortint*)&ksec1, (fortint*)&ksec2,psec2,
            ksec3,psec3, ksec4,psec4,
            npoints, buffer, &buflen, "D");
        printf("decode %d\n",e);
    */

    f = fopen(out, "w");
    if (!f) {
        marslog(LOG_EROR | LOG_PERR, "Cannot open %s", out);
        e = -1;
        goto error;
    }

    if (fwrite(buffer, 1, buflen, f) != buflen) {
        marslog(LOG_EROR | LOG_PERR, "fwrite(%s) failed", out);
        e = -1;
    }

    if (fclose(f)) {
        marslog(LOG_EROR | LOG_PERR, "fclose(%s) failed", out);
        e = -1;
    }

error:
    FREE(psec4);
    FREE(buffer);
    return e;
}


err grib_to_llmatrix(const char* g, const char* m) {
    return -1;
}
