/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                               DEMO PROGRAMS SET
                          sqlite3_test.cpp  -  description
                             -------------------
    begin                : Wed November 2, 2005
    copyright            : (C) 2005-2006 by Alexey S.Parshin
    email                : alexeyp@gmail.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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef __BORLANDC__
#include <vcl.h>
#pragma hdrstop
#endif

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

#include <sptk3/CSQLite3Database.h>
#include <sptk3/CDatabase.h>
#include <sptk3/CQuery.h>

using namespace std;
using namespace sptk;

int testTransactions(CDatabase&db,string tableName,bool rollback) {
   try {
      CQuery  step5Query(&db,"DELETE FROM "+tableName);
      CQuery  step6Query(&db,"SELECT count(*) FROM "+tableName);

      printf("\n        Begining the transaction ..");
      db.beginTransaction();
      printf("\n        Deleting everything from the temp table ..");
      step5Query.exec();

      step6Query.open();
      int counter = step6Query[0].asInteger();
      step6Query.close();
      printf("\n        The temp table now has %i records ..",counter);

      if (rollback) {
         printf("\n        Rolling back the transaction ..");
         db.rollbackTransaction();
      } else {
         printf("\n        Commiting the transaction ..");
         db.commitTransaction();
      }
      step6Query.open();
      counter = step6Query[0].asInteger();
      step6Query.close();
      printf("\n        The temp table now has %i records..",counter);
   }
   catch (exception& e) {
      printf("Error: %s\n",e.what());
   }

   return true;
}

int main() {

   // If you want to test the database abilities of the data controls
   // you have to setup the ODBC database connection.
   // Typical connect string is something like: "DSN=odbc_demo;UID=user;PWD=password".
   // If UID or PWD are omitted they are read from the datasource settings.
   CSQLite3Database     db("demo_db.sqlite3");

   /// Defining a log for the application. This is optional - you can omit this step
   CFileLog logFile("sqlite3_test.log");
   /// If the log is defined for the database, the database operations would be logged it.
   /// You can also print to the log your own messages.
   db.logFile(&logFile);

   logFile.writeString("sqlite3 started");

   try {
      printf("Openning the database.. ");
      db.open();
      printf("Ok.\nDriver description: %s\n",db.driverDescription().c_str());

      // Defining the queries
      CQuery step1Query(&db,"CREATE TABLE test(id INT,name CHAR(20),position CHAR(20))");
      CQuery step2Query(&db,"INSERT INTO test VALUES(:person_id,:person_name,:position_name)");
      CQuery step3Query(&db,"SELECT * FROM test WHERE id > :some_id");
      CQuery step4Query(&db,"DROP TABLE test");

      printf("Ok.\nStep 1: Creating the table.. ");
      step1Query.exec();

      printf("Ok.\nStep 2: Inserting data into the table.. ");

      // The following example shows how to use the paramaters,
      // addressing them by name
      CDateTime start,end;

      step2Query.param("person_id") = 1;
      step2Query.param("person_name") = "John Doe";
      step2Query.param("position_name") = "CIO";
      step2Query.exec();

      // Here is the example of using parameters as a stream. 
      // That method is several times faster than access by field name
      // Params should come in the exact order as they are defined in the query
      step2Query.params() << 2 << "Jane Doe" << "Vise President";
      step2Query.exec();

      // Here is the example of using parameters by index.
      // This is the even faster than stream
      step2Query.param(0) = 3;
      step2Query.param(1) = "Anonymous";
      step2Query.param(2) = "Manager";
      step2Query.exec();

      // And, finally - the fastest method: using CParam& variables.
      // If you have to call the same query multiple times with the different parameters,
      // that method gives you some extra gain.
      // So, lets define the parameter variables
      CParam& id_param = step2Query.param("person_id");
      CParam& name_param = step2Query.param("person_name");
      CParam& position_param = step2Query.param("position_name");
      // Now, we can use these variables
      id_param = 4;
      name_param = "Buffy";
      position_param = "Vampire slayer";
      step2Query.exec();
      // .. and use these variables again for the next insert
      id_param = 5;
      name_param = "Donald Duck";
      position_param.setNull(); // This is the way to set field to NULL
      step2Query.exec();

      printf("Ok.\nStep 3: Selecting the information the slow way ..\n");
      step3Query.param("some_id") = 1;
      step3Query.open();

      while ( ! step3Query.eof() ) {

         // getting data from the query by the field name
         int id = step3Query["id"].asInteger();

         // another method - getting data by the column number
         string name = step3Query[1].asString();
         string position = step3Query[2].asString();

         printf ("%-4i%-20s%-20s\n", id, name.c_str(), position.c_str() );

         step3Query.fetch();
      }
      step3Query.close();

      printf("Ok.\nStep 4: Selecting the information through the stream ..\n");
      step3Query.param("some_id") = 1;
      step3Query.open();

      while ( ! step3Query.eof() ) {

         int id;
         string name, position;

         step3Query.fields() >> id >> name >> position;

         printf ("%-4i%-20s%-20s\n", id, name.c_str(), position.c_str() );

         step3Query.fetch();
      }
      step3Query.close();

      printf("Ok.\nStep 5: Selecting the information the fast way ..\n");
      step3Query.param("some_id") = 1;
      step3Query.open();

      // First, find the field references by name or by number
      CField& idField = step3Query[0];
      CField& nameField = step3Query["name"];
      CField& positionField = step3Query["position"];

      while ( ! step3Query.eof() ) {

         int id = idField.asInteger();
         string name = nameField.asString();
         string position = positionField.asString();

         printf ("%-4i%-20s%-20s\n", id, name.c_str(), position.c_str() );

         step3Query.fetch();
      }
      step3Query.close();

      printf("Ok.\n***********************************************\nTesting the transactions.");

      testTransactions(db,"test",true);
      testTransactions(db,"test",false);

      step4Query.exec();

      printf("Ok.\nStep 6: Closing the database.. ");
      db.close();
      printf("Ok.\n");
   }
   catch (exception& e) {
      printf("\nError: %s\n",e.what());
      puts("\nSorry, you have to fix your database connection.");
      puts("Please, read the README.txt for more information.");
   }

   logFile.writeString("sqlite3 finished");
   logFile.flush();

   return 0;
}
