#ifndef _IKSHSH2_
  #define _IKSHSH2_
/*******************************************************************************
*                                                                              *
* COPYRIGHT:                                                                   *
*   IBM Open Class Library                                                     *
*   (C) Copyright International Business Machines Corporation 1992, 1997       *
*   Licensed Material - Program-Property of IBM - All Rights Reserved.         *
*                                                                              *
*******************************************************************************/

  #include <ibase.hpp>

#ifdef IC_USE_STL

  #include <istdops2.h>

//  #define _HASHKEYSET_AS_HASHMAP_
  #define __USE_MALLOC
  #ifdef _HASHKEYSET_AS_HASHMAP_
    #include <hash_map.h>
  #else
    #include <map.h>
  #endif


  template <class Element, class Key, class Imp>
  class ITImpKeySetAsHshTable
  {
  public:
     ITImpKeySetAsHshTable   ( unsigned long numberOfElements=100);
    ~ITImpKeySetAsHshTable   ( );

     class Cursor
     {
     public:
       Cursor (const ITImpKeySetAsHshTable<Element, Key, Imp>& aList)
         : fList((ITImpKeySetAsHshTable<Element, Key, Imp>&)aList),
           fIterator(fList.fImp.begin()) {}

       Cursor ( const Cursor& cursor)
         : fList(cursor.fList),
           fIterator(cursor.fIterator) {}

       Cursor& operator=(const Cursor& cursor)
       {
          if(this != &cursor)
          {
             fList = cursor.fList;
             fIterator = cursor.fIterator;
          }
          return *this;
       }


       bool setToFirst ()    { fIterator = fList.fImp.begin(); return fList.fImp.empty();}
       bool setToLast ()     { fIterator = fList.fImp.end();   fIterator--;
                               return fList.fImp.empty();}
       bool setToNext ()     { fIterator++; return fList.fImp.empty();}
       bool setToPrevious () { fIterator--; return fList.fImp.empty();}
       bool isValid()  const { return (fList.fImp.begin()!=fList.fImp.end()
                                    && fIterator!=fList.fImp.end()); }
       void invalidate ( )
       {     fIterator = fList.fImp.end(); }

       Element const
        &element    ( ) const
            { return (Element const&)((*fIterator).second);   }

       private:
       ITImpKeySetAsHshTable<Element, Key, Imp>
          &fList;
       #ifdef _HASHKEYSET_AS_HASHMAP_
         hash_map<Key, Imp, hash<Key>, equal_to<Key> >::iterator
           fIterator;
       #else
         map<Key, Imp, less<Key> >::iterator
           fIterator;
       #endif
        friend class ITImpKeySetAsHshTable<Element, Key, Imp>;
     }; // Cursor

     bool
       add       ( Element const& element);

     bool
       addOrReplaceElementWithKey( Element const& element);

     bool
       allElementsDo   ( bool (*function) (Element&, void*),
                         void* additionalArgument = 0)
       {

         #ifdef _HASHKEYSET_AS_HASHMAP_
           hash_map<Key, Imp, less<Key> >::iterator allIterator = fImp.begin();
         #else
           map<Key, Imp, less<Key> >::iterator allIterator = fImp.begin();
         #endif
         bool quit = false;
         while(allIterator != fImp.end() && quit == false)
         {
            quit = function((Element&)((*allIterator).second), additionalArgument);
            allIterator++;
         }
         return !quit;
       }

     bool
       allElementsDo   ( bool (*function) (Element const&, void*),
                         void* additionalArgument = 0) const
       {

         #ifdef _HASHKEYSET_AS_HASHMAP_
           hash_map<Key, Imp, less<Key> >::const_iterator allIterator = fImp.begin();
         #else
           map<Key, Imp, less<Key> >::const_iterator allIterator = fImp.begin();
         #endif
         bool quit = false;
         while(allIterator != fImp.end() && quit == false)
         {
            quit = function((Element const&)((*allIterator).second), additionalArgument);
            allIterator++;
         }
         return !quit;
       }

     bool
       containsElementWithKey(const Key& key) const
             { return (fImp.find(key) != fImp.end());   }

     Element
      &elementAt   ( const Cursor& cursor)
             { return (Element &)((*cursor.fIterator).second); }

     Element const
      &elementAt   ( const Cursor& cursor) const
             { return (Element const&)((*cursor.fIterator).second); }

     Element const&
       elementWithKey( Key const& key) const
             { return (Element const&)((*(fImp.find(key))).second);   }

     Element&
       elementWithKey( Key const& key)
             { return (Element &)((*(fImp.find(key))).second);   }

     bool
       isEmpty ( ) const { return (fImp.size() == 0); }

     bool
       locateElementWithKey  ( const Key& key, Cursor&    cursor)
            {  return ( (cursor.fIterator = fImp.find(key)) != fImp.end() ); }

     bool
       locateOrAddElementWithKey ( const Element& element);

     unsigned long
       numberOfElements ( ) const { return fImp.size(); }

     bool
       replaceElementWithKey( Element const& element);

     void
       removeAt ( Cursor& cursor) { fImp.erase( cursor.fIterator++); }

     unsigned long
       removeAll ( )
       {
         unsigned long count = fImp.size();
         fImp.erase(fImp.begin(), fImp.end());
         return count;
       }

     unsigned long
       removeAll ( bool (*predicateFunction)(Element const&, void*), void* data=0)
       {
          #ifdef _HASHKEYSET_AS_HASHMAP_
             hash_map<Key, Imp, less<Key> >::iterator posIterator = fImp.begin();
          #else
             map<Key, Imp, less<Key> >::iterator posIterator = fImp.begin();
          #endif
          unsigned long count = 0;
          while(posIterator != fImp.end())
          {
             if(predicateFunction((Element&)((*posIterator).second), data))
             {
               fImp.erase(posIterator);
               count++;
             }
             posIterator++;
          }
          return count;
       }

     bool
       removeElementWithKey ( const Key& key)
       {
          bool present = containsElementWithKey(key);
          if(present)
            fImp.erase(key);
          return present;
       }


  private:
  #ifdef _HASHKEYSET_AS_HASHMAP_
    hash_map<Key, Imp, hash<Key>, equal_to<Key> >
       fImp;
  #else
    map<Key, Imp, less<Key> >
      fImp;
  #endif
  unsigned long
    fNumberOfElements;
  friend class Cursor;

  };


