/*
 * Example 6: BTree-on-disk.  Retrieves birthdays, given a name
 *
 * $Id: btreedsk.cpp,v 7.4 1996/02/18 23:35:51 kyle Exp $
 *
 * (c) Copyright 1989 - 1996 Rogue Wave Software, Inc.
 * ALL RIGHTS RESERVED
 *
 * The software and information contained herein are proprietary to, and
 * comprise valuable trade secrets of, Rogue Wave Software, Inc., which
 * intends to preserve as trade secrets such software and information.
 * This software is furnished pursuant to a written license agreement and
 * may be used, copied, transmitted, and stored only in accordance with
 * the terms of such license and with the inclusion of the above copyright
 * notice.  This software and information or any other copies thereof may
 * not be provided or otherwise made available to any other person.
 *
 * Notwithstanding any other lease or license that may pertain to, or
 * accompany the delivery of, this computer software and information, the
 * rights of the Government regarding its use, reproduction and disclosure
 * are as set forth in Section 52.227-19 of the FARS Computer
 * Software-Restricted Rights clause.
 * 
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
 * Technical Data and Computer Software clause at DFARS 252.227-7013.
 * Contractor/Manufacturer is Rogue Wave Software, Inc.,
 * P.O. Box 2328, Corvallis, Oregon 97339.
 *
 * This computer software and information is distributed with "restricted
 * rights."  Use, duplication or disclosure is subject to restrictions as
 * set forth in NASA FAR SUP 18-52.227-79 (April 1985) "Commercial
 * Computer Software-Restricted Rights (April 1985)."  If the Clause at
 * 18-52.227-74 "Rights in Data General" is specified in the contract,
 * then the "Alternate III" clause applies.
 *
 ***************************************************************************
 *
 * $Log: btreedsk.cpp,v $
 * Revision 7.4  1996/02/18 23:35:51  kyle
 * Millenium adds prototype for printKey.
 *
 * Revision 7.3  1995/09/06 21:30:34  jims
 * Use new copyright macro
 *
 * Revision 7.2  1995/06/28  14:30:26  pearson
 * *** empty log message ***
 *
 * Revision 7.1  94/10/16  04:14:38  04:14:38  josh
 * Merged 6.1 and 7.0 development trees
 * 
 * Revision 6.5  1994/07/12  20:40:30  vriezen
 * Updated Copyright
 *
 * Revision 6.4  1994/06/28  22:31:08  nevis
 * Removed unused keyLen from main()
 *
 * Revision 6.3  1994/06/02  21:11:19  foote
 * Added RW_END_PROMPT macro
 *
 * Revision 6.2  1994/06/02  20:38:26  foote
 * Port to Symantec 7.0 on Macintosh
 *
 * Revision 6.1  1994/04/15  19:08:30  vriezen
 * Move all files to 6.1
 *
 * Revision 2.6  1993/08/07  21:40:21  keffer
 * Simplified further.
 *
 * Revision 2.5  1993/08/07  17:33:01  jims
 * Flush cout before requesting input from cin (MS C8 bug: streams not tied)
 *
 * Revision 2.4  1993/07/08  19:46:04  griswolf
 * Simplified by removing backward-compatible code
 *
 * Revision 2.3  1993/05/25  22:42:32  griswolf
 * updated to deal with the latest disktree version
 *
 * Revision 2.2  1993/02/24  22:42:06  griswolf
 * Update to fit version 0x200 RWBTreeOnDisk
 *
 * Revision 2.1  1992/12/04  05:07:27  myersn
 * update for tools.h++ 6.0
 *
 * Revision 2.0  1992/10/23  03:34:26  keffer
 * RCS Baseline version
 *
 * 
 *    Rev 1.1   07 Jun 1992 17:11:10   KEFFER
 * Tools.h++ V5.1
 * 
 */

#include "rw/disktree.h"
#include "rw/filemgr.h"
#include "rw/rwdate.h"
#include "rw/cstring.h"
#include "rw/rstream.h"


#ifdef applec                          
#  define RW_END_PROMPT   endl << flush
#else                                  
#  define RW_END_PROMPT   flush        
#endif                                 

// example of using a struct for the void* in applyToKeyAndValue:
struct printStruct {
  RWFileManager*	filemgr;
  unsigned	 	keyLen;
};

// Function to print a key and value:
void printKey(const char* a, RWstoredValue sv, void* x); // prototype

