// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SET_KERNEl_1_
#define DLIB_SET_KERNEl_1_

#include "set_kernel_abstract.h"
#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename T,
        typename bst_base,
        typename mem_manager = default_memory_manager
        >
    class set_kernel_1 : public enumerable<const T>,
                         public asc_remover<T,typename bst_base::compare_type>
    {

        /*!
            REQUIREMENTS ON bst_base
                bst_base is instantiated with <domain=T,range=char> and
                implements binray_search_tree/binary_search_tree_kernel_abstract.h

            INITIAL VALUE
                bst has its initial value

            CONVENTION
                bst.size() == the number of elements in the set and
                the elements in the set are stored in bst
        !*/
        

        public:

            typedef T type;
            typedef typename bst_base::compare_type compare_type;
            typedef mem_manager mem_manager_type;

            set_kernel_1(
            )
            {
            }

            virtual ~set_kernel_1(
            )
            {}

            inline void clear(
            );

            inline void add (
                T& item
            );

            inline bool is_member (
                const T& item
            ) const;

            inline void remove (
                const T& item,
                T& item_copy
            );

            inline void destroy (
                const T& item
            );

            inline void swap (
                set_kernel_1& item
            );

            // functions from the remover interface
            inline void remove_any (
                T& item
            );

            // functions from the enumerable interface
            inline size_t size (
            ) const;

            inline bool at_start (
            ) const;

            inline void reset (
            ) const;

            inline bool current_element_valid (
            ) const;

            inline const T& element (
            ) const;

     
            inline const T& element (
            );

            inline bool move_next (
            ) const;

            
        private:

            bst_base bst;
            char junk;

            // restricted functions
            set_kernel_1(set_kernel_1&);        
            set_kernel_1& operator=(set_kernel_1&); 

    };

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    inline void swap (
        set_kernel_1<T,bst_base,mem_manager>& a, 
        set_kernel_1<T,bst_base,mem_manager>& b 
    ) { a.swap(b); } 

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void deserialize (
        set_kernel_1<T,bst_base,mem_manager>& item, 
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            T temp;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(temp,in);
                item.add(temp);
            }
        }
        catch (serialization_error e)
        { 
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type set_kernel_1"); 
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    clear (
    )
    {
        bst.clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    add (
        T& item
    )
    {
        bst.add(item,junk);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    bool set_kernel_1<T,bst_base,mem_manager>::
    is_member(
        const T& item
    ) const
    {
        return (bst[item] != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    remove_any (
        T& item
    )
    {
        bst.remove_any(item,junk);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    remove(
        const T& item,
        T& item_copy
    )
    {
        bst.remove(item,item_copy,junk);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    destroy(
        const T& item
    )
    {
        bst.destroy(item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    size_t set_kernel_1<T,bst_base,mem_manager>::
    size (
    ) const
    {
        return bst.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    swap (
        set_kernel_1<T,bst_base,mem_manager>& item
    )
    {
        bst.swap(item.bst);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    bool set_kernel_1<T,bst_base,mem_manager>::
    at_start (
    ) const
    {
        return bst.at_start();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    reset (
    ) const
    {
        bst.reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    bool set_kernel_1<T,bst_base,mem_manager>::
    current_element_valid (
    ) const
    {
        return bst.current_element_valid();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    const T& set_kernel_1<T,bst_base,mem_manager>::
    element (
    ) const
    {
        return bst.element().key();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    const T& set_kernel_1<T,bst_base,mem_manager>::
    element (
    )
    {
        return bst.element().key();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    bool set_kernel_1<T,bst_base,mem_manager>::
    move_next (
    ) const
    {
        return bst.move_next();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SET_KERNEl_1_