/***************************************************************************
                          mymoneystoragesql.h
                          -------------------
    begin                : 11 November 2005
    copyright            : (C) 2005 by Tony Bloomfield
    email                : tonybloom@users.sourceforge.net
                         : Fernando Vilas <fvilas@iname.com>
 ***************************************************************************/

#ifndef MYMONEYSTORAGESQL_H
#define MYMONEYSTORAGESQL_H

// ----------------------------------------------------------------------------
// QT Includes

#include <tqsqldatabase.h>
#include <tqsqlquery.h>
#include <tqsqlerror.h>
#include <tqvaluestack.h>

class TQIODevice;
// ----------------------------------------------------------------------------
// KDE Includes

#include <kurl.h>
#include <ksharedptr.h>

// ----------------------------------------------------------------------------
// Project Includes

#include "imymoneystorageformat.h"
#include "../mymoneyinstitution.h"
#include "../mymoneypayee.h"
#include "../mymoneyaccount.h"
#include "../mymoneytransaction.h"
#include "../mymoneysplit.h"
#include "../mymoneyscheduled.h"
#include "../mymoneysecurity.h"
#include "../mymoneyprice.h"
#include "../mymoneyreport.h"
#include "../mymoneybudget.h"
#include "../mymoneyfile.h"
#include "../mymoneykeyvaluecontainer.h"
#include "mymoneymap.h"
#include "../mymoneymoney.h"
#include "../mymoneytransactionfilter.h"

// This is a convenience functor to make it easier to use STL algorithms
// It will return false if the MyMoneyTransaction DOES match the filter.
// This functor may disappear when all filtering can be handled in SQL.
class FilterFail {
  public:
    FilterFail (const MyMoneyTransactionFilter& filter,
                   IMyMoneyStorage* storage)
      : m_filter (filter),
        m_storage (storage)
    {}

    inline bool operator() (const TQPair<TQString, MyMoneyTransaction>& transactionPair)
    { return (*this) (transactionPair.second); }

    inline bool operator() (const MyMoneyTransaction& transaction)
    {
      return (! m_filter.match(transaction)) && (m_filter.matchingSplits().count() == 0);
    }

  private:
    MyMoneyTransactionFilter m_filter;
    IMyMoneyStorage *m_storage;
};

/**
@author Tony Bloomfield
 */
typedef enum databaseTypeE { // database (driver) type
  Db2 = 0, //
  Interbase, //
  Mysql, //
  Oracle8, //
  ODBC3, //
  Postgresql, //
  Sqlite, //
  Sybase, //
  Sqlite3 //
} _databaseType;

class MyMoneyStorageSql;

/**
  * The MyMoneySqlQuery class is derived from TQSqlQuery to provide
  * a way to adjust some queries based on databaseTypeE and make
  * debugging easier by providing a place to put debug statements.
  */
class MyMoneySqlQuery : public TQSqlQuery {
  public:
    MyMoneySqlQuery (MyMoneyStorageSql* db = 0);
    virtual ~MyMoneySqlQuery() {}
    bool exec ();
    bool prepare ( const TQString & query );
  private:
    const MyMoneyStorageSql* m_db;
};

/**
  * The MyMoneyDbDrivers class is a map from string to enum of db types.
  */
class MyMoneyDbDrivers {
  public:
    MyMoneyDbDrivers ();
    /**
      *  @return a list ofsupported TQt database driver types, their qt names and useful names
      **/
    const TQMap<TQString, TQString> driverMap() const {return (m_driverMap);};
    databaseTypeE driverToType (const TQString& driver) const;
    bool isTested (databaseTypeE dbType) const;
  private:
    TQMap<TQString, TQString> m_driverMap;
};

/**
  * The MyMoneyDbColumn class is a base type for generic db columns.
  * Derived types exist for several common column types.
  */
