#include <string>
#include "buffer.h"
#ifndef _main_h_
#define _main_h_
struct kv_pairs {
int** kv; // Array of [key, value] pairs
int kv_size; // Size of kv
};
class TreeNode {
public:
int key;
int value;
int height; // height in the tree, for balancing
TreeNode* left;
TreeNode* right;
// constructor to initialize a TreeNode
TreeNode(int key, int val);
};
class AVLTree {
public:
TreeNode* root;
int max_size;
int cur_size;
std::string db_name;
AVLTree(int max_size, std::string db_name);
// public methods
int put(int key, int value);
int get(int key);
struct kv_pairs* scan(int key1, int key2);
void deleteTree(TreeNode* node);
void freeKVpairs(kv_pairs* p);
private:
// get from tree
int get_node(TreeNode* node, int k);
// helpers for AVLTree::scan
void scan_node(TreeNode* node, int key1, int key2, struct kv_pairs *scanned_kv, bool fullscan);
// insert into the tree recursively
TreeNode* insert(TreeNode* node, int key, int val);
int getHeight(TreeNode* node);
int getBalanceFactor(TreeNode* node);
TreeNode* rotateRight(TreeNode* node);
TreeNode* rotateLeft(TreeNode* node);
// int compact_sst(int sst_num1, int sst_num2, int has_temp, int temp_size);
int get_SST_size(int sst_num);
int get_leaf_page(int sst_size);
void update_size(int sst_num, int sst_size);
int count_num_repeats(int size1, int size2, int fd1, int fd2, int in1, int in2);
friend class DB;
};
class DB {
public:
std::string name;
AVLTree* mem_table;
BufferPool* buffer;
int sst_counter;
int max_size;
int search_alg; // 0 for binary search, 1 for btree search
int bloomfilter_num_bits; // bits per entry to be given to bloom filter
int buffer_args[3]; // buffer args tracks information to avoid sequential flooding of the buffer.
// buffer_args[0] holds the most recent method called. It has value 1 for get(), and 2 for scan().
// buffer_args[1] holds the key for get(), and key1 for scan().
// buffer_args[2] holds key2 for scan().
DB(std::string name);
int Close();
int put(int key, int value);
int get(int key);
int update(int key, int value);
int remove(int key);
struct kv_pairs* scan(int key1, int key2);
void freeKVpairs(kv_pairs* p);
void set_max_dir_size(int size);
int transform_to_sst();
void write_bloom_filters(const std::vector<bool>& data, int lvl);
bool check_bloom_filters(int sst_num, int key);
int bloom_filter_id(int num1, int num2);
private:
// Helper for put, update, remove
int insert(int key, int value);
int get_SST_size(int sst_num);
int get_internal_node_offset(int sst_num, int index);
int get_bloom_size(int lvl);
std::vector<uint32_t> bloom_hash(int lvl, int key);
std::vector<bool> create_bloom_filter(int lvl, kv_pairs* kv);
// Helpers for scan
void scan_SST_Binary(int SST_num, int key1, int key2, struct kv_pairs *scanned_kv, bool args);
void scan_SST_BTree(int sst_num, int key1, int key2, struct kv_pairs *scanned_kv, bool args);
void merge_kv_pairs(struct kv_pairs *kv_1, struct kv_pairs *kv_2, struct kv_pairs *merged_kv);
void remove_scanned_tombstones(struct kv_pairs *scanned_kv);
// Helper for get
int get_from_SST_Binary(int sst_num, int key, bool args);
int get_from_SST_BTree(int sst_num, int key, bool args);
// Helper for SST Reading
int read_SST(std::string sst_name, int sst_num, int offset, bool args);
int get_offset(int sst_num, int index, int num_leaf_pages, int sst_size, int leaf_page);
int compact_sst(int sst_num1, int sst_num2, int has_temp, int temp_size);
// int get_leaf_page(int sst_size);
// void update_size(int sst_num, int sst_size);
};
DB* Open(std::string name, int max_size, int initial_directory_size, int max_directory_size, int search_alg, int bloomfilter_num_bits);
#endif