void 
printKey(const char* a, RWstoredValue sv, void* x)
{
  printStruct *ps = (struct printStruct *)x;
  unsigned len = ps->keyLen;
  RWCString key(a,len);		// don\'t count on trailing \0 in key
  RWDate bday;
  RWFileManager* fm = ps->filemgr;
  fm->SeekTo(sv);
  bday.restoreFrom(*fm);
  cout << "Name: " << key << " birthday: " << bday << endl;
}

main()
{
  RWCString	filename;
  RWDate	birthday;
  RWoffset	loc;

  cout << "       RWBTreeOnDisk sample program.\n";
  cout << "       Stores names and birthdays in a BTree.\n";

  cout << "Enter either the name of a new file or of a pre-existing file: " << RW_END_PROMPT;
  filename.readLine(cin);

  RWFileManager fmgr(filename.data());
  RWBTreeOnDisk bt(fmgr);	// Construct a B Tree with allocations managed by fmgr

  // display a list of this tree's parameters
  cout << "The RWBTreeOnDisk being managed in file " << filename;
  cout << ", has: " << endl;
  cout << "\tCache blocks:\t"     << bt.cacheCount() << endl;
  cout << "\tVersion:\t0x" << hex << bt.version() << dec << endl;
  cout << "\tKey Length:\t"       << bt.keyLength() << endl;
  cout << "\tOrder:\t\t"          << bt.order() << endl;
  cout << "\tMinimum Order:\t"    << bt.minOrder() << endl;
  cout << "\tHeight:\t\t"         << bt.height() << endl;
  cout << "\tEntries:\t"          << bt.entries() << endl;
  cout << endl;
  
  // Loop to do various things to the tree:

  while (1) {
    cout << "(i)ns (n)umber of entries (f)ind (d)el (l)ist (c)lear e(x)it: " << RW_END_PROMPT;

    /*
     * Read the character; check for EOF.
     */
    char response;
    if ( !(cin >> response).good() ) break;

    if ( response == 'x' || response == 'X' ) break; // Check for exit

    RWCString	name;
    RWCString	retKey;
    switch ( response ) {

    // Insert a key-value pair.
    case 'i':
    case 'I':

      cout << "Person's name: " << RW_END_PROMPT; // Prompt
      cin >> ws;			  // Skip any leading whitespace
      name.readLine(cin);		  // Get the person's name.
      name.resize(bt.keyLength());	  // Trim to the size of the B-Tree key.
      cout << "Birthday: " << RW_END_PROMPT;	  // Prompt for the person's birthday.
      cin >> birthday;			  // Read it in
      if( birthday.isValid() )		  // Check validity
      {
        loc = fmgr.allocate(birthday.binaryStoreSize());
        fmgr.SeekTo(loc);
        birthday.saveOn(fmgr);
        bt.insertKeyAndValue(name.data(), loc);	// Remember the location.
      }
      else
      {
        cin.clear();		// Clear state
        cout << "Bad date.\n";
      }
      break;

    // Find a person's birthday:
    case 'f':
    case 'F':

      cout << "Person's name: " << RW_END_PROMPT;   // Prompt
      cin >> ws;			  // Skip leading whitespace
      name.readLine(cin);		  // Get the person's name, to use as the key.
      name.resize(bt.keyLength());	  // Trim to the size of the B-Tree key.
      // Go find the birthday location.
      if(! bt.findKeyAndValue(name.data(), retKey, loc))
	cout << name << " not found.\n";
      else
      {
	fmgr.SeekTo(loc);
	birthday.restoreFrom(fmgr); // Retrieve the birthday.
	cout << "Birthday is " << birthday << endl;
      }
      break;

    // Delete a person:
    case 'd':
    case 'D':

      cout << "Name of person to delete: " << RW_END_PROMPT;
      cin >> ws;
      name.readLine(cin);
      name.resize(bt.keyLength());
      if(! bt.removeKeyAndValue(name.data(),loc))
	cout << "Can't find " << name << " to delete" << endl;
      else
	fmgr.deallocate(loc);
      
      break;

    // List the number of entries:
    case 'n':
    case 'N':

      cout << "Number of items in tree: " << bt.entries() << endl;
      break;

    // Clear the tree:
    case 'c':
    case 'C':
      cout << "Clearing..." << flush;
      bt.clear();		// Remove all keys.
      cout << "done.\n" << flush;
      break;

    // Print all entries:
    case 'l':

      struct printStruct ps;
      ps.filemgr = &fmgr;
      ps.keyLen = bt.keyLength();
      
      bt.applyToKeyAndValue(printKey, &ps);
      break;

    default:

      cerr << "Input not recognized...try again\n";

    }  // end switch
  }
  return 0;
}
