
extern "C" {
#include "postgres.h"
#include "fmgr.h"
}
#ifdef qsort
#undef qsort
#endif

#include "bingo_pg_build_engine.h"
#include "bingo_core_c.h"

#include "base_cpp/tlscont.h"
#include "base_cpp/array.h"

#include "bingo_pg_index.h"

using namespace indigo;

BingoPgBuildEngine::BingoPgBuildEngine():
_bufferIndexPtr(0) {
   _bingoSession = bingoAllocateSessionID();
}

BingoPgBuildEngine::~BingoPgBuildEngine(){
   bingoReleaseSessionID(_bingoSession);
}

void BingoPgBuildEngine::_setBingoContext() {
   bingoSetSessionID(_bingoSession);
   bingoSetContext(0);
}

void BingoPgBuildEngine::loadDictionary(BingoPgIndex& bingo_index) {
   _setBingoContext();

   QS_DEF(Array<char>, dict);
   bingo_index.readDictionary(dict);
   bingoSetConfigBin("cmf_dict", dict.ptr(), dict.sizeInBytes());
}

const char* BingoPgBuildEngine::getDictionary(int& size) {
   _setBingoContext();

   const char* dict_buf;

   bingoGetConfigBin("cmf-dict", &dict_buf, &size);

   return dict_buf;
}

int BingoPgBuildEngine::getNthreads() {
   // TO DISABLE THREADS UNCOMMENT THIS
//   return 1;
   int result;
   _setBingoContext();

   bingoGetConfigInt("nthreads", &result);

   return result;
}


int BingoPgBuildEngine::_getNextRecordCb (void *context) {
   BingoPgBuildEngine* engine = (BingoPgBuildEngine*)context;

   int& cache_idx = engine->_currentCache;
   ObjArray<StructCache>& struct_caches = *(engine->_structCaches);
   if(cache_idx >= struct_caches.size())
      return 0;

   StructCache& struct_cache = struct_caches[cache_idx];

   int struct_size;
   const char* struct_ptr = struct_cache.text->getText(struct_size);

   /*
    * Set target data. There is no need to handle errors
    */
   bingoSetIndexRecordData(cache_idx, struct_ptr, struct_size);
   ++cache_idx;
   return 1;
}

void BingoPgBuildEngine::_processErrorCb (int id, void *context) {
   BingoPgBuildEngine* engine = (BingoPgBuildEngine*)context;
   ObjArray<StructCache>& struct_caches = *(engine->_structCaches);
   ItemPointer item_ptr = &(struct_caches[id].ptr);
   int block_number = ItemPointerGetBlockNumber(item_ptr);
   int offset_number = ItemPointerGetOffsetNumber(item_ptr);
   elog(WARNING, "build engine: error while processing record with ctid='(%d,%d)'::tid: %s", block_number, offset_number, bingoGetWarning());
}