#include "WiscKeyTest_1.h"
#include <fstream>
#include <algorithm> 
#include <vector>      
#include <ctime>       
#include <cstdlib>    


typedef struct WiscKey { // 集成了leveldb数据库和一个logfile链表
  string dir;
  DB * leveldb;
  FILE * logfile;
} WK;

static bool wisckey_get(WK * wk, string &key, string &value)
{	
	cout << "\n\t\tGet Function\n\n";
	cout << "Key Received: " << key << endl;
	cout << "Value Received: " << value << endl;

	string offsetinfo;
        const bool found = leveldb_get(wk->leveldb, key, offsetinfo);
        if (found) {
       		cout << "Offset and Length: " << offsetinfo << endl;
        }
        else {
       	        cout << "Record:Not Found" << endl;
		return false;
        }
	std::string value_offset;
	std::string value_length;
	std::string s = offsetinfo;
	std::string delimiter = "&&";
	size_t pos = 0;
	std::string token;
	while ((pos = s.find(delimiter)) != std::string::npos) {
    		token = s.substr(0, pos);
		value_offset = token;
    		s.erase(0, pos + delimiter.length());
	}
	value_length = s;

	cout << "Value Offset: " << value_offset << endl;
	cout << "Value Length: " << value_length << endl;

  	std::string::size_type sz;
  	long offset = std::stol (value_offset,&sz);
	long length = std::stol (value_length,&sz);

	//cout << offset << length << endl;
	std::string value_record;
	//cout << ftell(wk->logread) << endl;
	fseek(wk->logfile,offset,SEEK_SET);
	//cout << ftell(wk->logfile) << endl;
	//rewind(wk->logfile);
	//cout << ftell(wk->logfile) << endl;	
	fread(&value_record,length,1,wk->logfile);
	//rewind(wk->logfile);
	cout << "LogFile Value: " << value_record << endl;
	return true;
}	

static void wisckey_set(WK * wk, string &key, string &value)
{
	long offset = ftell (wk->logfile);
	long size = sizeof(value);
	std::string vlog_offset = std::to_string(offset);
	std::string vlog_size = std::to_string(size);
	std::stringstream vlog_value;
	vlog_value << vlog_offset << "&&" << vlog_size;
	std::string s = vlog_value.str();	
	fwrite (&value, sizeof(value),1,wk->logfile);
	leveldb_set(wk->leveldb,key,s);
}

static void wisckey_del(WK * wk, string &key)
{
 	cout << "Key: " << key << endl; 
	leveldb_del(wk->leveldb,key);
	
}

static WK * open_wisckey(const string& dirname)
{
	WK * wk = new WK;
	wk->leveldb = open_leveldb(dirname);
  	wk->dir = dirname;
	wk->logfile = fopen("logfile","wb+");
  	return wk;
}

static void close_wisckey(WK * wk)
{
	fclose(wk->logfile);
  	delete wk->leveldb;
  	delete wk;
}


// For testing wisckey functionality 
static void testing_function(WK * wk, string &key, string &value) 
{
/* Setting Value and Testing it */
        
	cout << "\n\n\t\tInput Received\n" << endl;
	cout << "Key: " << key << endl;
        cout << "Value: " << value << endl;
	wisckey_set(wk,key,value);
	const bool found = wisckey_get(wk,key,value);
	if (found) {
		cout << "Record Matched" << endl;
	}

/* Deleting Value */
	cout << "\n\n\t\tDelete Operation\n" << endl;
	wisckey_del(wk,key);
	cout << "Delete Successful" << endl;
	
/* Read after Delete */
	cout << "\n\n\t\tInput Received\n" << endl;
        string testkey= "1001224314";
        string testvalue = "Abhishek Sharma";
        cout << "Key: " << testkey << endl;
        cout << "Value: " << testvalue << endl;
	const bool testfound = wisckey_get(wk,testkey,testvalue);
        if (testfound) {
               cout << "Record Matched" << endl;
        }
}	

int main(int argc, char ** argv)
{
	if (argc < 2) {
    		cout << "Usage: " << argv[0] << " <value-size>" << endl;
    		exit(0);
  	}
  	const size_t value_size = std::stoull(argv[1], NULL, 10);
  	if (value_size < 1 || value_size > 100000) {
    		cout << "  <value-size> must be positive and less then 100000" << endl;
   	 	exit(0);
  	}

  	WK * wk = open_wisckey("wisckey_test_dir");  // 打开数据库
  	if (wk == NULL) {
    		cerr << "Open WiscKey failed!" << endl;
    		exit(1);
  	}

	char * vbuf = new char[value_size];
  	for (size_t i = 0; i < value_size; i++) {
    		vbuf[i] = rand();
  	}
  	string value = string(vbuf, value_size);
 	size_t nfill = 1000000000 / (value_size + 8);  // 生成 nfill = 1,000,000,000 / (value_size + 8) 条随机键值对
  	clock_t t0 = clock();
  	size_t p1 = nfill / 40;  // 将插入任务分成四十份
  	for (size_t j = 0; j < nfill; j++) {
    		string key = std::to_string(((size_t)rand())*((size_t)rand()));
    		wisckey_set(wk, key, value);	
   		if (j >= p1) {
      			clock_t dt = clock() - t0;
      			cout << "progress: " << j+1 << "/" << nfill << " time elapsed: " << dt * 1.0e-6 << endl << std::flush;  // 打印进度和已经消耗的时间
      			p1 += (nfill / 40);
    		}    
  	}

  	clock_t dt = clock() - t0;
  	cout << "time elapsed: " << dt * 1.0e-6 << " seconds" << endl;
        close_wisckey(wk);
        destroy_leveldb("wisckey_test_dir");       
        remove("logfile");
        exit(0);
}