#ifndef _IKEYSET2_
  #define _IKEYSET2_
/*******************************************************************************
*                                                                              *
* 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 __USE_MALLOC
  #include <map.h>


  template <class Element, class Key, class Imp>
  class ITImpKeySet
  {
  public:

     ITImpKeySet   ( unsigned long numberOfElements=100);
    ~ITImpKeySet   ( );

     class Cursor
     {
     public:
       Cursor (const ITImpKeySet<Element, Key, Imp>& aList)
         : fList((ITImpKeySet<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:
         ITImpKeySet<Element, Key, Imp>
          &fList;
         map<Key, Imp, less<Key> >::iterator
           fIterator;
        friend class ITImpKeySet<Element, Key, Imp>;
     }; // Cursor

     bool
       add       ( Element const& element);

     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
       containsElementWithKey(const Key& key) const
             { return (fImp.find(key) != fImp.end());   }


     const Element
      &lastElement       ( ) const
     {
       map<Key, Imp, less<Key> >::const_iterator lastIterator = fImp.end();
       lastIterator--;
       return (Element const&)((*lastIterator).second);
     }

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

     bool
       locateOrAddElementWithKey ( const Element& element);

     bool
       replaceElementWithKey( Element const& element);

     void
       replaceAt ( const Cursor&  cursor,
                   const Element& element);

     bool
       addOrReplaceElementWithKey( 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)
       {
          map<Key, Imp, less<Key> >::iterator posIterator = fImp.begin();
          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;
       }

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

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


     bool
       allElementsDo   ( bool (*function) (Element&, void*),
                         void* additionalArgument = 0)
     {
       map<Key, Imp, less<Key> >::iterator allIterator = fImp.begin();
       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
        {
          map<Key, Imp, less<Key> >::const_iterator allIterator = fImp.begin();
          bool quit = false;
          while(allIterator != fImp.end() && quit == false)
          {
             quit = function((Element const&)((*allIterator).second), additionalArgument);
             allIterator++;
          }
          return !quit;
        }


     //  The following members of ISet are not supported:
     //
#if 0
       ITImpKeySet ( const ITImpKeySet<Element, Key, Imp>& keySet);


       ITImpKeySet
        &operator = ( const ITImpKeySet<Element, Key, Imp>& set);

       bool
         add       ( const Element& element,
                     Cursor&        cursor);

       void
         addAllFrom      ( const ITImpKeySet<Element, Key, Imp>& set),
         addAllFrom      ( const IACollection<Element>& collection);

       bool
         addOrReplaceElementWithKey ( const Element& element,
                                      Cursor&        cursor);

       const Element
        &anyElement      ( ) const;

       bool
         containsAllKeysFrom ( const ITImpKeySet& keySet),
         containsAllKeysFrom ( const IACollection<Element>& collection);

       void
         copy            ( const IACollection<Element>& collection);

       bool
         isBounded        ( ) const;

       bool
         isFull           ( ) const;

       const Key
        &key              ( const Element& element);

       bool
         locateOrAddElementWithKey ( const Element& element,
                                     Cursor&        cursor);

       unsigned long
         maxNumberOfElements ( ) const;

       Cursor
        *newCursor ( ) const;

       bool
         replaceElementWithKey( Element const& element,
                                Cursor&        cursor);

       bool
         setToFirst ( Cursor& cursor),
         setToNext  ( Cursor& cursor);

#endif  // Unsupported members of IKeySet

  private:
  map<Key, Imp, less<Key> >
    fImp;
  unsigned long
    fNumberOfElements;
  friend class Cursor;

  };

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


  template <class Element, class Key, class Imp>
  inline bool ITImpKeySet< 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 void ITImpKeySet< Element, Key, Imp>::replaceAt
              ( const Cursor&  cursor,
                const Element& element)
  {
     // This function seems unusual because the same thing is accomplish
     // by calling addOrReplaceElementWithKey.  The only thing gained(?)
     // here is an exception if the key of the cursored element doesn't
     // match the key of the element to replace it.  For now, we just
     // replace the element. Perhaps we need to add the assertions
     // later but I'd really like to change the source code using this
     // function (iacceltb.cpp) and remove it from the supported list.
     fImp[::key(element)] = element;
  }




template <class Element, class Key, class Imp>
  inline bool ITImpKeySet< 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 ITImpKeySet< 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 IKeySet : public ITImpKeySet<Element, Key, Element>
  {
  public:
    IKeySet( unsigned long numberOfElements = 100);
    ~IKeySet();
  };


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

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

#else // Not STL
  #include <ikeyset.h>
  #define IVPtrKeySet IKeySet
#endif

#endif  // _IKEYSET2_

