/* sqlite.h  --  Generic functions to simplify SQLite3 queries - data structures defined here
 *
 *  GPLv2 only - Copyright (C) 2008 - 2012
 *               David Sommerseth <dazo@users.sourceforge.net>
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; version 2
 *  of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

/**
 * @file   sqlite.h
 * @author David Sommerseth <dazo@users.sourceforge.net>
 * @date   2008-08-06
 *
 * @brief  Generic functions to simplify the SQLite3 integration.
 *
 */

#ifndef   	SQLITE_H_
# define   	SQLITE_H_

#include <stdarg.h>
#ifdef HAVE_LIBXML2
# include <libxml/tree.h>
#endif
#include <eurephiadb_mapping.h>

/**
 *  Defines XML field types, used when extracting SQLite3 results directly into an xmlNode
 */
typedef enum _xmlFieldType { XML_ATTR, XML_NODE } xmlFieldType;

/**
 * Contains information about all fields/columns in an SQLite3 result.
 * It also keeps track over the length of the longest record/field value in the given field.
 *
 * This struct is built up as a dual-way chain pointer ring.  So you need to keep an eye
 * on the fieldid value to know if you have gone one round or not.
 */
typedef struct __sqlite_header {
        unsigned int fieldid;   /**< Numeric field ID, starts at 1 and increases */
        char *name;             /**< Name of the field/column */
        // char *type;
        size_t namelength;      /**< Length of the field name */
        size_t maxvaluelength;  /**< Length of the longest record in this column */
        struct __sqlite_header *next; /**< Pointer to the next field */
        struct __sqlite_header *prev; /**< Pointer to the previous field */
} _sqlite_header;


/**
 * Contains information about a particular data cell.  That means one specific record
 * in one specific column.
 *
 * This struct is built up as a dual-way chain pointer ring.  So you need to keep an eye
 * on the fieldid and/or tupleid value to know if you have gone one round or not.
 */
typedef struct __sqlite_tuples {
        unsigned int tupleid;   /**< Defines the "record number" */
        unsigned int fieldid;   /**< Defines the field ID this record belongs to */
        char *value;            /**< Pointer to the value of this field */
        size_t length;          /**< Length of the value of this field */
        _sqlite_header *header; /**< A pointer to the header record with more info about this field/column */
        struct __sqlite_tuples *nextfield; /**< Pointer to the same record, but the next field in it */
        struct __sqlite_tuples *prevfield; /**< Pointer to the same record, but the previous field in it */
        struct __sqlite_tuples *nexttuple; /**< Pointer to the same field, but the next record */
        struct __sqlite_tuples *prevtuple; /**< Pointer to the same field, but the previous record */
} _sqlite_tuples;


/**
 *  Defines dbresult status types
 */
typedef enum _QueryStatus { dbEMPTY,   /**< No SQL query has been performed */
                            dbSUCCESS, /**< SQL query was successful */
                            dbERROR,   /**< SQL query failed */
                            dbINVALID  /**< Invalid dbresult (NULL value) */
} QueryStatus;

/**
 *  Defines error severities
 */
typedef enum _ErrorSeverity { sevWARNING,   /**< Query returns some data, but with errors in completeing it */
                              sevERROR,     /**< Query could not complete, but may try again */
                              sevCRITICAL, /**< Query failed and there is no point of trying again */
                              sevPANIC      /**< Query failed and eurephia should shutdown */
} ErrorSeverity;

/**
 * The main definition of the dbresult strucutre.  This structure keeps the
 * complete information about both fields and values of all records from a query.
 *
 * This structure keeps to "search" pointers.  This is used when the sqlite_get_value() or
 * sqlite_xml_value() functions are called.  These pointers will point at the last record being looked
 * up, so that if you do sequencial look ups, it will not loop through the whole chain from the start.
 * Even if you go a little bit back an forth, it will find the quickest way to avoid as many iterations
 * as possible.
 */
typedef struct __sqlite_dbresult {
        QueryStatus status;           /**< Indicates if the query was successful or not */
        char *query;                  /**< Copy of the parsed SQL query */

        // Query results
        _sqlite_tuples *tuples;       /**< Pointer to the chains which contains field values */
        _sqlite_header *headerrec;    /**< Pointer to the chains with info about the field/columns */
        size_t num_tuples;            /**< Number of records received in the SELECT query */
        size_t num_fields;            /**< Number of fields for each record */
        sqlite_int64 last_insert_id;  /**< Reference to the last record from a INSERT INTO statement */
	int affected_rows;            /**< How many records where INSERTed, UPDATEd or DELETEd */

        // "Search" pointers
        _sqlite_tuples *srch_tuples;    /**< "Cache" of the last record being looked up */
        _sqlite_header *srch_headerrec; /**< "Cache" of the last header record being looked up */

        // Error handling
        ErrorSeverity errSeverity;      /**< Severity of the error  */
        char *errMsg;                   /**< If status == dbERROR, a error message can be found here */
} dbresult;


/**
 * Enumeration of suported SQL queries via the sqlite_query_mapped() API
 */
typedef enum _SQLqueryType { SQL_SELECT, SQL_INSERT, SQL_UPDATE, SQL_DELETE } SQLqueryType;


int sqlite_init_functions(eurephiaCTX *ctx);

/**
 * Free up a dbresult structure.  This is the public interface for the
 * internal function _sqlite_free_results()
 *
 * @param r Pointer to the dbresult to be freed
 */
#define sqlite_free_results(r) { _sqlite_free_results(r); r = NULL; }
void _sqlite_free_results(dbresult *);

void sqlite_log_error(eurephiaCTX *ctx, dbresult *dbres );
#ifdef HAVE_LIBXML2
xmlNode *sqlite_log_error_xml(eurephiaCTX *ctx, dbresult *dbres );
#endif

dbresult *sqlite_query(eurephiaCTX *ctx, const char *, ...);
dbresult *sqlite_query_mapped(eurephiaCTX *ctx, SQLqueryType type, const char *sqlstub,
                              eDBfieldMap *valMap, eDBfieldMap *whereMap, const char *sortkeys);
#define sqlite_query_status(res) (QueryStatus) (res != NULL ? res->status : dbINVALID)
char *sqlite_get_value(dbresult *res, int, int);
#ifdef HAVE_LIBXML2
xmlNodePtr sqlite_xml_value(xmlNodePtr node, xmlFieldType xmltyp, char *name, dbresult *res, int row, int col);
#endif
void sqlite_dump_result(FILE *, dbresult *);


/**
 * Retrieve number of tuples in a given dbresult structure
 *
 * @param dbres Pointer to a dbresult
 *
 * @return Returns number of rows/number of tuples in the result.
 */
#define sqlite_get_numtuples(dbres) (dbres != NULL ? dbres->num_tuples : 0)


/**
 * Retrieve number of affected tuples in current dbresult structure.  This is only useful
 * when called on a result from INSERT, UPDATE or DELETE queries.
 *
 * @param dbres Pointer to a dbresult
 *
 * @return Returns number of rows/tuples affected by the SQL query
 */
#define sqlite_get_affected_rows(dbres) (dbres != NULL ? dbres->affected_rows : 0)

#endif 	    /* !SQLITE_H_ */
