// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include <iostream>
#include <fstream>
#include <thread>
#include <queue>
#include "db/prefetch_iter.h"

#include "db/db_impl.h"
#include "db/dbformat.h"
#include "db/filename.h"
#include "leveldb/env.h"
#include "leveldb/iterator.h"
#include "port/port.h"
#include "util/logging.h"
#include "util/mutexlock.h"
#include "util/random.h"
#include "port/port.h"

namespace leveldb {

namespace {



// Memtables and sstables that make the DB representation contain
// (userkey,seq,type) => uservalue entries.  DBPreFetchIter
// combines multiple entries for the same userkey found in the DB
// representation into a single entry while accounting for sequence
// numbers, deletion markers, overwrites, etc.
class DBPreFetchIter : public Iterator {
 public:
  // Which direction is the iterator currently moving?
  // (1) When moving forward, the internal iterator is positioned at
  //     the exact entry that yields this->key(), this->value()
  // (2) When moving backwards, the internal iterator is positioned
  //     just before all entries whose user key == this->key().
  enum IterPos {Left,Mid,Right};

  DBPreFetchIter(DBImpl* db, Iterator* iter, Iterator* prefetch_iter,int prefetch_num)
      : 
        db_(db),iter_(iter),prefetch_iter_(prefetch_iter),prefetch_num_(prefetch_num) {}

  DBPreFetchIter(const DBPreFetchIter&) = delete;
  DBPreFetchIter& operator=(const DBPreFetchIter&) = delete;

  ~DBPreFetchIter() override { 
    // if(prefetch_thread.joinable()){
    //   stop_flag.store(true);
    //   prefetch_thread.join();
    // }
    delete prefetch_iter_;
    //std::cout<<"fetch:"<<fetched_<<" unfetch:"<<unfetched_<<"\n";
    delete iter_; 
  }
  bool Valid() const override { return iter_->Valid(); }
  Slice key() const override {
    return iter_->key();
  }
  Slice value() const override {
    // if(cur_pos>=0&&cur_pos<=1000000&&prefetched_array[cur_pos].load()){
    //   fetched_++;
    //   return prefetch_array[cur_pos];
    // }
    // else{
    //   unfetched_++;
      buf_for_value=std::move(GetAndParseTrueValue(iter_->value()));
      return Slice(buf_for_value.data(),buf_for_value.size());
    //}
  }
  Status status() const override {
    return iter_->status();
  }

  void Next() override;
  void Prev() override;
  void Seek(const Slice& target) override;
  void SeekToFirst() override;
  void SeekToLast() override;

 private:
   std::string GetAndParseTrueValue(Slice tmp_value)const{
    if(tmp_value.size()==0){
      return "";
    }
    if(tmp_value.data()[0]==(char)(0x00)){
      tmp_value.remove_prefix(1);
      return std::string(tmp_value.data(),tmp_value.size());
    }
    tmp_value.remove_prefix(1);
    uint64_t file_id,valuelog_offset;
    bool res=GetVarint64(&tmp_value,&file_id);
    if(!res)assert(0);
    res=GetVarint64(&tmp_value,&valuelog_offset);
    if(!res)assert(0);
    std::string str;
    Status s=db_->ReadValueLog(file_id,valuelog_offset, &str);
    return std::move(str);
  }


  // void PreFetchThreadForward(){
  //   std::thread prefetch_threads[prefetch_num_];
  //   std::queue<std::pair<std::string,int>> q;
  //   port::Mutex* lock=new port::Mutex();
  //   port::CondVar* cv=new port::CondVar(lock);
  //   bool local_stop_flag=false;
  //   int remaining_task_cnt=0;
  //   bool main_finish=false;
  //   for(int i=0;i<prefetch_num_;i++){
  //     prefetch_threads[i]=std::thread([this,&q,&lock,&cv,&local_stop_flag,&remaining_task_cnt,&main_finish]() 
  //       {
  //         int pos;
  //         while(1){
  //           lock->Lock();
  //           while(q.empty()&&!local_stop_flag&&!(remaining_task_cnt==0&&main_finish)){
  //             cv->Wait();
  //           }
  //           if(local_stop_flag||(remaining_task_cnt==0&&main_finish)){
  //             cv->SignalAll();
  //             lock->Unlock();
  //             break;
  //           }
  //           std::string s=q.front().first;
  //           pos=q.front().second;
  //           q.pop();
  //           remaining_task_cnt--;
  //           lock->Unlock();
  //           prefetch_array[pos]=std::move(GetAndParseTrueValue(s));
  //           prefetched_array[pos].store(true);
  //         }
  //       }
  //     );
  //   }
  //   Slice val;
  //   int pos=0;
  //   for(int i=0;i<100&&prefetch_iter_->Valid();i++){
  //     prefetch_iter_->Next();
  //     pos++;
  //   }
  //   for(;prefetch_iter_->Valid()&&!stop_flag.load()&&pos<1000000;prefetch_iter_->Next()){
  //     val=prefetch_iter_->value();
  //     lock->Lock();
  //     q.push({std::string(val.data(),val.size()),pos});
  //     cv->Signal();
  //     remaining_task_cnt++;
  //     lock->Unlock();
  //     pos++;
  //   }

