// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Boolberry developers
// Copyright (c) 2017-2025 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// You may obtain a copy of the licence at:
//
//     https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
//
// The EUPL is a copyleft licence that is compatible with the MIT/X11
// licence used by the original projects; the MIT terms are therefore
// considered “grandfathered” under the EUPL for this code.
//
// SPDX‑License‑Identifier: EUPL-1.2
//

#pragma once

#include  <thread>

#include "include_base_utils.h"

#include "db_backend_base.h"
#include "db/liblmdb/lmdb.h"


namespace tools
{
  namespace db
  {
    class lmdb_db_backend : public i_db_backend
    {

      struct tx_entry
      {
        MDB_txn* ptx;
        bool read_only; // needed for thread-top transaction, for figure out if we need to unlock exclusive access
        size_t count;   //count of read-only nested emulated transactions
      };
      typedef std::list<tx_entry> transactions_list;


      std::string m_path;
      MDB_env *m_penv;

      boost::recursive_mutex m_cs;
      boost::recursive_mutex m_write_exclusive_lock;
      std::map<std::thread::id, transactions_list> m_txs; // size_t -> count of nested read_only transactions
      bool pop_tx_entry(tx_entry& txe);

    public:
      lmdb_db_backend();
      ~lmdb_db_backend();

      //----------------- i_db_backend -----------------------------------------------------
      bool close() override;
      bool begin_transaction(bool read_only = false) override;
      bool commit_transaction() override;
      void abort_transaction() override;
      bool open(const std::string& path, uint64_t cache_sz = CACHE_SIZE) override;
      bool open_container(const std::string& name, container_handle& h) override;
      bool close_container(container_handle& h) override;
      bool erase(container_handle h, const char* k, size_t s) override;
      bool get(container_handle h, const char* k, size_t s, std::string& res_buff) override;
      bool clear(container_handle h) override;
      uint64_t size(container_handle h) override;
      bool set(container_handle h, const char* k, size_t s, const char* v, size_t vs) override;
      bool enumerate(container_handle h, i_db_callback* pcb) override;
      bool get_stat_info(tools::db::stat_info& si) override;
      const char* name() override;
      //-------------------------------------------------------------------------------------
      bool have_tx();
      MDB_txn* get_current_tx();

      static bool convert_db_4kb_page_to_16kb_page(const std::string& source_path, const std::string& destination_path);

    };
  }
}
