/*
 * © 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"
#include <ctype.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;
  }

  request* setup = findbase(dbname);
  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;
	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);
    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;
}
