/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                               DEMO PROGRAMS SET
                          odbc_test3.cpp  -  description

    This test creates several threads with the independent database 
	connection per thread.

                             -------------------
    begin                : October 15, 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 <sptk3/CODBCDatabase.h>
#include <sptk3/CQuery.h>
#include <sptk3/CThread.h>

using namespace std;
using namespace sptk;

/// Opens a database connection and inserts
/// 100 of records to the database. After that
/// verifies that all the records are inserted
/// properly.
class CInsertThread : public CThread {
   static int threadIndex;

   CODBCDatabase    m_db;
   CQuery           m_query;
   int              m_threadIndex;

public:
   CInsertThread(std::string connectString);
   virtual void threadFunction();
};

int CInsertThread::threadIndex = 0;

CInsertThread::CInsertThread(std::string connectString)
: CThread("Thread "+int2string(threadIndex)), m_db(connectString), m_query(&m_db,""), m_threadIndex(threadIndex) {
   threadIndex++;
}

void CInsertThread::threadFunction() {
   try {
      // Opening the database
      m_db.open();
      
      string tableName = "test_odbc" + int2string(m_threadIndex);
      string isTemp = "TEMP ";
      if (m_db.driverDescription() == "SQL Server") {
         tableName = "##test_odbc" + int2string(m_threadIndex);
         isTemp = "";
      }
      
      unsigned maxRows = 1000;
      
      // Creating the temp table
      m_query.sql("CREATE " + isTemp +" TABLE " + tableName + " (id int,name char(20))");
      m_query.exec();
      printf("Thread %i query 1 completed\n",m_threadIndex);
      m_query.sql("INSERT INTO " + tableName + " VALUES(:id,:name)");
      for (unsigned i = 1; i <= maxRows; i++) {
         int id = m_threadIndex * maxRows + i;
         char buffer[80];
         sprintf(buffer,"Row %i",id);
         m_query.param("id") = id;
         m_query.param("name") = buffer;
         m_query.exec();
      }
      printf("Thread %i query 2 completed\n",m_threadIndex);
      m_db.close();
   }
   catch (exception& e) {
      printf("Error in thread %i: %s\n",m_threadIndex,e.what());
   }
   catch (...) {
      printf("Unknown error in thread %i\n",m_threadIndex);
   }
}

int main() {
   unsigned maxThreads = 4;
   unsigned threadNumber;

   CODBCDatabase	db1("DSN=odbc_demo"),db2("DSN=odbc_demo");

   vector<CInsertThread *> threads;

   for (threadNumber = 0; threadNumber < maxThreads; threadNumber++) {
      CInsertThread *thread = new CInsertThread("DSN=odbc_demo");
	  threads.push_back(thread);
	  thread->run();
   }

#ifdef WIN32
   Sleep(1000);
#else
   sleep(1);
#endif

 
   for (threadNumber = 0; threadNumber < maxThreads; threadNumber++) {
      cout << "Waiting for thread " << threadNumber << endl;
      try {
         CInsertThread *thread = threads[threadNumber];
         delete thread;
      }
      catch (exception& e) {
         printf("exception deleting thread %i: %s\n", threadNumber, e.what());
      }
      catch (...) {
         printf("exception deleting thread %i: %s\n", threadNumber, "Unknown exception");
      }
   }

/*
   // And this is really ugly
   for (threadNumber = 0; threadNumber < maxThreads; threadNumber++) {
      cout << "Waiting for thread " << threadNumber << endl;
      CInsertThread *thread = threads[threadNumber];
      while (thread->running()) {
#ifdef WIN32
        Sleep(1000);
#else
        sleep(1);
#endif
      }
      delete thread;
   }
*/
#ifdef WIN32
   Sleep(3000);
#else
   sleep(3);
#endif

   return 0;
}