class MyMoneyDbColumn : public TDEShared {
  public:
    MyMoneyDbColumn (const TQString& iname,
             const TQString& itype = TQString(),
             const bool iprimary = false,
             const bool inotnull = false,
             const TQString &initVersion = "0.1"):
    m_name(iname),
    m_type(itype),
    m_isPrimary(iprimary),
    m_isNotNull(inotnull),
    m_initVersion(initVersion) {}
    MyMoneyDbColumn (void) {}
    virtual ~MyMoneyDbColumn () {}

    /**
      * This method is used to copy column objects. Because there are several derived types,
      * clone() is more appropriate than a copy ctor in most cases.
      */
    virtual MyMoneyDbColumn* clone () const;

    /**
      * This method generates the DDL (Database Design Language) string for the column.
      *
      * @param dbType Database driver type
      *
      * @return TQString of the DDL for the column, tailored for what the driver supports.
      */
    virtual const TQString generateDDL (databaseTypeE dbType) const;

    const TQString& name(void) const {return (m_name);}
    const TQString& type(void) const {return (m_type);}
    bool isPrimaryKey(void) const {return (m_isPrimary);}
    bool isNotNull(void) const {return (m_isNotNull);}
  private:
    TQString m_name;
    TQString m_type;
    bool m_isPrimary;
    bool m_isNotNull;
    TQString m_initVersion;
};

/**
  * The MyMoneyDbDatetimeColumn class is a representation of datetime columns.
  */
class MyMoneyDbDatetimeColumn : public MyMoneyDbColumn {
  public:
    MyMoneyDbDatetimeColumn (const TQString& iname,
                             const bool iprimary = false,
                             const bool inotnull = false,
                             const TQString &initVersion = "0.1"):
            MyMoneyDbColumn (iname, "", iprimary, inotnull, initVersion)
            {}
    virtual ~MyMoneyDbDatetimeColumn() {}
    virtual const TQString generateDDL (databaseTypeE dbType) const;
    virtual MyMoneyDbDatetimeColumn* clone () const;
  private:
    static const TQString calcType(void);
};

/**
  * The MyMoneyDbColumn class is a representation of integer db columns.
  */
class MyMoneyDbIntColumn : public MyMoneyDbColumn {
  public:
    enum size {TINY, SMALL, MEDIUM, BIG};
    MyMoneyDbIntColumn (const TQString& iname,
                        const size type = MEDIUM,
                        const bool isigned = true,
                        const bool iprimary = false,
                        const bool inotnull = false,
             const TQString &initVersion = "0.1"):
        MyMoneyDbColumn (iname, "", iprimary, inotnull, initVersion),
    m_type  (type),
    m_isSigned (isigned) {}
    virtual ~MyMoneyDbIntColumn() {}
    virtual const TQString generateDDL (databaseTypeE dbType) const;
    virtual MyMoneyDbIntColumn* clone () const;
  private:
    size m_type;
    bool m_isSigned;
};

/**
  * The MyMoneyDbTextColumn class is a representation of text db columns,
  * for drivers that support it.  If the driver does not support it, it is
  * usually some sort of really large varchar or varchar2.
  */
class MyMoneyDbTextColumn : public MyMoneyDbColumn {
  public:
    enum size {TINY, NORMAL, MEDIUM, LONG};
    MyMoneyDbTextColumn (const TQString& iname,
                         const size type = MEDIUM,
                         const bool iprimary = false,
                         const bool inotnull = false,
             const TQString &initVersion = "0.1"):
        MyMoneyDbColumn (iname, "", iprimary, inotnull, initVersion),
    m_type  (type) {}
    virtual ~MyMoneyDbTextColumn() {}
    virtual const TQString generateDDL (databaseTypeE dbType) const;
    virtual MyMoneyDbTextColumn* clone () const;
  private:
    size m_type;
};

/**
  * The MyMoneyDbIndex class is a representation of a db index.
  * To provide generic support for most databases, the table name,
  * name of the index, and list of columns for the index are required.
  * Additionally, the user can specify whether the index is unique or not.
  *
  * At this time, different types of index are not supported, since the portability
  * is fairly limited.
  */
