// ------------------------------- //
// -------- Start of File -------- //
// ------------------------------- //
// ----------------------------------------------------------- // 
// C++ Source Code File Name: testprog.cpp 
// Compiler Used: MSVC, BCC32, GCC, HPUX aCC, SOLARIS CC
// Produced By: glNET Software
// File Creation Date: 08/22/2000 
// Date Last Modified: 08/22/2001
// Copyright (c) 2001 glNET Software
// ----------------------------------------------------------- // 
// ------------- Program Description and Details ------------- // 
// ----------------------------------------------------------- // 
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
 
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  
USA

This test program is used to store multiple B-trees in a single
index file.
*/
// ----------------------------------------------------------- // 
#include <iostream.h>
#include "gxdstats.h"
#include "gxbtree.h"

const BtreeNodeOrder_t MyKeyClassOrder = 7;
const __WORD__ MyKeyNameSize = 64;

class MyKeyClass : public DatabaseKeyB
{
public:
  MyKeyClass();
  MyKeyClass(const char *name);
  void operator=(const char *name);
  ~MyKeyClass() { }

public: // Base class interface
  size_t KeySize() { return sizeof(key_name); }
  int operator==(const DatabaseKeyB& key) const;
  int operator>(const DatabaseKeyB& key) const;
  
public: // Persistent data member
  char key_name[MyKeyNameSize];
};

MyKeyClass::MyKeyClass() : DatabaseKeyB((char *)key_name)
{
  for(int i = 0; i < MyKeyNameSize; i++) key_name[i] = 0;
}

MyKeyClass::MyKeyClass(const char *name) : DatabaseKeyB((char *)key_name)
{
  strncpy(key_name, name,  MyKeyNameSize);
  key_name[ MyKeyNameSize-1] = 0; // Ensure null termination
}

void MyKeyClass::operator=(const char *name)
{
  strncpy(key_name, name,  MyKeyNameSize);
  key_name[ MyKeyNameSize-1] = 0; // Ensure null termination
}

int MyKeyClass::operator==(const DatabaseKeyB& key) const
{
  const MyKeyClass *kptr = (const MyKeyClass *)(&key);
  return (strcmp(key_name, (char *)kptr->db_key) == 0);
}

int MyKeyClass::operator>(const DatabaseKeyB& key) const
{
  const MyKeyClass *kptr = (const MyKeyClass *)(&key);
  return (strcmp(key_name, (char *)kptr->db_key) > 0);
}

const int NKEYS = 26;
const char *keys1[NKEYS] = { "DOG", "CAT", "FISH", "MOUSE", "BIRD", "PIG",
			     "HORSE", "LION", "SNAKE", "COW", "ARMADILLO",
			     "GROUPER", "RAT", "MONKEY", "ZEBRA",
			     "STARFISH", "LIZARD", "CRAB", "SNAIL",
			     "GORILLA", "LOBSTER", "TURKEY", "BEETLE",
			     "SHARK", "CLAM", "OYSTER" }; 

const char *keys2[NKEYS] = { "FLEA", "BUTTERFLY", "SPARROW", "GOLDFISH",
			     "TIGER", "BEAR", "TROUTE", "MOOSE", "DEAR",
			     "SALMON", "TUNA", "GAZELLE", "SLOTH", "SPIDER",
			     "LEAPORD", "GIRAFFE", "MUSTANG", "CONDOR",
			     "KANGAROO", "SKUNK", "FOX", "PANTER",
			     "CHEETAH", "TOUCAN", "PARROT", "BUFFALO" };


const char *keys3[NKEYS] = { "KOALA", "HORSEFLY", "ANACONDA", "CROCODILE",
			     "RACCOON", "ALLIGATOR", "RABBIT", "WHALE",
			     "ANT", "CRANE", "LONGHORN", "CANARY", "WOMBAT",
			     "WOLFHOUND", "COUGAR", "BAT", "OWL", "SHRIMP",
			     "SCALLOP", "SQUID", "PYTHON", "SARDINE",
			     "TAPIR", "ELEPHANT", "EEL", "RHINOCEROS" };

const char *keys4[NKEYS] = { "LAMB", "BISON", "GRASSHOPPER", "MACKEREL",
			     "FERRET", "WASP", "CATERPILLAR", "MILLIPEDE",
			     "CENTIPEDE", "MOSQUITO", "POSSUM", "DUCK",
			     "WEASEL", "CARIBOU", "ANTELOPE", "SALAMANDER",
			     "NEWT", "CHICKEN", "BULL", "COBRA",
			     "CHIMPANZEE", "URCHIN", "CROW", "WOLF",
			     "SPONGE", "JELLYFISH" };


void PausePrg()
{
  cout << endl;
  cout << "Press enter to continue..." << endl;
  cin.get();
}

void BtreeStatus(gxBtree &btx)
{
  cout << endl;
  cout << "Root address =      " << btx.Root() << endl;
  cout << "Number of entries = " << btx.NumKeys() << endl;
  cout << "Number of nodes =   " << btx.NumNodes() << endl;
  cout << "Btree order =       " << btx.NodeOrder() << endl;
  cout << "Btree height =      " << btx.BtreeHeight() << endl;
  PausePrg();
}

