/*
 * © 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.
 */

/*

   B.Raoult
   ECMWF Oct-93

 */

#include <errno.h>
#include "mars.h"

err feed(database* bout, request* r) {
    extern base_class* netbase;
    extern base_class* gribbase;
    static long buflen  = 4 * 1024 * 1024;
    static char* buffer = NULL;
    database* bin;
    int i;
    int cnt = 0;
    err ret;

    bin = database_open(gribbase, NULL, r, get_environ(), READ_MODE);
    if (!bin)
        return -2;

    if (!buffer)
        buffer = reserve_mem(buflen);

    if (observation(r))
        r = 0;

    do {
        request* s  = clone_all_requests(r);
        long length = buflen;

        ret = database_read(bin, s, buffer, &length);

        if (ret == BUF_TO_SMALL) {
            release_mem(buffer);
            buflen = length;
            buffer = reserve_mem(buflen);

            ret = 0;
            database_close(bin);
            bin = database_open(gribbase, NULL, r, get_environ(),
                                READ_MODE);

            for (i = 0; i < (cnt + 1); i++)
                ret = database_read(bin, s, buffer, &length);
        }

        if (ret == 0) {
            ret = database_write(bout, s, buffer, &length);
            cnt++;
        }

        free_all_requests(s);

        if (ret == EOF) {
            ret = 0;
            break;
        }

    } while (ret == 0);

    database_close(bin);

    marslog(LOG_INFO, "%d records fed to database '%s'", cnt, bout->name);

    return ret;
}

static request* make_arc_request(const char* path) {
    const char* x;
    long buflen = 0;
    long length = 0;
    char* buffer;
    request* a = empty_request("ARCHIVE");
    err e;
    int cnt = 0;

    buflen = mars.readany_buffer_size;
    length = buflen;

    FILE* f = fopen(path, "r");
    if (f == NULL) {
        marslog(LOG_EROR | LOG_PERR, "ARCHIVE : '%s'", path);
        marsexit(1);
    }

    buffer = reserve_mem(length);
    length = buflen;
    while ((e = _readany(f, buffer, &length)) == NOERR || (e == BUF_TO_SMALL)) {
        request* g = empty_request(0);
        grib_to_request(g, buffer, length);
        reqmerge(a, g);
        free_all_requests(g);
        length = buflen;
        cnt++;
    }

#if 0
	x = get_value(a,"_RESOL",0);    if(x) add_value(a,"RESOL",x);
	x = get_value(a,"_GAUSSIAN",0); if(x) add_value(a,"RESOL",x);
	x = get_value(a,"_GRID_EW",0);  if(x) add_value(a,"RESOL","%d",
			(int)(360.0/atof(x)));
	x = get_value(a,"_GRID_NS",0);  if(x) add_value(a,"RESOL","%d",
			(int)(360.0/atof(x)));
#endif

    set_value(a, "EXPECT", "%d", cnt);

    return a;
}

err handle_archive(request* r, void* data) {
    int i         = 0;
    err e         = 0;
    const char* s = 0;

    mars.fields_are_ok         = true;
    mars.fields_in_order       = true;
    mars.fields_have_same_size = true;

    if (mars.autoarch) {
        const char* s = no_quotes(get_value(r, "SOURCE", 0));
        request* a    = make_arc_request(s);

        if (mars.autoarch != 2) {
            unset_value(r, "CLASS");
            unset_value(r, "TYPE");
            unset_value(r, "STREAM");
            unset_value(r, "EXPVER");
            unset_value(r, "LEVTYPE");
            unset_value(r, "LEVELIST");
            unset_value(r, "REPRES");
            unset_value(r, "DOMAIN");
            unset_value(r, "PARAM");
            unset_value(r, "DATE");
            unset_value(r, "TIME");
            unset_value(r, "STEP");
            unset_value(r, "DISP");
            unset_value(r, "RESOL");
            unset_value(r, "NUMBER");
            unset_value(r, "METHOD");
            unset_value(r, "SYSTEM");
        }

        reqcpy(r, a);
        free_all_requests(a);

        marslog(LOG_INFO, "Archive request changed to: ");
        print_one_request(r);
    }

    while ((s = get_value(r, "DATABASE", i++)) != NULL) {
        database* base;
        const char* name = 0;
        request* cache   = 0;
        int retry        = 0;
        int slp          = 1;

        const request* b = findbase(s, r);
        if (!b) {
            marslog(LOG_EROR, "Could not find database '%s' for archive", s);
            return -2;
        }

        for (;;) {

            base = openbase(b, r, &name, &cache, WRITE_MODE);
            if (base) {
                int e1 = database_archive(base, r);
                marslog(LOG_DBUG, "database_archive return %d", e1);
                int e2 = database_close(base);
                marslog(LOG_DBUG, "database_close return %d", e2);
                e = e1 ? e1 : e2;
            }
            else {
                marslog(LOG_EROR, "Failed to open database '%s' for archive", s);
                e = -2;
            }

            if (e != RETRY_FOREVER_ERR && e != RETRY_ERR && e != RETRY_SAME_DATABASE)
                break;

            if (e == RETRY_ERR) {
                if (retry < mars.maxretries) {
                    retry++;
                    marslog(LOG_WARN, "Sleeping %d minutes", slp);
                    sleep(slp * 60);
                }
                else {
                    e = -2;
                    marslog(LOG_WARN, "Giving up after %d retries", retry);
                    break;
                }
            }

            if (e == RETRY_FOREVER_ERR) {
                if (slp < 5)
                    slp += 1;
                marslog(LOG_WARN, "Sleeping %d minutes", slp);
                sleep(slp * 60);
            }

            if (e == RETRY_SAME_DATABASE) {
                marslog(LOG_WARN, "Request will be retried");
                sleep(5);
            }
        }

        if (e != 0)
            break;
    }

    return e;
}