class MyMoneyDbIndex {
  public:
    MyMoneyDbIndex (const TQString& table,
                    const TQString& name,
                    const TQStringList& columns,
                    bool unique = false):
      m_table(table),
      m_unique(unique),
      m_name(name),
      m_columns(columns)
      {}
    MyMoneyDbIndex () {}
    inline const TQString table () const {return m_table;}
    inline bool isUnique () const {return m_unique;}
    inline const TQString name () const {return m_name;}
    inline const TQStringList columns () const {return m_columns;}
    const TQString generateDDL (databaseTypeE dbType) const;
  private:
    TQString m_table;
    bool m_unique;
    TQString m_name;
    TQStringList m_columns;
};

/**
  * The MyMoneyDbTable class is a representation of a db table.
  * It has a list of the columns (pointers to MyMoneyDbColumn types) and a
  * list of any indices that may be on the table.
  * Additionally, a string for a parameterized query for each of some common
  * tasks on a table is created by the ctor.
  *
  * Const iterators over the list of columns are provided as a convenience.
  */
class MyMoneyDbTable {
  public:
    MyMoneyDbTable (const TQString& iname,
             const TQValueList<TDESharedPtr <MyMoneyDbColumn> >& ifields,
             const TQString& initVersion = "1.0"):
    m_name(iname),
    m_fields(ifields),
    m_initVersion(initVersion) {}
    MyMoneyDbTable (void) {}

    inline const TQString& name(void) const {return (m_name);}
    inline const TQString& insertString(void) const {return (m_insertString);};
    inline const TQString selectAllString(bool terminate = true) const
      {return (terminate ? TQString(m_selectAllString + ";") : m_selectAllString);};
    inline const TQString& updateString(void) const {return (m_updateString);};
    inline const TQString& deleteString(void) const {return (m_deleteString);};

    /**
      * This method determines the string required to drop the primary key for the table
      * based on the db specific syntax.
      *
      * @param dbType The driver type of the database.
      *
      * @return TQString for the syntax to drop the primary key.
      */
    const TQString dropPrimaryKeyString(databaseTypeE dbType) const;
    /**
      * This method returns a comma-separated list of all column names in the table
      *
      * @return TQString column list.
      */
    const TQString columnList() const;
    /**
      * This method returns the string for changing a column's definition.  It covers statements
      * like ALTER TABLE..CHANGE COLUMN, MODIFY COLUMN, etc.
      *
      * @param dbType The driver type of the database.
      * @param columnName The name of the column to be modified.
      * @param newDef The MyMoneyColumn object of the new column definition.
      *
      * @return TQString containing DDL to change the column.
      */
    const TQString modifyColumnString(databaseTypeE dbType, const TQString& columnName, const MyMoneyDbColumn& newDef) const;

    /**
      * This method builds all of the SQL strings for common operations.
      */
    void buildSQLStrings(void);

    /**
      * This method generates the DDL required to create the table.
      *
      * @param dbType The driver type of the database.
      *
      * @return TQString of the DDL.
      */
    const TQString generateCreateSQL (databaseTypeE dbType) const;

    /**
      * This method creates a MyMoneyDbIndex object and adds it to the list of indices for the table.
      *
      * @param name The name of the index.
      * @param columns The list of the columns affected.
      * @param unique Whether or not this should be a unique index.
      */
    void addIndex(const TQString& name, const TQStringList& columns, bool unique = false);

    typedef TQValueList<TDESharedPtr <MyMoneyDbColumn> >::const_iterator field_iterator;
    inline field_iterator begin(void) const {return m_fields.constBegin();}
    inline field_iterator end(void) const {return m_fields.constEnd(); }
  private:
    TQString m_name;
    TQValueList<TDESharedPtr <MyMoneyDbColumn> > m_fields;

