/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 * In particular this file is part of the iWear Database Access Library.
 *
 * The iWear Framework 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 as in version 2 of the License.

 * 
 * The iWear Framework 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
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __DBCLASSES_IWDB_H
#define __DBCLASSES_IWDB_H

#ifndef __DBCLASSES_CONFIG_H
#include <dbclasses/config.h>
#endif

#ifndef __IWEAR_IWEAR_H
#include <iwear/iwear.h>
#endif

#ifndef __DBCLASSES_RECORDSET_H
#include <dbclasses/recordset.h>
#endif

#include <iwear/iwmutex.h>

extern "C" {
#include <stdint.h>
}

namespace iwear {
    namespace db {
/**
 * This class is a base representation of a Database Connection.
 */
class IWDB
{
private:
   /**
    * @name Worker Functions
    * These pure virtual functions really do the work on the database. They are
    * called from the api functions, that do a generic locking.
    * @see API Functions for details about parameters
    * @{
    */

   /**
    * This Function does the real work on a connect.
    */
    virtual int32_t do_connect( const string& dbh, const string& dbn, const string& dbu, const string& dbpw, const string& dbpar) = 0;
    virtual int32_t do_disconnect( void ) = 0;
    virtual int32_t do_query( const string& cmd) = 0;
    virtual int32_t do_query( const string& cmd, RecordSet*& RS) = 0;
    virtual int32_t do_transact(void) = 0;
    virtual int32_t do_commit(void) = 0;
    virtual int32_t do_rollback(void) = 0;
    virtual int32_t do_set_encoding( const string& ) = 0;
    /**
     * @}
     */
protected:
    string dbhost;
    string dbname;
    string dbusername;
    string dbpassword;

   /**
    * This flag is set to true if the database is in a connected state.
    */
    bool connected;

   /**
    * Keep Track of multiple level transactions via this variable.
    */
    uint32_t transaction_level;

   /**
    * This is the mutex to protect the access to a single database connection
    * through multiple threads (kind of multiplexing).
    * Derived classes must lock this in the following ways:
    *
    * - Lock at beginning of query, unlock at end.
    * - Lock at beginning of transact
    * - Unlock at the end of a commit and rollback
    * - Unlock when an exception is to be thrown within a locked state, and the
    *   DB is not in transaction state
    * @note This needs the use to be carefully to not totally lock the database
    * for the whole process when issuing transactions. Unfortunately this is
    * necessary to prevent other threads from writing during our transaction.
    * Beside this, you are advised to unlock the database as soon as possible.
    */
    IWMutex Mutex;
public:
   /**
    * We do nothing more here
    */
    IWDB( );

   /**
    * Make shure we really disconnect
    */
    virtual ~IWDB( );

   /**
    * This Function is the FrontEnd function for connecting to a database. It
    * will internally do necessary checks and locking common for all databases,
    * and then call do_connect()
    * @return 0 on Success, vendor specific error code otherwise. Often this is
    * a constant from cerrno, or its negative.
    * @param dbh Hostname where the database resides
    * @param dbn DBName of the Database
    * @param dbu UserName for Database Login
    * @param dbpw Password for logging into the database
    * @param dbpar Vendor specific parameter string. Usually empty.
    */
    int32_t DBConnect(  const string& dbh, const string& dbn,
	    		const string& dbu, const string& dbpw, const string& dbpar);

   /**
    * Disconnect from the database. In disconnected state, you cannot query the
    * database.
    * @return An error code, if any. 0 on Success.
    */
    int32_t DBDisconnect( void );

   /**
    * Query awaiting no result. This function will lock the database if
    * necessary, and then call do_query() internally.
    * @param cmd is the SQL Command String to be executed on the database.
    * @return an errorcode, if any. 0 on Success.
    */
    int32_t query( const string& cmd);

   /**
    * query that gets data out of the DB
    * @param cmd is the sql select string that will be sent to the database.
    * @param rs is a reference to a pointer to a recordset. The reason is that
    * different database incarnations will have different types of results,
    * that will be filled in here. In case the query failes, this throws an
    * exception and the pointer remains at its old value.
    */
    int32_t query( const string& cmd, RecordSet*& rs);

   /**
    * Start a Transaction. Databases that do not use a SQL98 Keyword for it
    * need to reimplement this function
    */
    int32_t transact( void );

   /**
    * Rolls back an active transaction. Without transaction this throws an
    * exception.
    */
    int32_t rollback( void );

   /**
    * Commits an transaction, without active transaction this throws an error.
    */
    int32_t commit( void );

   /**
    * This sets the encoding of the client system. This might be usefull if the
    * database has a different encoding, so they can be translated. The details
    * of this behaviour will certainly differ on implementations.
    */
    int32_t set_encoding( const string& );

   /**
    * This is to check for connected database backend. 
    * @return true if the connection is established
    * @note A more sophisticated derived class will shurely override this
    * function, since it can check more reliable for the connection state of
    * the database.
    */
    virtual bool is_connected( void ) { return connected; }
};
} // namespace iwear
}
#endif
