#ifndef _RS_DBI_H
#define _RS_DBI_H 1

/*
 * RS-DBI.h
 *
 * $Id$
 *
 * This package was developed as a part of Summer of Code program organized by Google.
 * Thanks to David A. James & Saikat DebRoy, the authors of RMySQL package.
 * Code from RMySQL package was reused with the permission from the authors.
 * Also Thanks to my GSoC mentor Dirk Eddelbuettel for helping me in the development.
 *
 * Processed with
 * indent --verbose -br -brs -i4 -nut --line-length120 --comment-line-length120 --leave-preprocessor-space -npcs
 *
 */


/* The following include file defines a number of C macros that hide
 * differences between R and S (e.g., the macro for type "Sint" expand
 * to "long" in the case of S and to int in the case of R, etc.)
 */

#ifdef __cplusplus
extern "C" {
#endif

#include "S4R.h"

#ifdef WIN32
#include <process.h>
#else
#include <unistd.h>
#endif

#include<ctype.h>               /* NOTE:added this header because of using isalpha in RS-DBI.c -sameer */

//    pid_t getpid();


    /* We now define 4 important data structures:
     * RS_DBI_manager, RS_DBI_connection, RS_DBI_resultSet, and
     * RS_DBI_fields, corresponding to dbManager, dbConnection,
     * dbResultSet, and list of field descriptions.
     */
    /* In R/S a dbObject is a foreign reference consisting of a vector
     * of 1, 2 or 3 integers.  In the C implementation we use these
     * R/S vectors as handles (we could have use pointers).
     */
    typedef enum enum_dbi_exception {
        RS_DBI_MESSAGE,
        RS_DBI_WARNING,
        RS_DBI_ERROR,
        RS_DBI_TERMINATE
    } DBI_EXCEPTION;

    /* dbObject handles are simple S/R integer vectors of 1, 2, or 3 integers
     * the *_ID macros extract the appropriate scalar.
     */

#define Mgr_Handle s_object
#define Con_Handle s_object
#define Res_Handle s_object
#define Db_Handle  s_object     /* refers to any one of the above */
    /* The integer value for the following enum's needs to equal
     * GET_LENGTH(handle) for the various handles.
     */
    typedef enum enum_handle_type {
        MGR_HANDLE_TYPE = 1,    /* dbManager handle */
        CON_HANDLE_TYPE = 2,    /* dbConnection handle */
        RES_HANDLE_TYPE = 3     /* dbResult handle */
    } HANDLE_TYPE;

#define MGR_ID(handle) INT_EL((handle),0)       /* the actual scalar mgr id */
#define CON_ID(handle) INT_EL((handle),1)
#define RES_ID(handle) INT_EL((handle),2)

    /* First, the following fully describes the field output by a select
     * (or select-like) statement, and the mappings from the internal
     * database types to S classes.  This structure contains the info we need
     * to build the R/S list (or data.frame) that will receive the SQL
     * output.  It still needs some work to handle arbitrty BLOB's (namely
     * methods to map BLOBs into user-defined S objects).
     * Each element is an array of num_fields, this flds->Sclass[3] stores
     * the S class for the 4th output fields.
     */
    typedef struct st_sdbi_fields {
        int num_fields;
        char **name;            /* DBMS field names */
        int *type;             /* DBMS internal types */
        int *length;           /* DBMS lengths in bytes */
        int *precision;        /* DBMS num of digits for numeric types */
        int *scale;            /* DBMS num of decimals for numeric types */
        int *nullOk;           /* DBMS indicator for DBMS'  NULL type */
        int *isVarLength;      /* DBMS variable-length char type */
        Stype *Sclass;          /* R/S class (type) -- may be overriden */
        /* TODO: Need a table of fun pointers to converters */
    } RS_DBI_fields;

    typedef struct st_sdbi_exception {
        DBI_EXCEPTION exceptionType;    /* one of RS_DBI_WARN, RS_RBI_ERROR, etc */
        int errorNum;           /* SQL error number (possibly driver-dependent */
        char *errorMsg;         /* SQL error message */
    } RS_DBI_exception;

    /* The RS-DBI resultSet consists of a pointer to the actual DBMS
     * resultSet (e.g., MySQL, Oracle) possibly NULL,  plus the fields
     * defined by the RS-DBI implementation.
     */
    typedef struct st_sdbi_resultset {
        void *drvResultSet;     /* the actual (driver's) cursor/result set */
        void *drvData;          /* a pointer to driver-specific data */
        int managerId;         /* the 3 *Id's are used for   */
        int connectionId;      /* validating stuff coming from S */
        int resultSetId;
        int isSelect;          /* boolean for testing SELECTs */
        char *statement;        /* SQL statement */
        int rowsAffected;      /* used by non-SELECT statements */
        int rowCount;          /* rows fetched so far (SELECT-types) */
        int completed;         /* have we fetched all rows? */
        RS_DBI_fields *fields;
    } RS_DBI_resultSet;

    /* A dbConnection consists of a pointer to the actual implementation
     * (MySQL, Oracle, etc.) connection plus a resultSet and other
     * goodies used by the RS-DBI implementation.
     * The connection parameters (user, password, database name, etc.) are
     * defined by the actual driver -- we just set aside a void pointer.
     */

    typedef struct st_sdbi_connection {
        void *conParams;        /* pointer to connection params (host, user, etc) */
        void *drvConnection;    /* pointer to the actual DBMS connection struct */
        void *drvData;          /* to be used at will by individual drivers */
        RS_DBI_resultSet **resultSets;  /* vector to result set ptrs  */
        int *resultSetIds;
        int length;            /* max num of concurrent resultSets */
        int num_res;           /* num of open resultSets */
        int counter;           /* total number of queries */
        int managerId;
        int connectionId;
        RS_DBI_exception *exception;
    } RS_DBI_connection;

    /* dbManager */
    typedef struct st_sdbi_manager {
        char *drvName;          /* what driver are we implementing? */
        void *drvData;          /* to be used by the drv implementation */
        RS_DBI_connection **connections;        /* list of dbConnections */
        int *connectionIds;    /* array of connectionIds */
        int length;            /* max num of concurrent connections */
        int num_con;           /* num of opened connections */
        int counter;           /* num of connections handled so far */
        int fetch_default_rec; /* default num of records per fetch */
        int managerId;         /* typically, process id */
        RS_DBI_exception *exception;
    } RS_DBI_manager;

    /* All RS_DBI functions and their signatures */

    /* Note: the following alloc functions allocate the space for the
     * corresponding manager, connection, resultSet; they all
     * return handles.  All DBI functions (free/get/etc) use the handle
     * to work with the various dbObjects.
     */
    Mgr_Handle *RS_DBI_allocManager(const char *drvName, int max_con, int fetch_default_rec, int force_realloc);
    void RS_DBI_freeManager(Mgr_Handle * mgrHandle);
    RS_DBI_manager *RS_DBI_getManager(Db_Handle * handle);
    Mgr_Handle *RS_DBI_asMgrHandle(int pid);
    s_object *RS_DBI_managerInfo(Mgr_Handle * mgrHandle);

    /* dbConnection */
    Con_Handle *RS_DBI_allocConnection(Mgr_Handle * mgrHandle, int max_res);
    void RS_DBI_freeConnection(Con_Handle * conHandle);
    RS_DBI_connection *RS_DBI_getConnection(Db_Handle * handle);
    Con_Handle *RS_DBI_asConHandle(int mgrId, int conId);
    s_object *RS_DBI_connectionInfo(Con_Handle * con_Handle);

    /* dbResultSet */
    Res_Handle *RS_DBI_allocResultSet(Con_Handle * conHandle);
    void RS_DBI_freeResultSet(Res_Handle * rsHandle);
    RS_DBI_resultSet *RS_DBI_getResultSet(Res_Handle * rsHandle);
    Res_Handle *RS_DBI_asResHandle(int pid, int conId, int resId);
    s_object *RS_DBI_resultSetInfo(Res_Handle * rsHandle);

    /* utility funs */
    s_object *RS_DBI_validHandle(Db_Handle * handle);   /* callable from S/R */
    int is_validHandle(Db_Handle * handle, HANDLE_TYPE handleType);

    /* a simple object database (mapping table) -- it uses simple linear
     * search (we don't expect to have more than a handful of simultaneous
     * connections and/or resultSets. If this is not the case, we could
     * use a hash table, but I doubt it's worth it (famous last words!).
     * These are used for storing/retrieving object ids, such as
     * connection ids from the manager object, and resultSet ids from a
     * connection object;  of course, this is transparent to the various
     * drivers -- they should deal with handles exclusively.
     */
    int RS_DBI_newEntry(int * table, int length);
    int RS_DBI_lookup(int * table, int length, int obj_id);
    int RS_DBI_listEntries(int * table, int length, int * entries);
    void RS_DBI_freeEntry(int * table, int indx);

    /* description of the fields in a result set */
    RS_DBI_fields *RS_DBI_allocFields(int num_fields);
    s_object *RS_DBI_getFieldDescriptions(RS_DBI_fields * flds);
    void RS_DBI_freeFields(RS_DBI_fields * flds);

    /* we (re)allocate the actual output list in here (with the help of
     * RS_DBI_fields).  This should be some kind of R/S "relation"
     * table, not a dataframe nor a list.
     */
    void RS_DBI_allocOutput(s_object * output, RS_DBI_fields * flds, int num_rec, int expand);
    void RS_DBI_makeDataFrame(s_object * data);

    /* TODO: We need to elevate RS_DBI_errorMessage to either
     * dbManager and/or dbConnection methods.  I still need to
     * go back and re-code the error-handling throughout, darn!
     */
    void RS_DBI_errorMessage(char *msg, DBI_EXCEPTION exceptionType);
    void RS_DBI_setException(Db_Handle * handle, DBI_EXCEPTION exceptionType, int errorNum, const char *errorMsg);
    /* utility funs (copy strings, convert from R/S types to string, etc. */
    char *RS_DBI_copyString(const char *str);
    char *RS_DBI_nCopyString(const char *str, size_t len, int del_blanks);

    /* We now define a generic data type name-Id mapping struct
     * and initialize the RS_dataTypeTable[].  Each driver could
     * define similar table for generating friendly type names
     */
    struct data_types {
        char *typeName;
        int typeId;
    };

    /* return the primitive type name for a primitive type id */
    const char *RS_DBI_getTypeName(int typeCode, const struct data_types table[]);
    /* same, but callable from S/R and vectorized */
    s_object *RS_DBI_SclassNames(s_object * types);

    s_object *RS_DBI_createNamedList(char **names, Stype * types, int * lengths, int n);
    s_object *RS_DBI_copyFields(RS_DBI_fields * flds);

    void RS_na_set(void *ptr, Stype type);
    int RS_is_na(void *ptr, Stype type);
    extern const struct data_types RS_dataTypeTable[];

#ifdef __cplusplus
}
#endif
#endif                          /* _RS_DBI_H */