    typedef TQValueList<MyMoneyDbIndex>::const_iterator index_iterator;
    TQValueList<MyMoneyDbIndex> m_indices;
    TQString m_initVersion;
    TQString m_insertString; // string to insert a record
    TQString m_selectAllString; // to select all fields
    TQString m_updateString;  // normal string for record update
    TQString m_deleteString; // string to delete 1 record
};

/**
  * The MyMoneyDbView class is a representation of a db view.
  *
  * Views will be dropped and recreated on upgrade, so there is no need
  * to do anything more complex than storing the name of the view and
  * the CREATE VIEW string.
  */
class MyMoneyDbView {
  public:
    MyMoneyDbView (const TQString& name,
                   const TQString& createString,
                   const TQString& initVersion = "0.1")
    : m_name (name), m_createString (createString), m_initVersion (initVersion)
    {}

    MyMoneyDbView (void) {}

    inline const TQString& name(void) const {return (m_name);}
    inline const TQString createString(void) const {return (m_createString);};

  private:
    TQString m_name;
    TQString m_createString;
    TQString m_initVersion;
};

/**
  * The MyMoneyDbDef class is
  */
class MyMoneyDbDef  {
  friend class MyMoneyStorageSql;
  friend class MyMoneyDatabaseMgr;
public:
    MyMoneyDbDef();
    ~MyMoneyDbDef() {}

    const TQString generateSQL (const TQString& driver) const;

    typedef TQMap<TQString, MyMoneyDbTable>::const_iterator table_iterator;
    inline table_iterator tableBegin(void) const {return m_tables.constBegin();}
    inline table_iterator tableEnd(void) const {return m_tables.constEnd();}

    typedef TQMap<TQString, MyMoneyDbView>::const_iterator view_iterator;
    inline view_iterator viewBegin(void) const {return m_views.constBegin();}
    inline view_iterator viewEnd(void) const {return m_views.constEnd();}

    inline unsigned int currentVersion() const {return (m_currentVersion);};

private:
  const TQString enclose(const TQString& text) const
    {return (TQString("'" + text + "'"));};
  static unsigned int m_currentVersion; // The current version of the database layout
  MyMoneyDbDrivers m_drivers;
#define TABLE(name) void name();
#define VIEW(name) void name();
  TABLE(FileInfo);
  TABLE(Institutions);
  TABLE(Payees);
  TABLE(Accounts);
  TABLE(Transactions);
  TABLE(Splits);
  TABLE(KeyValuePairs);
  TABLE(Schedules);
  TABLE(SchedulePaymentHistory);
  TABLE(Securities);
  TABLE(Prices);
  TABLE(Currencies);
  TABLE(Reports);
  TABLE(Budgets);
  VIEW(Balances);
protected:
  TQMap<TQString, MyMoneyDbTable> m_tables;
  TQMap<TQString, MyMoneyDbView> m_views;
};

class IMyMoneySerialize;

/**
  * The MyMoneyDbColumn class is a base type for generic db columns.
  * Derived types exist for several common column types.
  */
class MyMoneyStorageSql : public IMyMoneyStorageFormat, public TQSqlDatabase, public TDEShared {
public:

  MyMoneyStorageSql (IMyMoneySerialize *storage, const KURL& = KURL());
  virtual ~MyMoneyStorageSql() {close(true);}

  unsigned int currentVersion() const {return (m_db.currentVersion());};

    /**
   * MyMoneyStorageSql - open database file
   *
   * @param url pseudo-URL of database to be opened
   * @param openMode open mode, same as for TQFile::open
   * @param clear whether existing data can be deleted

   * @return 0 - database successfully opened
   * @return 1 - database not opened, use lastError function for reason
   * @return -1 - output database not opened, contains data, clean not specified
   *
     */
  int open(const KURL& url, int openMode, bool clear = false);
  /**
   * MyMoneyStorageSql close the database
   *
   * @return void
   *
   */
  void close(bool logoff = true);
  /**
   * MyMoneyStorageSql read all the database into storage
   *
   * @return void
   *
   */
  bool readFile(void);
  /**
   * MyMoneyStorageSql write/update the database from storage
   *
   * @return void
   *
   */
  bool writeFile(void);