void BuildTree(gxBtree &btx, const char *keys[NKEYS])
{
  MyKeyClass key;
  MyKeyClass compare_key;
  int i, rv;

  const int INSERTIONS = NKEYS;

  // Inserting the keys
  for(i = 0; i < INSERTIONS; i++) {
    key = keys[i];  

    rv = btx.Insert(key, compare_key);
    
    if(rv != 1) {
      cout << endl << "Problem adding " << keys[i] << " - " << i << endl;
      return;
    }
  }

  // "Verifying the insertions
  for(i = 0; i < INSERTIONS; i++) {
    key = keys[i];      
    rv = btx.Find(key, compare_key);
    if(rv != 1) {
      cout << "Error finding key " << keys[i] << " - " << i << endl;
      return;
    }
  }


  // "Deleting all the entries
  for(i = 0; i < INSERTIONS; i++) {
    key = keys[i];      

    rv = btx.Delete(key, compare_key);

    if(rv != 1) {
      cout << "Error deleting key " << keys[i] << " - " << i << endl;
      return;
    }

    // Verify the remaining key locations
    for(int j = INSERTIONS-1; j != i; j--) {
      key = keys[j];      
      rv = btx.Find(key, compare_key);
      if(rv != 1) {
	cout << "Error finding key " << keys[j] << " - " << j << endl;
	cout << "After deleting key " << keys[i] << " - " << i << endl;
	return;
      }
    }
  }

  // Re-inserting all the keys
  for(i = 0; i < INSERTIONS; i++) {
    key = keys[i];  

    rv = btx.Insert(key, compare_key);

    if(rv != 1) {
      cout << endl << "Problem adding " << keys[i] << " - " << i << endl;
      return;
    }
  }

  BtreeStatus(btx);
}

int main()
{
  const char *fname = "testfile.btx";
  int num_trees = 4;

  MyKeyClass key, compare_key;
  gxBtree btx1(key, MyKeyClassOrder);
  gxBtree btx2(key, MyKeyClassOrder);
  gxBtree btx3(key, MyKeyClassOrder);
  gxBtree btx4(key, MyKeyClassOrder);

  // Create a new Btree index file with room for multiple Btrees
  gxDatabase *index_file = new gxDatabase;
  FAU static_size = \
    (FAU)(index_file->FileHeaderSize() * num_trees);
  index_file->Create(fname, static_size);
  if(CheckError(index_file) != 0) return 1;

  btx1.InitBtree(index_file, 1, (FAU)index_file->FileHeaderSize());
  btx2.InitBtree(index_file, 1, (FAU)(index_file->FileHeaderSize() * 2));
  btx3.InitBtree(index_file, 1, (FAU)(index_file->FileHeaderSize() * 3));
  btx4.InitBtree(index_file, 1, (FAU)(index_file->FileHeaderSize() * 4));

  cout << "Building the tree number 1..." << endl;
  BuildTree(btx1, keys1);

  cout << "Building the tree number 2..." << endl;
  BuildTree(btx2, keys2);
    
  cout << "Building the tree number 3..." << endl;
  BuildTree(btx3, keys3);

  cout << "Building the tree number 4..." << endl;
  BuildTree(btx4, keys4);

  cout << "Walking through the tree number 1 in sort order" << endl;
  PausePrg();
  
  // Walk through the tree starting at the first node
  if(btx1.FindFirst(key)) {
    cout << key.key_name << ' ';
    while(btx1.FindNext(key, compare_key))
      cout << key.key_name << ' ';
  }

  cout << endl << endl;
  cout << "Walking through the tree number 2 in sort order" << endl;
  PausePrg();
  
  // Walk through the tree starting at the first node
  if(btx2.FindFirst(key)) {
    cout << key.key_name << ' ';
    while(btx2.FindNext(key, compare_key))
      cout << key.key_name << ' ';
  }

  
  cout << endl << endl;
  cout << "Walking through the tree number 3 in sort order" << endl;
  PausePrg();
  
  // Walk through the tree starting at the first node
  if(btx3.FindFirst(key)) {
    cout << key.key_name << ' ';
    while(btx3.FindNext(key, compare_key))
      cout << key.key_name << ' ';
  }

  cout << endl << endl;
  cout << "Walking through the tree number 4 in sort order" << endl;
  PausePrg();
  
  // Walk through the tree starting at the first node
  if(btx4.FindFirst(key)) {
    cout << key.key_name << ' ';
    while(btx4.FindNext(key, compare_key))
      cout << key.key_name << ' ';
  }

  // Relase all references to the open file pointer. NOTE: If the file
  // pointer is not released, with more then one object referencing it,
  // the gxBtree destructor will automatically delete the file pointer
  // before any other object or entity referencing it has complete its
  // cleanup operations.
  btx1.Release();
  btx2.Release();
  btx3.Release();
  btx4.Release();

  // Delete the open file pointer
  delete index_file; // Database engine closed by destructor call

  cout << endl << endl;
  cout << "Exiting..." << endl;
  return 0;
}
// ----------------------------------------------------------- //
// ------------------------------- //
// --------- End of File --------- //
// ------------------------------- //