#include "cgi"

#include <vector>
#include <stack>
#include <cstring>
#include <istream>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <memory>

#include <sys/stat.h>
#include <sys/types.h>

//#include "../a2x/a2x"
//#include "../x2a/x2a"

#include "../exception/exception"
#include "../string/string"
#include "../stat/stat"
#include "../fswap/fswap"
#include "../ranger/ranger"

using namespace std;
using namespace FBB;

namespace FBB
{

typedef pair<char const *const, int (*const)(int)> PairCPPFunP;

class CGIFSA
{
    enum Token
    {
        DEFAULT = 256,
        SET,
        END,
    };            
    enum State         // change data.cc s_stateName when this changes
    {   
        START,
        CHECKSET,
        DEFINESET,
        OPENBRACKET,
        LEFTCOLON,
        SETNAME,
        RIGHTCOLON,

        N_STATES_,
        STOP = N_STATES_,
    };

    struct Record
    {
        State   current;
        size_t  token;
        void    (CGIFSA::*action)();
        State   next;
        size_t  (CGIFSA::*tokenizer)();
    };

    stack<char> d_stack;
    bool *d_escape;
    bool d_setEscape;
    State d_state;
    size_t  d_tokenIdx;
    string d_buffer;
    size_t  d_setIdx;
    istream &d_in;
           
    struct Transition
    {
        size_t  token;
        void (CGIFSA::*action)();
        State   next;
    };

    static vector<Transition> s_fsa[];
    static size_t (CGIFSA::*s_tokenizer[])();
    static Record const s_fsaRawData[];
    static Record const *const s_fsaRawDataEnd;
    static PairCPPFunP const s_charClass[];
    static PairCPPFunP const *const s_charClassEnd;
    static bool s_installed;
    static char const *s_stateName[];
    static string s_cgi;

    public:
        CGIFSA(bool *escape, istream &in = cin, bool setEscape = false);
        void run();

    private:
        void push();
        void accept();
        void charRange();
        void charClass();

        void acceptAll();           // all elements on the stack

        size_t tokenIdx();

        void setEscape(size_t idx);                 // .i
    
        size_t charToken();
        size_t wordToken();

        static void setFsa(Record const &record);
        static int iscgi(int ch);                   // .i
};

#include "iscgi.f"
#include "setescape.f"

}   // namespace