  // check database type
  bool isDb2() const { return (m_dbType == Db2);};
  bool isInterbase() const { return (m_dbType == Interbase);};
  bool isMysql() const { return (m_dbType == Mysql);};
  bool isOracle8() const { return (m_dbType == Oracle8);};
  bool isODBC3() const { return (m_dbType == ODBC3);};
  bool isPostgresql() const { return (m_dbType == Postgresql);};
  bool isSybase() const { return (m_dbType == Sybase);};
  bool isSqlite3() const { return (m_dbType == Sqlite3);};

    /**
   * MyMoneyStorageSql generalized error routine
   *
   * @return : error message to be displayed
   *
     */
  const TQString& lastError() const {return (m_error);};
  /**
   * This method is used when a database file is open, and the data is to
   * be saved in a different file or format. It will ensure that all data
   * from the database is available in memory to enable it to be written.
   */
  virtual void fillStorage();
  /**
    * The following functions correspond to the identically named (usually) functions
    * within the Storage Manager, and are called to update the database
    */
  void modifyUserInfo(const MyMoneyPayee& payee);
  void addInstitution(const MyMoneyInstitution& inst);
  void modifyInstitution(const MyMoneyInstitution& inst);
  void removeInstitution(const MyMoneyInstitution& inst);
  void addPayee(const MyMoneyPayee& payee);
  void modifyPayee(const MyMoneyPayee& payee);
  void removePayee(const MyMoneyPayee& payee);
  void addAccount(const MyMoneyAccount& acc);
  void modifyAccount(const MyMoneyAccount& acc);
  void removeAccount(const MyMoneyAccount& acc);
  void addTransaction(const MyMoneyTransaction& tx);
  void modifyTransaction(const MyMoneyTransaction& tx);
  void removeTransaction(const MyMoneyTransaction& tx);
  void addSchedule(const MyMoneySchedule& sch);
  void modifySchedule(const MyMoneySchedule& sch);
  void removeSchedule(const MyMoneySchedule& sch);
  void addSecurity(const MyMoneySecurity& sec);
  void modifySecurity(const MyMoneySecurity& sec);
  void removeSecurity(const MyMoneySecurity& sec);
  void addPrice(const MyMoneyPrice& p);
  void removePrice(const MyMoneyPrice& p);
  void addCurrency(const MyMoneySecurity& sec);
  void modifyCurrency(const MyMoneySecurity& sec);
  void removeCurrency(const MyMoneySecurity& sec);
  void addReport(const MyMoneyReport& rep);
  void modifyReport(const MyMoneyReport& rep);
  void removeReport(const MyMoneyReport& rep);
  void addBudget(const MyMoneyBudget& bud);
  void modifyBudget(const MyMoneyBudget& bud);
  void removeBudget(const MyMoneyBudget& bud);

