#ifndef _INCLUDED_BOBCAT_CMDFINDER_
#define _INCLUDED_BOBCAT_CMDFINDER_

#include <algorithm>
#include <string>

#include <bobcat/cmdfinderbase>

namespace FBB
{
    template <typename FP>
    class CmdFinder: public CmdFinderBase
    {
        size_t d_count;

        protected:
            typedef FP FunctionPtr;                 // define template type 
                                                    // as a named type

                                                    // elements of the array
                                                    // of keys/f-ptrs
            typedef std::pair<char const *, FP> Entry;
    
        private:
            Entry const *d_begin;
            Entry const *d_end;

            friend class MatchKey;
    
            class MatchKey
            {
                FP *d_fp;
                CmdFinder<FP> *d_cmdFinder;
    
                public:
                    MatchKey(FunctionPtr *fp, 
                             CmdFinder<FP> *cmdFinder)
                    :
                        d_fp(fp),
                        d_cmdFinder(cmdFinder)
                    {}

                    bool operator()(CmdFinder::Entry const &entry)
                    {
                        if (!d_cmdFinder->match(entry.first))
                            return false;

                        *d_fp = entry.second;
                        return true;
                    }
            };
    
            bool match(std::string const &key) const
            {
                return (this->*d_match)(key);
            }

        protected:
            CmdFinder(Entry const *begin, Entry const *end,
                      size_t mode = 0)
            :
                CmdFinderBase(mode),
                d_count(0),
                d_begin(begin),
                d_end(end)
            {}

            FP findCmd(std::string const &cmd)
            {
                (this->*d_useCmd)(cmd);     // store the cmd to use

                FunctionPtr fp;
                MatchKey matchKey(&fp, this);   // create an object matching 
                                                // a cmd with a key

                                            // count the number of occurrences
                d_count = std::count_if(d_begin, d_end, matchKey);

                                     
                return d_count == 1 ?   
                            fp              // return fp if cmd found
                        :                   // otherwise return the last fptr
                            (d_end - 1)->second;
            }

            size_t count() const
            {
                return d_count;
            }
    };

} // FBB
        
#endif




