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

#ifndef _H_MARS

/* For empress <c.h>  header file */
#define SYSTEM_BOOLEAN
#define _H_MARS

/* This is for name clashes with struct queue in sys/stream.h,
   included from netinet/in.h, and use of stl with mars. The
   define is reverted after mars has included the files.
   There is probably a safer way of doing this
*/

#include <float.h> /* for FLT_MAX */
#include <limits.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h> /* for clock_t */
#include <unistd.h>

#if mars_client_HAVE_RPC
#include <rpc/rpc.h>
#include <rpc/xdr.h>
#endif /* mars_client_HAVE_RPC */


/* when the ibm goes down, undef this variable. Even better, grep it
  and remove the code in it */
#define OBSOLETE


#define C2FORT(x) (x)


/*=======================================================================*/
/* Fortran types                                                         */

#if !defined(I32) && !defined(I64) && !defined(I128)
#define I32
#endif

#if !defined(R32) && !defined(R64) && !defined(R128)
#define R32
#endif

#define INT_MISSING_VALUE INT_MAX
#ifdef hpux
#define FLOAT_MISSING_VALUE 3.40282346638528859812E+38F
#else
#define FLOAT_MISSING_VALUE FLT_MAX
#endif


#ifdef I32
typedef int fortint; /* fortran integer */
#endif

#ifdef I64
typedef long long fortint;
#endif

#ifdef R32
typedef float fortfloat; /* fortran single precision float */
#define PFLOAT "f"
#endif

#ifdef R64
typedef double fortfloat;
#define FLOAT "lf"
#endif

/*===========================================================================*/
/* Common mars types                                                         */

#if !defined(__cplusplus) && !defined(c_plusplus)
#ifndef false
#define true 1
#define false 0
#endif
#endif

typedef int err;
typedef double real;
typedef long long long64;
typedef unsigned long long ulong64;
typedef int boolean;

#include "hash.h" /* must be here for rpcmars.h" */

#if mars_client_HAVE_RPC
#include "rpcmars.h"
#else
typedef char* cache_t;
typedef void* voidp_t;
struct value {
    /*  request part */
    struct value* next;
    cache_t name;
    /* language part */
    struct value* other_names;
    struct value* ref;
    struct value* expand;
};
typedef struct value value;

struct request {
    struct request* next;
    struct parameter* params;
    cache_t name;
    cache_t info;
    cache_t kind;
    voidp_t data; /* user data */
    long order;
};
typedef struct request request;

struct parameter {
    /*  request part */
    struct parameter* next;
    struct value* values;
    cache_t name;
    int count;
    struct request* subrequest;
    /* language part */
    struct value* default_values;
    struct value* current_values;
    struct value* ibm_values;
    struct request* interface;
};
typedef struct parameter parameter;

struct cache_index {
    struct request* index;
};
#endif

/*===========================================================================*/
/* Mars logging routines                                                     */
/*===========================================================================*/


#define LOG_DBUG 0    /* debugging message    */
#define LOG_INFO 1    /* informative message  */
#define LOG_WARN 2    /* warning message      */
#define LOG_EROR 3    /* error   message      */
#define LOG_EXIT 4    /* fatal error message  */
#define LOG_SMS 5     /* sms message  */
#define LOG_NONE 6    /* no prefix */
#define LOG_PERR 256  /* print errno          */
#define LOG_NOCR 512  /* no carriage-return   */
#define LOG_ONCE 1024 /* print messages only once */

typedef void (*loopproc)(const request*, int, char**, char**, void*);
typedef void (*exitproc)(int, void*);
typedef void (*cbackproc)(void*); /* simple call back */

/*===========================================================================*/
/* Usefull macros                                                            */
/*===========================================================================*/


#ifndef NUMBER
#define NUMBER(a) (sizeof(a) / sizeof(a[0])) /* number of elem. of an array */
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
#define ABS(a) ((a) < 0 ? -(a) : (a))
#define ROUND(a) ((long)((a) + 0.5))
#define EQ(a, b) ((*(a) == *(b)) && (strcmp(a, b) == 0))
#define LT(a, b) ((*(a) < *(b)) || (strcmp(a, b) < 0))


/*===========================================================================*/
/* Memory mamagement                                                         */
/*===========================================================================*/

/* Use the macros ... */

#define NEW(type) (type*)get_mem(sizeof(type))
#define NEW_CLEAR(type) (type*)get_mem_clear(sizeof(type))
#define MALLOC(size) get_mem(size)
#define NEW_ARRAY(type, cnt) (type*)get_mem((cnt) * (sizeof(type)))
#define NEW_ARRAY_CLEAR(type, cnt) (type*)get_mem_clear((cnt) * (sizeof(type)))
#define FREE(x) free_mem(x)
#define NEW_STRING(s) new_string(s)
#define REALLOC(x, n) re_alloc(x, n)
#define CLEAR(a) memset(&a, 0, sizeof(a))