  unsigned long transactionCount  (const TQString& aid = TQString()) const;
  inline const TQMap<TQString, unsigned long> transactionCountMap () const
      {return (m_transactionCountMap);};
  /**
    * the storage manager also needs the following read entry points
    */
  const TQMap<TQString, MyMoneyAccount> fetchAccounts (const TQStringList& idList = TQStringList (), bool forUpdate = false) const;
  const TQMap<TQString, MyMoneyMoney> fetchBalance(const TQStringList& id, const TQDate& date) const;
  const TQMap<TQString, MyMoneyBudget> fetchBudgets (const TQStringList& idList = TQStringList (), bool forUpdate = false) const;
  const TQMap<TQString, MyMoneySecurity> fetchCurrencies (const TQStringList& idList = TQStringList (), bool forUpdate = false) const;
  const TQMap<TQString, MyMoneyInstitution> fetchInstitutions (const TQStringList& idList = TQStringList (), bool forUpdate = false) const;
  const TQMap<TQString, MyMoneyPayee> fetchPayees (const TQStringList& idList = TQStringList (), bool forUpdate = false) const;
  const  MyMoneyPriceList fetchPrices (const TQStringList& fromIdList = TQStringList (), const TQStringList& toIdList = TQStringList(), bool forUpdate = false) const;
  const  MyMoneyPrice fetchSinglePrice (const TQString& fromIdList, const TQString& toIdList, const TQDate& date, bool exactDate, bool forUpdate = false) const;
  const TQMap<TQString, MyMoneyReport> fetchReports (const TQStringList& idList = TQStringList (), bool forUpdate = false) const;
  const TQMap<TQString, MyMoneySchedule> fetchSchedules (const TQStringList& idList = TQStringList (), bool forUpdate = false) const;
  const TQMap<TQString, MyMoneySecurity> fetchSecurities (const TQStringList& idList = TQStringList (), bool forUpdate = false) const;
  const TQMap<TQString, MyMoneyTransaction> fetchTransactions (const TQString& tidList = TQString (), const TQString& dateClause = TQString(), bool forUpdate = false) const;
  const TQMap<TQString, MyMoneyTransaction> fetchTransactions (const MyMoneyTransactionFilter& filter) const;
  bool isReferencedByTransaction(const TQString& id) const;

  void readPayees(const TQString&);
  void readPayees(const TQValueList<TQString> payeeList = TQValueList<TQString>());
  void readTransactions(const MyMoneyTransactionFilter& filter);
  void setProgressCallback(void(*callback)(int, int, const TQString&));

  virtual void readFile(TQIODevice* s, IMyMoneySerialize* storage) { Q_UNUSED(s); Q_UNUSED(storage) };
  virtual void writeFile(TQIODevice* s, IMyMoneySerialize* storage){ Q_UNUSED(s); Q_UNUSED(storage) };

  void startCommitUnit (const TQString& callingFunction);
  bool endCommitUnit (const TQString& callingFunction);
  void cancelCommitUnit (const TQString& callingFunction);

  long unsigned getRecCount(const TQString& table) const;
  long unsigned getNextBudgetId() const;
  long unsigned getNextAccountId() const;
  long unsigned getNextInstitutionId() const;
  long unsigned getNextPayeeId() const;
  long unsigned getNextReportId() const;
  long unsigned getNextScheduleId() const;
  long unsigned getNextSecurityId() const;
  long unsigned getNextTransactionId() const;

  long unsigned incrementBudgetId();
  long unsigned incrementAccountId();
  long unsigned incrementInstitutionId();
  long unsigned incrementPayeeId();
  long unsigned incrementReportId();
  long unsigned incrementScheduleId();
  long unsigned incrementSecurityId();
  long unsigned incrementTransactionId();

  void loadAccountId(const unsigned long& id);
  void loadTransactionId(const unsigned long& id);
  void loadPayeeId(const unsigned long& id);
  void loadInstitutionId(const unsigned long& id);
  void loadScheduleId(const unsigned long& id);
  void loadSecurityId(const unsigned long& id);
  void loadReportId(const unsigned long& id);
  void loadBudgetId(const unsigned long& id);

private:
  // a function to build a comprehensive error message
  TQString& buildError (const TQSqlQuery& q, const TQString& function, const TQString& message) const;
  // write routines
  void writeUserInformation(void);
  void writeInstitutions(void);
  void writePayees(void);
  void writeAccounts(void);
  void writeTransactions(void);
  void writeSchedules(void);
  void writeSecurities(void);
  void writePrices(void);
  void writeCurrencies(void);
  void writeFileInfo(void);
  void writeReports(void);
  void writeBudgets(void);