  //   lock->Lock();
  //   main_finish=true;
  //   while(remaining_task_cnt){
  //     cv->Wait();
  //   }
  //   lock->Unlock();
  //   cv->SignalAll();

  //   for (auto& thread : prefetch_threads) {
  //       if (thread.joinable()) {
  //           thread.join();
  //       }
  //   }
  // }

  //  void PreFetchThreadBackward(){
  //   std::thread prefetch_threads[prefetch_num_];
  //   std::queue<std::pair<std::string,int>> q;
  //   port::Mutex* lock=new port::Mutex();
  //   port::CondVar* cv=new port::CondVar(lock);
  //   bool local_stop_flag=false;
  //   int remaining_task_cnt=0;
  //   bool main_finish=false;
  //   for(int i=0;i<prefetch_num_;i++){
  //     prefetch_threads[i]=std::thread([this,&q,&lock,&cv,&local_stop_flag,&remaining_task_cnt,&main_finish]() 
  //       {
  //         int pos;
  //         while(1){
  //           lock->Lock();
  //           while(q.empty()&&!local_stop_flag&&!(remaining_task_cnt==0&&main_finish)){
  //             cv->Wait();
  //           }
  //           if(local_stop_flag||(remaining_task_cnt==0&&main_finish)){
  //             cv->SignalAll();
  //             lock->Unlock();
  //             break;
  //           }
  //           std::string s=q.front().first;
  //           pos=q.front().second;
  //           q.pop();
  //           remaining_task_cnt--;
  //           lock->Unlock();
  //           prefetch_array[pos]=std::move(GetAndParseTrueValue(s));
  //           prefetched_array[pos].store(true);
  //         }
  //       }
  //     );
  //   }
  //   Slice val;
  //   int pos=1000000;
  //   for(;prefetch_iter_->Valid()&&!stop_flag.load()&&pos>=0;prefetch_iter_->Prev()){
  //     val=prefetch_iter_->value();
  //     lock->Lock();
  //     q.push({std::string(val.data(),val.size()),pos});
  //     cv->Signal();
  //     remaining_task_cnt++;
  //     lock->Unlock();
  //     pos--;
  //   }

  //   lock->Lock();
  //   main_finish=true;
  //   while(remaining_task_cnt){
  //     cv->Wait();
  //   }
  //   lock->Unlock();
  //   cv->SignalAll();

  //   for (auto& thread : prefetch_threads) {
  //       if (thread.joinable()) {
  //           thread.join();
  //       }
  //   }
  // }

  
  DBImpl* db_;
  Iterator* const iter_;
  Iterator* const prefetch_iter_;
  int prefetch_num_;
  // std::atomic<bool> stop_flag;
  // std::string prefetch_array[1000005];
  // std::atomic<bool> prefetched_array[1000005];
  std::thread prefetch_thread;
  mutable std::string buf_for_value;
  int cur_pos=0;
  mutable int fetched_=0;
  mutable int unfetched_=0;
};
void DBPreFetchIter::Next() {
  iter_->Next();
  //cur_pos++;
}
void DBPreFetchIter::Prev() {
  iter_->Prev();
  //cur_pos--;
}

void DBPreFetchIter::Seek(const Slice& target) {
  iter_->Seek(target);
  
  // if(prefetch_thread.joinable()){
  //   stop_flag.store(true);
  //   prefetch_thread.join();
  //   stop_flag=false;
  // }
  // for(int i=0;i<=1000000;i++)prefetched_array[i]=false;
  // cur_pos=0;
  // prefetch_iter_->Seek(target);
  // prefetch_thread=std::thread([this]() {
  //     PreFetchThreadForward();
  // });
}

void DBPreFetchIter::SeekToFirst() {
  iter_->SeekToFirst();
  
  // if(prefetch_thread.joinable()){
  //   stop_flag.store(true);
  //   prefetch_thread.join();
  //   stop_flag=false;
  // }
  // for(int i=0;i<=1000000;i++)prefetched_array[i]=false;
  // cur_pos=0;
  // prefetch_iter_->SeekToFirst();
  // prefetch_thread=std::thread([this]() {
  //     PreFetchThreadForward();
  // });
  }
void DBPreFetchIter::SeekToLast() {
  iter_->SeekToLast();
  
  // if(prefetch_thread.joinable()){
  //   stop_flag.store(true);
  //   prefetch_thread.join();
  //   stop_flag=false;
  // }
  // for(int i=0;i<=1000000;i++)prefetched_array[i]=false;
  // cur_pos=1000000;
  
  // prefetch_thread=std::thread([this]() {
  //     prefetch_iter_->SeekToLast();
  //     PreFetchThreadBackward();
  // });
}

}  // anonymous namespace
Iterator* NewPreFetchIterator(DBImpl* db,Iterator* db_iter,Iterator* prefetch_iter,int prefetch_num) {
  return new DBPreFetchIter(db,db_iter,prefetch_iter,prefetch_num);
}
}  // namespace leveldb
