    // ------------------------------- //
    // -------- 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: 06/25/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;
        }
      }

      // "Verifing 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 --------- //
    // ------------------------------- //