  void writeInstitution(const MyMoneyInstitution& i, MyMoneySqlQuery& q);
  void writePayee(const MyMoneyPayee& p, MyMoneySqlQuery& q, bool isUserInfo = false);
  void writeAccount (const MyMoneyAccount& a, MyMoneySqlQuery& q);
  void writeTransaction(const TQString& txId, const MyMoneyTransaction& tx, MyMoneySqlQuery& q, const TQString& type);
  void writeSplits(const TQString& txId, const TQString& type, const TQValueList<MyMoneySplit>& splitList);
  void writeSplit(const TQString& txId, const MyMoneySplit& split, const TQString& type, const int splitId, MyMoneySqlQuery& q);
  void writeSchedule(const MyMoneySchedule& sch, MyMoneySqlQuery& q, bool insert);
  void writeSecurity(const MyMoneySecurity& security, MyMoneySqlQuery& q);
  void writePricePair ( const MyMoneyPriceEntries& p);
  void writePrice (const MyMoneyPrice& p);
  void writeCurrency(const MyMoneySecurity& currency, MyMoneySqlQuery& q);
  void writeReport (const MyMoneyReport& rep, MyMoneySqlQuery& q);
  void writeBudget (const MyMoneyBudget& bud, MyMoneySqlQuery& q);
  void writeKeyValuePairs(const TQString& kvpType, const TQString& kvpId, const TQMap<TQString, TQString>& pairs);
  void writeKeyValuePair(const TQString& kvpType, const TQString& kvpId,
                         const TQString& kvpKey, const TQString& kvpData);
  // read routines
  void readFileInfo(void);
  void readLogonData(void);
  void readUserInformation(void);
  void readInstitutions(void);
  void readAccounts(void);
  void readTransaction(const TQString id);
  void readTransactions(const TQString& tidList = TQString(), const TQString& dateClause = TQString());
  void readTransaction(MyMoneyTransaction &tx, const TQString& tid);
  void readSplit (MyMoneySplit& s, const MyMoneySqlQuery& q, const MyMoneyDbTable& t) const;
  const MyMoneyKeyValueContainer readKeyValuePairs (const TQString& kvpType, const TQString& kvpId) const;
  const TQMap<TQString, MyMoneyKeyValueContainer> readKeyValuePairs (const TQString& kvpType, const TQStringList& kvpIdList) const;
  void readSchedules(void);
  void readSecurities(void);
  void readPrices(void);
  void readCurrencies(void);
  void readReports(void);
  void readBudgets(void);

  void deleteTransaction(const TQString& id);
  void deleteSchedule(const TQString& id);
  void deleteKeyValuePairs(const TQString& kvpType, const TQString& kvpId);
  long unsigned calcHighId (const long unsigned&, const TQString&);

  void setVersion (const TQString& version);

  void signalProgress(int current, int total, const TQString& = "") const;
  void (*m_progressCallback)(int, int, const TQString&);

  //void startCommitUnit (const TQString& callingFunction);
  //void endCommitUnit (const TQString& callingFunction);
  //void cancelCommitUnit (const TQString& callingFunction);
  int splitState(const MyMoneyTransactionFilter::stateOptionE& state) const;

  inline const TQDate getDate (const TQString& date) const {
    return (date.isNull() ? TQDate() : TQDate::fromString(date, Qt::ISODate));
  }

  inline const TQDateTime getDateTime (const TQString& date) const {
    return (date.isNull() ? TQDateTime() : TQDateTime::fromString(date, Qt::ISODate));
  }

  // open routines
  /**
   * MyMoneyStorageSql create database
   *
   * @param url pseudo-URL of database to be opened
   *
   * @return true - creation successful
   * @return false - could not create
   *
   */
  int createDatabase(const KURL& url);
  int upgradeDb();
  int upgradeToV1();
  int upgradeToV2();
  int upgradeToV3();
  int upgradeToV4();
  int upgradeToV5();
  int upgradeToV6();
  bool sqliteAlterTable(const MyMoneyDbTable& t);
  bool addColumn(const MyMoneyDbTable& t,
                 const MyMoneyDbColumn& c,
                 const TQString& after = TQString());
  bool addColumn(const TQString& table,
                 const TQString& column,
                 const TQString& after = TQString());
  bool dropColumn(const MyMoneyDbTable& t,
                  const TQString& c);
  bool dropColumn(const TQString& table,
                  const TQString& column);

//  long long unsigned getRecCount(const TQString& table);
  int createTables();
  void createTable(const MyMoneyDbTable& t);
  void clean ();
  int isEmpty();
  // data
  MyMoneyDbDrivers m_drivers;
  databaseTypeE m_dbType;

