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

static void forward_init(void);
static err forward_open(void* data, request*, request*, int);
static err forward_close(void* data);
static err forward_read(void* data, request* r, void* buffer, long* length);
static err forward_write(void* data, request* r, void* buffer, long* length);
static boolean forward_check(void* data, request* r);
static err forward_validate(void* data, request*, request*, int);


typedef struct forwarddata {
    char* forward;
    char* defaultdbname;
    database* db;
} forwarddata;

static option opts[] = {
    {"forward", NULL, NULL, NULL, t_str, sizeof(char*),
     OFFSET(forwarddata, forward)},
    {"default", NULL, NULL, NULL, t_str, sizeof(char*),
     OFFSET(forwarddata, defaultdbname)},
};


base_class _forwardbase = {

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

    false, /* inited       */

    sizeof(forwarddata), /* private size */
    NUMBER(opts),        /* option count */
    opts,                /* options      */

    forward_init, /* init         */

    forward_open,  /* open         */
    forward_close, /* close        */

    forward_read,  /* read         */
    forward_write, /* write        */

    NULL, /* control      */

    forward_check, /* check        */
    NULL,          /* query        */

    NULL, /* archive      */
    NULL, /* admin        */

    forward_validate, /* validate */


};


base_class* forwardbase = &_forwardbase;

static void forward_init(void) {
}

static char* select_dbname(forwarddata* fdata, boolean report) {

    char* dbname = 0;

    if (fdata->forward) {

        dbname = getenv(fdata->forward);

        if (dbname)
            return dbname;

        if (report)
            marslog(LOG_DBUG, "Forward-base: forward environment variable not defined");
    }
    else {
        if (report)
            marslog(LOG_DBUG, "Forward-base: forward keyword not defined");
    }

    if (fdata->defaultdbname)
        return fdata->defaultdbname;

    if (report)
        marslog(LOG_DBUG, "Forward-base: default database name not defined");

    return 0;
}

static err forward_open(void* data, request* r, request* e, int mode) {
    const char* name;
    request* cachesetup = 0;

    forwarddata* fdata = (forwarddata*)data;

    char* dbname = select_dbname(fdata, true);

    if (!dbname) {
        marslog(LOG_EROR, "Forward-base: failed to select a database to forward to");
        return -2;
    }

    const request* setup = findbase(dbname, r);
    if (!setup)
        return -2;

    marslog(LOG_INFO, "Forward-base: forwarding to database %s", dbname);

    fdata->db = openbase(setup, r, &name, &cachesetup, READ_MODE);
    if (!fdata->db)
        return -2;

    return NOERR;
}

static err forward_close(void* data) {
    forwarddata* fdata = (forwarddata*)data;
    int ret            = 0;

    if (fdata->db != 0) {
        ret = database_close(fdata->db);
    }

    return ret;
}

static err forward_read(void* data, request* r, void* buffer, long* length) {
    forwarddata* fdata = (forwarddata*)data;

    return database_read(fdata->db, r, buffer, length);
}

static err forward_write(void* data, request* r, void* buffer, long* length) {
    marslog(LOG_EROR, "Cannot write on Forward-base");
    return -2;
}

static boolean forward_check(void* data, request* r) {
    forwarddata* fdata = (forwarddata*)data;
    return database_check(fdata->db, r);
}

static err forward_validate(void* data, request* r, request* e, int mode) {
    forwarddata* fdata = (forwarddata*)data;
    const char* name;
    const request* setup;
    int i;

    char* dbname = select_dbname(fdata, false);
    if (!dbname) {
        marslog(LOG_EROR, "Forward-base: failed to select a database to forward to");
        return -2;
    }

    setup = findbase(dbname, r);
    if (!setup)
        return -1;

    name = get_value(setup, "class", 0);
    if (database_validate(base_class_by_name(name), dbname, r, e, mode) != 0)
        return -1;

    return NOERR;
}
