#include "persifs.h"
#include "testutils.h"
#include "testpersibplustree.h"
#include "superblob.h"
#include "persibplustree.h"

#include <amisc.h>
#include <async.h>
#include <arpc.h>
#include <stdlib.h>
#include <list.h>

const int TEST_COUNT = 15;
const int TEST_BRANCHT = 2;
const int TEST_CACHESIZE = 2;
const str TEST_FILENAME = "testpersibplustree.pbt";
const str TEST_ROOT_MAP_FILENAME = "testpersibplustree.pbr";

struct testEnt
{
  tailq_entry<testEnt> link;
  blockFingerprint k;
  blockAddress v;
  treeTimestamp ts;
};


void
testsDone()
{
  warn << "PersiBPlusTree test passes... hooray!\n";
  if (unlink(TEST_FILENAME.cstr()) != 0)
    perror("unlink");
  if (unlink(TEST_ROOT_MAP_FILENAME.cstr()) != 0)
    perror("unlink");

  exit(0);
}

void
testPersiBPlusTree(int count, ref<bpt> t)
{
  tailq<testEnt, &testEnt::link> q;
  for (int i = 0; i < count; i++)
  {
    blockFingerprint k = randomFingerprint();
    blockAddress v = randomAddress();

    warn << "inserting " << k << " = " << v << "(" << i << ")\n";

    testEnt *ent = New testEnt;
    ent->k = k;
    ent->v = v;
    ent->ts = t->insert(k, v);
    q.insert_tail(ent);
    t->commit();
  }

  t->printTree();
  
  testEnt *ent;
  for (ent = q.first; ent; ent = q.next(ent)) {
    warn << "inserting " << ent->k << " = " << 0 << "\n";
    t->insert(ent->k, 0);
  }
  t->commit();

  int i;
  
  for (i = 1; i < count+1; i++)
  {
    for (ent = q.first; ent; ent = q.next(ent)) {
      warn << "[" << i << "] checking " << ent->k;
      if (ent->ts > i) {
        warn << " exp. not found\n";
      } else {
        warn << " = " << ent->v << "\n";
      }

      ptr<blockAddress> r = t->syncSearch(ent->k, i);
      if (ent->ts > i) {
        if (r != NULL) {
          warn << "Expected null, got " << *r << "\n";
          fail("Incorrect result");
        }
      } else {
        if (r == NULL) {
          fail("Unexpected null");
        } else {
          if (*r != ent->v) {
            warn << "Expected " << ent->v << "; got " << *r << "\n";
            fail("Incorrect result");
          }
        }
      }
    }
  }
  for (ent = q.first; ent; ent = q.next(ent)) {
    ptr<blockAddress> r = t->syncSearch(ent->k, i);
    if (*r != 0) {
      warn << "Expected 0, got " << *r << "\n";
      fail("Incorrect result");
    }
  }
  warn << "Memory transfers: " << t->blockTransfers();
  testsDone();    
}

int
main(int argc, const char **argv)
{
  srandom(0x6824);

  bpt::create(TEST_FILENAME, TEST_ROOT_MAP_FILENAME, TEST_BRANCHT,
              TEST_CACHESIZE,
              wrap(&testPersiBPlusTree, TEST_COUNT), wrap(&failCBE));
  
  amain();
}
