/***************************************************************************
 *   Copyright (C) 2005 by Roberto Cappuccio and the KAT Team              *
 *   Roberto Cappuccio : roberto.cappuccio@gmail.com                       *
 *                                                                         *
 *   Portions of the code contained in this file have been taken from      *
 *   CppSqlite3 - Copyright (C) 2004 Rob Groves                            *
 *   Rob Groves : rob.groves@btinternet.com                                *
 *                                                                         *
 *   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; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef _QtSQLite3_H_
#define _QtSQLite3_H_

#include <sqlite3.h>
#include <cstdio>
#include <cstring>
#include <string>
#include <qstring.h>

#include "kat_export.h"

#define QTSQLITE_ERROR 1000

using std::string;

class KAT_EXPORT QtSQLite3Exception
{
public:

    QtSQLite3Exception( const int nErrCode,
                        char* szErrMess,
                        bool bDeleteMsg = true );

    QtSQLite3Exception( const QtSQLite3Exception& e );

    virtual ~QtSQLite3Exception();

    const int errorCode() { return mnErrCode; }
    const char* errorMessage() { return mpszErrMess; }
    static const char* errorCodeAsString( int nErrCode );

private:

    int mnErrCode;
    char* mpszErrMess;
};

class KAT_EXPORT QtSQLite3Buffer
{
public:
    QtSQLite3Buffer();
    ~QtSQLite3Buffer();

    const char* format( const char* szFormat, ... );
    operator const char*() { return mpBuf; }
    void clear();

private:

    char* mpBuf;
};

class KAT_EXPORT QtSQLite3Binary
{
public:
    QtSQLite3Binary();
    ~QtSQLite3Binary();

    void setBinary( const unsigned char* pBuf, int nLen );
    void setEncoded( const unsigned char* pBuf );

    const unsigned char* getEncoded();
    const unsigned char* getBinary();

    int getBinaryLength();

    unsigned char* allocBuffer( int nLen );

    void clear();

private:

    unsigned char* mpBuf;
    int mnBinaryLen;
    int mnBufferLen;
    int mnEncodedLen;
    bool mbEncoded;
};

class KAT_EXPORT QtSQLite3Query
{
public:

    QtSQLite3Query();
    QtSQLite3Query( const QtSQLite3Query& rQuery );
    QtSQLite3Query( sqlite3* pDB, sqlite3_stmt* pVM, bool bEof, bool bOwnVM = true );
    QtSQLite3Query& operator = ( const QtSQLite3Query& rQuery );
    virtual ~QtSQLite3Query();

    int numFields();

    int fieldIndex( const QString& qsField );
    const char* fieldName( int nCol );

    const char* fieldDeclType( int nCol );
    int fieldDataType( int nCol );

    const char* fieldValue( int nField );
    const char* fieldValue( const QString& qsField );

    int getIntField( int nField, int nNullValue = 0 );
    int getIntField( const QString& qsField, int nNullValue = 0 );

    double getFloatField( int nField, double fNullValue = 0.0 );
    double getFloatField( const QString& qsField, double fNullValue = 0.0 );

    const QString getStringField( int nField );
    const QString getStringField( const QString& qsField );

    const unsigned char* getBlobField( int nField, int& nLen );
    const unsigned char* getBlobField( const QString& qsField, int& nLen );

    bool fieldIsNull( int nField );
    bool fieldIsNull( const QString& qsField );

    bool eof();

    void nextRow();

    void finalize();

private:

    void checkVM();

    sqlite3* mpDB;
    sqlite3_stmt* mpVM;
    bool mbEof;
    int mnCols;
    bool mbOwnVM;
};

class KAT_EXPORT QtSQLite3Table
{
public:

    QtSQLite3Table();
    QtSQLite3Table( const QtSQLite3Table& rTable );
    QtSQLite3Table( char** paszResults, int nRows, int nCols );
    virtual ~QtSQLite3Table();
    QtSQLite3Table& operator = ( const QtSQLite3Table& rTable );

    int numFields();

    int numRows();

    const char* fieldName( int nCol );

    const char* fieldValue( int nField );
    const char* fieldValue( const QString& qsField );

    int getIntField( int nField, int nNullValue = 0 );
    int getIntField( const QString& qsField, int nNullValue = 0 );

    double getFloatField( int nField, double fNullValue = 0.0 );
    double getFloatField( const QString& qsField, double fNullValue = 0.0 );

    const QString getStringField( int nField );
    const QString getStringField( const QString& qsField );

    bool fieldIsNull( int nField );
    bool fieldIsNull( const QString& qsField );

    void setRow( int nRow );

    void finalize();

private:

    void checkResults();

    int mnCols;
    int mnRows;
    int mnCurrentRow;
    char** mpaszResults;
};

class KAT_EXPORT QtSQLite3Statement
{
public:

    QtSQLite3Statement();
    QtSQLite3Statement( const QtSQLite3Statement& rStatement );
    QtSQLite3Statement( sqlite3* pDB, sqlite3_stmt* pVM );
    virtual ~QtSQLite3Statement();
    QtSQLite3Statement& operator = ( const QtSQLite3Statement& rStatement );

    int execDML();

    QtSQLite3Query execQuery();

    void bind( int nParam, const char* szValue );
    void bind( int nParam, const QString& qsValue );
    void bind( int nParam, const int nValue );
    void bind( int nParam, const unsigned int nValue );
    void bind( int nParam, const long lValue );
    void bind( int nParam, const unsigned long ulValue );
    void bind( int nParam, const double dwValue );
    void bind( int nParam, const unsigned char* blobValue, int nLen );
    void bind( int nParam, unsigned char* blobValue, int nLen );
    void bindNull( int nParam );

    void reset();

    void finalize();

private:

    void checkDB();
    void checkVM();

    sqlite3* mpDB;
    sqlite3_stmt* mpVM;
};

class KAT_EXPORT QtSQLite3DB
{
public:

    QtSQLite3DB();
    virtual ~QtSQLite3DB();

    void open( const QString& qsFile );

    void close();

    bool tableExists( const QString& qsTable );

    int execDML( const QString& qsSQL );

    QtSQLite3Query execQuery( const QString& qsSQL );

    int execScalar( const QString& qsSQL );

    QtSQLite3Table getTable( const QString& qsSQL );

    QtSQLite3Statement compileStatement( const QString& qsSQL );

    sqlite_int64 lastRowId();

    void interrupt() { sqlite3_interrupt( mpDB ); }

    void setBusyTimeout( int nMillisecs );

    static const char* SQLiteVersion() { return SQLITE_VERSION; }

private:

    QtSQLite3DB( const QtSQLite3DB& db );
    QtSQLite3DB& operator = ( const QtSQLite3DB& db );

    sqlite3_stmt* compile( const QString& qsSQL );

    void checkDB();

    sqlite3* mpDB;
    int mnBusyTimeoutMs;
};

#endif // _QtSQLite3_H_
