    // ------------------------------- //
    // -------- 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: 05/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 is a test program for the Btree node class.
    */
    // ----------------------------------------------------------- //
    #include <iostream.h>
    #include "btnode.h"
    #include "gxdbase.h"

    // Set the node order and maximum key size for this key class
    const BtreeNodeOrder_t MyKeyClassOrder = 8;
    const __WORD__ MyKeyNameSize = 26;

    // Key class for this database
    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)
    {
      for(int i = 0; i < MyKeyNameSize; i++) key_name[i] = 0;
      strcpy(key_name, name);
    }

    void MyKeyClass::operator=(const char *name)
    {
      for(int i = 0; i < MyKeyNameSize; i++) key_name[i] = 0;
      strcpy(key_name, name);
    }

    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);
    }

    void PrintNode(BtreeNode &n)
    // Print a Btree node.
    {
      MyKeyClass kbuf;
      BtreeKeyLocation_t key_location = (BtreeKeyLocation_t)0;
      for(BtreeKeyCount_t i = (BtreeKeyCount_t)0; i < n.key_count; i++) {
        n.LoadKey(kbuf, key_location++);
        cout << (char *)kbuf.key_name << ' ' << kbuf.right_child << ' ';
      }
      cout << endl;
      cout << "Key count = " << n.key_count << endl;
      cout << "Left child = " << n.left_child << endl;
    }

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

    gxDatabaseError WriteNode(gxDatabase *f, const BtreeNode &n, FAU na)
    // Function used to write a Btree node to an open database file.
    // Returns zero if successful or a non-zero value to indicate a
    // failure.
    {
      gxDatabaseError rv;
      rv = f->Write(&n.key_count, sizeof(n.key_count), na);
      if(rv != gxDBASE_NO_ERROR) return rv;
      rv = f->Write(&n.left_child, sizeof(n.left_child));
      if(rv != gxDBASE_NO_ERROR) return rv;
      rv = f->Write(n.key_entries, (n.key_size * n.node_order));
      if(rv != gxDBASE_NO_ERROR) return rv;
      return rv;
    }

    gxDatabaseError ReadNode(gxDatabase *f, BtreeNode &n, FAU na)
    // Function used to read a Btree node from an open database file.
    // Returns zero if successful or a non-zero value to indicate a
    // failure.
    {
      gxDatabaseError rv;
      rv = f->Read(&n.key_count, sizeof(n.key_count), na);
      if(rv != gxDBASE_NO_ERROR) return rv;
      rv = f->Read(&n.left_child, sizeof(n.left_child));
      if(rv != gxDBASE_NO_ERROR) return rv;
      rv = f->Read(n.key_entries, (n.key_size * n.node_order));
      if(rv != gxDBASE_NO_ERROR) return rv;
      return rv;
    }

    int main()
    {
      MyKeyClass key, compare_key;

      cout << "--------- Key and Btree Node Statistics ---------" << endl;
      cout << "Key name size     = " << key.KeySize() << endl;
      cout << "Database key size = " << key.SizeOfDatabaseKey() << endl;
      cout << "Key entry size    = "
           << (key.SizeOfDatabaseKey() * (MyKeyClassOrder-1)) << endl;
      BtreeNode n(key.SizeOfDatabaseKey(), MyKeyClassOrder);
      cout << "Btree order       = " << n.node_order << endl;
      cout << "Btree node size   = " << n.SizeOfBtreeNode() << endl;

      PausePrg();

      BtreeKeyLocation_t key_location = (BtreeKeyLocation_t)0;
      int i, rv;
      const char *strings[7] = { // Array matching the Btree order
        "DOG", "CAT", "PIG", "COW", "FISH", "ZEBRA", "HORSE"
      };

      cout << "Inserting " << n.node_order << " entries into the Btree node"
           << endl;
      for(i = 0; i < n.node_order; i++) {
        key = strings[i];

        rv = n.FindKeyLocation(key, compare_key, key_location);

        // Do not insert duplicate keys
        if(rv != 0) {
          key_location++;
          n.InsertDatabaseKey(key, key_location);
        }
      }

      cout << "Reading back the database keys" << endl;
      PrintNode(n);

      PausePrg();

      cout << "Testing database read/write operations" << endl;
      gxDatabase *f = new gxDatabase();
      f->Create("testfile.gxd");
      FAU node_address = f->Alloc(n.SizeOfBtreeNode());
      WriteNode(f, n, node_address);
      BtreeNode nbuf(key.SizeOfDatabaseKey(), MyKeyClassOrder);
      ReadNode(f, nbuf, node_address);
      PrintNode(nbuf);
      delete f;

      PausePrg();

      cout << "Testing the delete function" << endl;
      n.DeleteDatabaseKey((BtreeKeyLocation_t)0);
      PrintNode(n);

      PausePrg();

      cout << "Testing the split fucntion" << endl;
      BtreeNode r(key.SizeOfDatabaseKey(), MyKeyClassOrder);
      n.SplitNode(r, n.node_order/2);
      PrintNode(n);
      cout << endl;
      PrintNode(r);

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