#ifndef _SELECTOR_H_
#define _SELECTOR_H_

#include <iosfwd>
#include <string>
#include <vector>

class Options;
class Alternatives;

struct Selector
{
    enum ReturnValue
    {
        CD           = 0,
        COMMAND      = 1,
        NO_SELECTION = 2,
        NO_SOLUTIONS = 3,
        USAGE        = 4,
        ERROR        = 5
    };

    private:
        enum
        {
            MIN_BLOCK_SIZE = 5              // # alternatives showed in 
        };                                  // a block of alternatives
    
        enum Action
        {
            DEC,
            INC,
            INPUT
        };

        struct Block
        {
            size_t begin;
            size_t end;
            std::string prompt;
        };

        Options const &d_options;    
        Alternatives &d_alternatives;
    
        size_t d_index;                 // constructor: #alternatives,
                                        // at select(): selected alternative
        size_t d_blockSize;
        
        bool   d_ioctl;                 // true: --input was specified

        bool d_direct;                  // Alternatives's result == DIRECT

        ReturnValue d_returnValue;
    
        std::string d_selectChars;      // d_blockSize substr of s_allChars
    
        static std::string s_dec;       // chars used to inc. the block-index
        static std::string s_inc;       // chars used to dec. the block-index
        static std::string s_allChars;  // all possible alternative selection
                                        // chars.
    public:
        Selector(Alternatives &alternatives);

        void select();
        ReturnValue returnValue() const;                                // .f

    private:
        static bool accept(int ch, std::string const &alternatives, 
                                   std::string const &accepted);
        Action action(Block const &block);
        std::vector<Block> blockVector(size_t nBlocks);

        void chdir();                       // changes dir to d_alt.[d_index]
        static void input(std::string const &text);
        void noCD(int ch);
                                            // set bextBlock's begin/end 
                                            // fields
        void set(Block &nextBlock, size_t lastEnd) const;               // 1
        void set(Block &beforeLast, Block &last);                       // 2

                                            // set the #alternatives shown in
        void setBlockSize();                // a block

        void showAlternatives();
        void show(Block const &block) const;
};

#include "selector.f"

#endif