  MyMoneyDbDef m_db;
  unsigned int m_dbVersion;
  IMyMoneySerialize *m_storage;
  IMyMoneyStorage *m_storagePtr;
  // input options
  bool m_loadAll; // preload all data
  bool m_override; // override open if already in use
  // error message
  TQString m_error;
  // record counts
  long unsigned m_institutions;
  long unsigned m_accounts;
  long unsigned m_payees;
  long unsigned m_transactions;
  long unsigned m_splits;
  long unsigned m_securities;
  long unsigned m_prices;
  long unsigned m_currencies;
  long unsigned m_schedules;
  long unsigned m_reports;
  long unsigned m_kvps;
  long unsigned m_budgets;
  // next id to use (for future archive)
  long unsigned m_hiIdInstitutions;
  long unsigned m_hiIdPayees;
  long unsigned m_hiIdAccounts;
  long unsigned m_hiIdTransactions;
  long unsigned m_hiIdSchedules;
  long unsigned m_hiIdSecurities;
  long unsigned m_hiIdReports;
  long unsigned m_hiIdBudgets;
  // encrypt option - usage TBD
  TQString m_encryptData;

  /**
    * This variable is used to suppress status messages except during
   * initial data load and final write

  */
  bool m_displayStatus;
  /**
   * On occasions, e.g. after a complex transaction search, or for populating a
   * payee popup list, it becomes necessary to load all data into memory. The
   * following flags will be set after such a load, to indicate that further
   * retrievals are not needed.
   */
//  bool m_transactionListRead;
//  bool m_payeeListRead;
  /**
   * This member variable holds a list of those accounts for which all
   * transactions are in memory, thus saving reading them again
   */
//  TQValueList<TQString> m_accountsLoaded;
  /**
    * This member variable is used when loading transactions to list all
    * referenced payees, which can then be read into memory (if not already there)
    */
//  TQValueList<TQString> m_payeeList;

  void alert(TQString s) const {tqDebug("%s", s.ascii());}; // FIXME: remove...
  /** The following keeps track of commitment units (known as transactions in SQL
    * though it would be confusing to use that term within KMM). It is implemented
    * as a stack for debug purposes. Long term, probably a count would suffice
    */
  TQValueStack<TQString> m_commitUnitStack;
  /**
    * This member variable is used to preload transactions for preferred accounts
    */
  MyMoneyTransactionFilter m_preferred;
  /**
    * This member variable is used because reading prices from a file uses the 'add...' function rather than a
    * 'load...' function which other objects use. Having this variable allows us to avoid needing to check the
    * database to see if this really is a new or modified price
    */
  bool m_readingPrices;
  /**
    * This member variable holds a map of transaction counts per account, indexed by
    * the account id. It is used
    * to avoid having to scan all transactions whenever a count is needed. It should
    * probably be moved into the MyMoneyAccount object; maybe we will do that once
    * the database code has been properly checked out
    */
  TQMap<TQString, unsigned long> m_transactionCountMap;
  /**
    * These member variables hold the user name and date/time of logon
    */
  TQString m_logonUser;
  TQDateTime m_logonAt;
  TQDateTime m_txPostDate; // FIXME: remove when Tom puts date into split object

  //Disable copying
  MyMoneyStorageSql (const MyMoneyStorageSql& rhs);
  MyMoneyStorageSql& operator= (const MyMoneyStorageSql& rhs);
  //
  bool m_newDatabase;
};
#endif // MYMONEYSTORAGESQL_H