typedef struct {
    int pages; /* Number of pages to allocate */
    int clear; /* clear newly allocated memory */
    void* priv;
} mempool;

extern mempool* permanent_mem;
extern mempool* transient_mem;


/*===========================================================================*/
/* Expand flags                                                              */
/*===========================================================================*/

#define EXPAND_DATE 1         /* expand dates           */
#define EXPAND_TIME 2         /* expand times           */
#define EXPAND_NO_OFF 4       /* remove off values      */
#define EXPAND_LAST_NAME 8    /* name is last           */
#define EXPAND_2ND_NAME 16    /* name is second         */
#define EXPAND_FIRST_NAME 32  /* name is first          */
#define EXPAND_LISTS 64       /* expand lists (not imp) */
#define EXPAND_NO_DEFAULT 128 /* expand, no default val */
#define EXPAND_DEFAULTS 512   /* expand, default as well*/
#define EXPAND_DONT_FAIL 1024 /* expand, don't fail     */
#define EXPAND_SUB_LISTS 2048 /* expand values into lists*/
#define EXPAND_STEP 4096      /* expand steps           */

#define EXPAND_MARS (EXPAND_DATE | EXPAND_TIME | EXPAND_STEP | EXPAND_NO_OFF | EXPAND_LAST_NAME | EXPAND_LISTS | EXPAND_SUB_LISTS)


/*===========================================================================*/
/* Schedule flags                                                            */
/*===========================================================================*/

#define SCHEDULE_FAIL 0x01
#define SCHEDULE_INFORM 0x02
#define SCHEDULE_LOG 0x04
#define SCHEDULE_INFORM_FUTURE_CHANGE 0x08
#define SCHEDULE_MAIL 0x10

/* compare two values */
typedef boolean (*namecmp)(const char*, const char*);
/*===========================================================================*/
/*                                                                           */
/*===========================================================================*/

/*===========================================================================*/
/* Lex & Yacc                                                                */
/*===========================================================================*/
#define YYMAXDEPTH 300

/*===========================================================================*/
/* Language                                                                  */
/*===========================================================================*/

typedef void (*lookupproc)(char*, void*);

/*===========================================================================*/
/* Networking                                                                */
/*===========================================================================*/

typedef void (*taskproc)(int, int, void*);
typedef void (*udpproc)(char*, int*, int, void*);

typedef struct udpinfo {
    int soc;
    struct sockaddr_in sin;
    struct timeval timeout;
} udpinfo;

typedef struct firewall_info firewall_info;


/*===========================================================================*/
/* Post-processing                                                           */
/*===========================================================================*/

/* Vector Post-processing */
typedef struct ppbuffer_t {
    char* buffer;
    long buflen;
    long inlen;
    long outlen;
} ppbuffer_t;

typedef err (*postproc)(ppbuffer_t*, long*);

/*===========================================================================*/
/* XDR                                                                   */
/*===========================================================================*/

#ifdef __linux__
typedef int (*xdrproc)(char*, char*, int);
#else
typedef int (*xdrproc)(void*, void*, int);
#endif

/*===========================================================================*/
/* Handler                                                                   */
/*===========================================================================*/

typedef err (*handlerproc)(request*, void*);

typedef struct handler {
    char* name;
    handlerproc proc;
    long flags;
} handler;

/*===========================================================================*/
/* Service                                                                   */
/*===========================================================================*/

typedef struct svc svc;


typedef struct svcid {
    struct svcid* next;
    request* r;
    svc* s;
    void* data;
} svcid;

typedef void (*svcproc)(svcid*, request*, void*);
typedef boolean (*inputproc)(FILE*, void*); /* return false on eof */

typedef struct svcprocs {
    struct svcprocs* next;
    char* name;
    svcproc proc;
    void* data;
    request* args;
} svcprocs;

typedef struct inputprocs {
    struct inputprocs* next;
    inputproc proc;
    void* data;
    FILE* f;
} inputprocs;

#if mars_client_HAVE_RPC
struct svc {
    int soc;
    XDR x;

    svcid* id;

    svcproc waitp; /* wait for      */
    err waite;     /* wait error    */

    svcprocs* serv; /* services   cb */
    svcprocs* repl; /* replies    cb */
    svcprocs* mess; /* messages   cb */
    svcprocs* prog; /* progession cb */
    svcprocs* fncs; /* functions  cb */
    svcprocs* drop; /* drag-drop  cb */

    inputprocs* input; /* input procs */

    boolean recording;

    int port; /* pid on server side */
    char* host;
    char* name;
    char* user; /* server only */

    long context;
    long flags;
    long timeout;

    long replies; /* number of outstanding replies */

    request* r;
};
#endif /* mars_client_HAVE_RPC */

/*===========================================================================*/
/* Service functions                                                         */
/*===========================================================================*/

enum argtype
{

