//
// Copyright (C) 1991 Texas Instruments Incorporated.
//
// Permission is granted to any individual or institution to use, copy, modify,
// and distribute this software, provided that this complete copyright and
// permission notice is maintained, intact, in all copies and supporting
// documentation.
//
// Texas Instruments Incorporated provides this software "as is" without
// express or implied warranty.
//
// Created: LGO 05/22/89 -- Initial design and implementation
// Updated: MBN 09/16/89 -- Added conditional exception handling
// Updated: MBN 10/13/89 -- Added Package_state typedef for Iterator<Type>
// Updated: MJF 06/30/90 -- Added base class name to constructor initializer
//
// The Package  class is publicly  derived from the Hash_Table<T1,T2> class and
// implements  a hash  table of Symbols.   The Symbol class is publicly derived
// from the Generic class and implements the notion of a symbol that has a name
// with an  optional  value and property   list.   Symbols   are interned  in a
// package, which is merely a mechanism for establishing a  name-space where by
// there is only one symbol with a given name in  a given package. Packages are
// implemented as hash tables by the COOL Package class,  which is a  friend of
// the Symbol class. Because   each  named Symbol  is   unique within  its  own
// package, they can be used  as a "dynamic  enumeration" type and as  run-time
// variables, with the Package acting as a symbol-table.
//
// In addition to dynamic run time symbols, the COOL DEFPACKAGE extension makes
// it possible  to define constant pointers  to symbols at  compile-time.   The
// compile-time symbols are interned in the package with the Initialize_Package
// method   of  Package.   This allows  for   efficient   symbol   and  package
// manipulation and is  used extensively by  COOL to  implement  run time  type
// checking and type query.
//
// The Package class has no data section, since it  is a specialization  of the
// Hash_Table<T1,T2> class. There are four constructors  for the Package class.
// The first takes no arguments and creates a package of the default  size that
// can hold 24 entires.  The  second takes an  integer argument  and  creates a
// package that can contain at least the specified number of entries. The third
// takes a number and a pointer to an initialize  method that is used to create
// packages of  constant symbols  by the DEFPACKAGE  macro.  The  last takes  a
// reference to a Package object and duplicates its size and values.
//
// In addition to the methods  inherited from the  Hash_Table<T1,T2> class, the
// Package class overloads several and provides the intern method to get and/or
// create a Symbol entry in the package. A user applicatino should only use the
// Package::intern() method to create and add Symbol objects. In addition, four
// functions   provide  Emacs-like  completion, next-completion, Interlisp-like
// spelling correction, and an  "apropos" function to  find all  symbols  whose
// name contains some series of characters.

#ifndef PACKAGEH				// If no Package definition
#define PACKAGEH

#ifndef SYMBOLH					// If no Symbol definition
#include <cool/Symbol.h>				// Include symbol header file
#endif

#ifndef HASH_TABLEH				// If no Hash Table definition
#include <cool/Hash_Table.h>				// Include header file
#endif

#ifndef PACKAGE_STATE
#define PACKAGE_STATE
typedef long Package_state;			// Current position state
#endif

class String;					// Forward reference String
class Package;					// Forward reference Package
DECLARE Hash_Table<char*, Symbol*>;

typedef void (*Package_Initializer)(Package*);	// Initialize package function

class Package : public Hash_Table<char*, Symbol*> {
public:
  inline Package ();				// Package of default size
  inline Package (unsigned long);		// Package for at least size
  Package (unsigned long n, Package_Initializer i); // Initialize const symbols
  inline Package (Package&);			// Package with reference
  ~Package();					// Destructor

  Boolean put (const char*, Symbol&);		// Initializes constant symbols
  inline const char* get_key (const Symbol*) CONST; // Get name of symbol
  Symbol* intern (const char*);			// Get and/or create symbol 
  Boolean remove (Symbol*);			// Remove Symbol from package
  inline Boolean remove (char*);		// Remove symbol from table
  friend ostream& operator<< (ostream&, const Package&);
  inline friend ostream& operator<< (ostream&, const Package*);

// The following methods are inherited from Hash_Table:
// Package& operator= (const Package&); 	// Assignment
// Boolean get (const Tkey&, Tval&);		// Get associated value for key
// void resize (int);				// Resize for at least count
// Boolean find (const Tkey&);			// Set current position
// Boolean remove ();				// Remove symbol at current pos
// const Tkey& key ();				// Get key at current position
// const Tval& value ();			// value at current position
// inline int length ();			// Return number of entries
// inline int capacity ();			// Return max number of entries
// inline Boolean is_empty ();			// Determine empty/nonempty 
// inline int get_bucket_count ();		// Return number of buckets
// inline void set_ratio (float);		// Set growth ratio
// inline get_count_in_bucket(int);		// Used to return item count
// inline void reset ();			// Set current position invalid
// Boolean next ();				// Advance current position
// Boolean prev ();				// Backup current position
// void clear ();				// Empty the Package
// Boolean operator== (Hash_Table<Tkey,Tval>&); // Package equality test
// inline Boolean operator!= (Hash_Table<Tkey,Tval>&); //     inequality test

};

// "Emacs"  style   symbol  name completion.  The   function modifies  the name
// parameter, returns the count of possible matches, and  sets current position
// of the Package to the last match found.

extern int complete (Package&, String&, Boolean sensitive = FALSE);


// Find the next symbol after the  current position whose name starts  with the
// given name. If found, return TRUE and set new  current position, else return
// FALSE.

extern Boolean completions (Package&, const char*, Boolean sensitive = FALSE);


// Perform "Interlisp" style spelling correction  on a symbol name. Returns the
// number of matches and sets the current position  of the Package to  the best
// match found. The number  of errors is  available by passing  a pointer to an
// int as the last parameter.

extern int correct (Package&, const char*, Boolean sensitive=FALSE,
		    int* errors=NULL);


// Find the next symbol from the current position in the package whose name
// contains the given name. If found, return TRUE and set new current position,
// else return FALSE.

extern Boolean apropos (Package&, const char*);


// Package -- Simple constructor to create package of default size to hold
//            24 entries
// Input:     None
// Output:    None

inline Package::Package () {
}


// Package -- Constructor to create a package to hold at least "n" entries
// Input:     Number of entries
// Output:    None


inline Package::Package (unsigned long n)
#ifdef __cplusplus
 : Hash_Table<char*, Symbol*>(n)
#else
 : (n)
#endif
{}

// Package -- Constructor that duplicates size and entries of another package
// Input:     Reference to Package object
// Output:    None

inline Package::Package (Package& p)
#ifdef __cplusplus
 : Hash_Table<char*, Symbol*>(p)
#else
 : (p) 
#endif
{}


// get_key -- Overload the Hash_Table::get_key() method to simply return the
//            name of the Symbol
// Input:     Pointer to symbol
// Output:    Symbol name

inline const char* Package::get_key (const Symbol* sym) CONST {
  return sym->name();
}


// remove -- Remove the symbol from the package
// Input:    Symbol name
// Output:   Boolean TRUE/FALSE

inline Boolean Package::remove (char* name) {
  return this->Hash_Table<char*, Symbol*>::remove(name);
}


// operator<< -- Overload the output operator to provide a crude print
//               capability for Package objects
// Input:        ostream reference, Package pointer
// Output:       Reference to ostream

inline ostream& operator<< (ostream& os, const Package* p) {
  return operator<< (os, *p);			// Output package
}

#endif