template <class Element, class Key, class Imp>
inline bool ITImpKeySetAsHshTable< Element, Key, Imp>::add( Element const& element)
{
  Key const& key = ::key(element);
  fImp[key] = element; return true;
}

template <class Element, class Key, class Imp>
  inline bool ITImpKeySetAsHshTable< Element, Key, Imp>::locateOrAddElementWithKey ( const Element& element)
  {
     bool present = containsElementWithKey(::key(element));
     if(!present)
        add(element);
     return present;
  }

template <class Element, class Key, class Imp>
  inline bool ITImpKeySetAsHshTable< Element, Key, Imp>::replaceElementWithKey( Element const& element)
  {
     bool exists = (fImp.find(::key(element)) != fImp.end());
     fImp[::key(element)] = element;
     return exists;
  }

  template <class Element, class Key, class Imp>
  inline bool ITImpKeySetAsHshTable< Element, Key, Imp>::addOrReplaceElementWithKey( Element const& element)
  {
     bool exists = (fImp.find(::key(element)) != fImp.end());
     fImp[::key(element)] = element;
     return exists;
  }



  template <class Element, class Key>
  class IKeySetAsHshTable : public ITImpKeySetAsHshTable<Element, Key, Element>
  {
  public:
    IKeySetAsHshTable( unsigned long numberOfElements = 100);
    ~IKeySetAsHshTable();
  };

  #ifdef IC_USE_STL_VPTR
    template <class Element, class Key>
    class IVPtrKeySetAsHshTable : public ITImpKeySetAsHshTable<Element, Key, void*>
    {
    public:
      IVPtrKeySetAsHshTable( unsigned long numberOfElements = 100);
      ~IVPtrKeySetAsHshTable();
    };
  #else
    #define IVPtrKeySetAsHshTable IKeySetAsHshTable
  #endif


  #ifndef __TEMPINC__
    #include <ikshsh2.c>
  #endif


#else // Not STL
  #include <ikshsh.h>
  #define IVPtrKeySetAsHshTable IKeySetAsHshTable
#endif

#endif  // _IKSHSH2_