    tnumber  = 1L, /* warning : for recording, it's a double ... */
    tstring  = 2L,
    tdate    = 4L,
    tmatrix  = 8L,
    tgrib    = 16L,
    tbufr    = 32L,
    tlist    = 64L,
    trequest = 128L,
    tfile    = 256L,
    tdefered = 512L,
    terror   = 1024L,
    timage   = 2048L,
    tvector  = 4096L,
    tgeopts  = 32768L,
    tvis5d   = 65536L,
    tnil     = 131072L,
    tnetcdf  = 262144L,
    tobject  = 524288L,
    todb     = 1048576L,
    ttable   = 2097152L,
    tgptset  = 4194304L,

    /* used only for recording .. */

    tinteger = 8192L,
    tboolean = 16384L,


    tany  = ~0L,
    tnone = 0L
};

typedef enum argtype argtype;

typedef struct {
    char* name;
    char* def;
    argtype kind;
} argdef;

/*===========================================================================*/
/* Stream                                                                    */
/*===========================================================================*/


typedef struct mstream {
    long64 in;
    long64 out;
    err error;
    void* data;
    int (*read)(void*, void*, int);
    int (*write)(void*, void*, int);
} mstream;

/*===========================================================================*/
/* Options                                                                   */
/*===========================================================================*/

typedef enum
{
    t_char,
    t_int,
    t_long,
    t_long64,
    t_str,
    t_str_random,
    t_ptr,
    t_double,
    t_boolean,
    t_fortfloat
} type;

typedef struct option {

    char* name;  /* Option name          */
    char* env;   /* Environment variable */
    char* opt;   /* command line option  */
    char* def;   /* default value        */
    type kind;   /* type of variable     */
    int size;    /* field size           */
    long offset; /* field offset         */

} option;

#define OFFSET(type, field) (((char*)(&(((type*)NULL)->field))) - ((char*)NULL))

typedef struct _wind wind;

/*===========================================================================*/
/* Time                                                                      */
/*===========================================================================*/
#define SECS_IN_DAY 86400

typedef long64 datetime;

typedef struct time_interval {

    datetime begin;
    datetime end;

} time_interval;

/*===========================================================================*/
/* Timer                                                                     */
/*===========================================================================*/

typedef struct timer {

    struct timeval start_;
    double timer_;
    boolean active_;
    char* name_;
    int count_;
    long64 total_;

    boolean elapsed_;
    double cpu_;
    double total_cpu_;

    char* statname_;

    struct timer* next_;
} timer;

/*===========================================================================*/
/* Errors                                                                    */
/*===========================================================================*/


#define NOERR 0
#ifndef EOF
#define EOF -1
#endif
#define BUF_TO_SMALL -3
#define COMPRESS_ERR -4
#define NOT_FOUND_7777 -5
#define END_REQUEST -6
#define HYPERCUBE_ERROR -7
#define POSTPROC_ERROR -8
#define FAILED_EXPAND -9
#define ODB_ERROR -10
#define QUOTA_ERROR -11
#define ODB_FOUND_EOF -12

#define NOT_READY_ERR -42
#define TOO_SHORT_ERR -43

#define RETRY_FOREVER_ERR -7776
#define RETRY_ERR -7777
#define RETRY_SAME_DATABASE -7778

#define EMPRESS_ERR -1000

#define QUALBUILD_ERR (-1 + EMPRESS_ERR)
#define LOCK_ERR (-2 + EMPRESS_ERR)
#define ADD_ERR (-3 + EMPRESS_ERR)
#define CONVERT_ERR (-4 + EMPRESS_ERR)
#define DUPLICATE_ERR (-5 + EMPRESS_ERR)
#define REQUEST_ERR (-6 + EMPRESS_ERR)
#define WRITEBLOB_ERR (-7 + EMPRESS_ERR)
#define OPENTABLE_ERR (-8 + EMPRESS_ERR)
#define UPDATE_ERR (-9 + EMPRESS_ERR)
#define ATTRLIST_ERR (-10 + EMPRESS_ERR)

typedef struct math {
    struct math* left;
    struct math* right;
    char* name;
    int arity;
} math;

typedef double (*mathproc)();
typedef err (*funcproc)(math*, mathproc);

typedef struct func {
    char* name;
    funcproc addr;
    mathproc proc;
    int arity;
    char* info;
} func;

#include "base.h"
#include "bufr.h"
#include "control.h"
#include "field.h"
#include "globals.h"
#include "grib.h"
#include "hypercube.h"
#include "index.h"
#include "lang.h"
#include "nctarget.h"
#include "tools.h"
#include "variable.h"

typedef struct marslist {
    struct marslist* next;
    char* name;
    void* data;
} marslist;


#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

/* used to certify requests */
typedef struct ECMarsCertReply eCMarsCertReply;

#include "api.h"
#include "cos.h"
#include "json.h"
#include "proto.h"
extern err parser(const char*, boolean);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif


#endif
