/*
 * © 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 "mars.h"
#if defined(hpux)
#define EMPRESS
#endif

#ifdef EMPRESS
#include <ctype.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>


/* db prototypes */

static void rdb_init(void);
static err rdb_open(void* data, request* r, request* e, int mode);
static err rdb_close(void* data);
static err rdb_read(void* data, request* r, void* buffer, long* length);
static err rdb_write(void* data, request* r, void* buffer, long* length);
static err rdb_query(void* data, request* r, long* length);
static boolean rdb_check(void* data, request* r);


extern err setvalrdb(const char* name, const char* val);
extern err setrangerdb(const char* name, const char* val1, const char* val2);
extern err readrdb(void* data, long* length);
extern err openrdb(const char*);
extern err closerdb(void);

static base_class _rdb_base = {

    NULL,       /* parent class */
    "rdb_base", /* name         */

    false, /* inited       */

    NULL,

    NULL,
    NULL,

    rdb_init, /* init         */

    rdb_open,  /* open         */
    rdb_close, /* close        */

    rdb_read,  /* read         */
    rdb_write, /* write        */

    NULL, /* control      */

    rdb_check, /* check */

};


/* the only 'public' variable ... */

base_class* rdb_base = &_rdb_base;


static void rdb_init(void) {
    marslog(LOG_DBUG, "rdb_init:Initialize RDB");
}


static err rdb_open(void* data, request* r, request* e, int mode) {
    parameter* p     = 0;
    request* t       = empty_request(0);
    long flags       = expand_flags(EXPAND_MARS | EXPAND_SUB_LISTS);
    request* s       = 0;
    const char* type = 0;

    unset_value(r, "TARGET");
    s    = expand_all_requests(mars_language(), mars_rules(), r);
    type = get_value(s, "TYPE", 0);

    expand_flags(flags);
    reset_language(mars_language());

    marslog(LOG_DBUG, "rdb_open");
    if (type && !EQ("OB", type)) {
        free_all_requests(s);
        return NOERR;
    }

    /* Open the database */
    openrdb(NULL);

    if (mars.debug)
        print_all_requests(s);

    names_loop(s, sort_request, &t);

    p = s->params;
    while (p) {
        if (get_value(t, p->name, 0) == 0)
            valcpy(t, s, p->name, p->name);

        p = p->next;
    }

    p = t->params;

    while (p) {
        marslog(LOG_DBUG, "setvalrdb: %s %s", p->name, p->values->name);

        if (p->count > 1 && EQ(p->name, "TIME")) {
            const char* q1 = 0;
            const char* q2 = 0;
            if (EQ("TO", get_value(s, p->name, 1))) {
                q1 = get_value(s, p->name, 0);
                q2 = get_value(s, p->name, 2);
                setrangerdb(p->name, q1, q2);
            }
            else {
                int i = 0;
                while (q1 = get_value(s, p->name, i++))
                    setvalrdb(p->name, q1);
            }
        }
        else {
            const char* q = 0;
            int i         = 0;
            while (q = get_value(t, p->name, i++))
                setvalrdb(p->name, q);
        }

        p = p->next;
    }

    free_all_requests(t);
    free_all_requests(s);

    return NOERR;
}


static err rdb_close(void* data) {
    marslog(LOG_DBUG, "rdb_close");

    return closerdb();
}


static err rdb_read(void* data, request* r, void* buffer, long* length) {
    static int count = 0;
    long size        = *length;
    err e            = NOERR;
    boolean save     = (getenv("SAVE_DATA_READRDB") != NULL);


    marslog(LOG_DBUG, "-> rdb_read: %ld bytes", *length);

    e = readrdb(buffer, length);
    marslog(LOG_DBUG, "<- rdb_read: %ld bytes", *length);
    if (*length > size)
        marslog(LOG_EROR, "Read %ld bytes > buffer size (%ld bytes)", *length, size);

    if (save) {
        FILE* fd;
        char fname[50];
        sprintf(fname, "readrdb.buffer.%d", count);
        if ((fd = fopen(fname, "w")) == NULL)
            marslog(LOG_EROR | LOG_PERR, "Error saving buffer read from RDB. Can't open file %s", fname);
        else {
            if (fwrite(buffer, 1, *length, fd) != *length)
                marslog(LOG_EROR | LOG_PERR, "Error writing to file %s", fname);
        }
        fclose(fd);
    }

    count++;
    if (e != NOERR)
        return EOF;

    return e;
}


static err rdb_write(void* data, request* r, void* buffer, long* length) {
    marslog(LOG_DBUG, "rdb_write:Not implemented");

    return NOERR;
}


static boolean rdb_check(void* data, request* r) {
    const char* type = get_value(r, "TYPE", 0);

    marslog(LOG_DBUG, "rdb_check: ");
    if (EQ(type, "OB"))
        return true;

    return false;
}

#else
#include "mars.h"
extern base_class _nullbase;
base_class* rdb_base = &_nullbase;
#endif
