#pragma once
#ifndef AUTOMATA_H
#define AUTOMATA_H

#include <climits>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>

namespace lxs {
    typedef unsigned long long State;
    typedef unsigned long long Priority;
    const State deadState = ULLONG_MAX;

    struct Automaton {
        State numStates = 0;
        std::set<State> accepting;
        std::map<State, Priority> priority;
        std::map<State, std::string> acceptingToken;
        State starting;
    };

    struct DFA : public Automaton {
        std::map<State, std::map<char, State> > delta;
    };

    struct NFA : public Automaton {
        std::map<State, std::map<char, std::set<State> > > delta;
        virtual std::set<State> eClose(State) const;
    };

    struct ENFA : public NFA {
        std::map<State, std::set<State> > epsilonTransitions;
        virtual std::set<State> eClose(State) const;

        private:
            mutable std::map<State, std::set<State> > eCloseCache;
    };

    std::string toDot(const DFA& d);
    std::string toDot(const NFA& n);
    std::string toDot(const ENFA& e);

    ENFA merge(const std::vector<ENFA>& enfas);
    DFA mssc(const NFA& e);
    DFA minimize(const DFA& d);
} //namespace lxs

#endif //AUTOMATA_H
