#pragma once
#ifndef LEXESIS_BACKEND_H
#define LEXESIS_BACKEND_H

#include "Lexesis/automata.h"
#include "Lexesis/template.h"

#include "mstch/mstch.hpp"

#include <functional>
#include <memory>
#include <string>

namespace lxs {
    /**
     * A general interface for a Lexesis backend
     */
    class Backend {
        public:
            /**
             * Constructor
             */
            Backend();

            /**
             * Destructor
             */
            virtual ~Backend();

            /**
             * Report a name for the backend
             * used in resolving template paths
             *
             * @return std::string A name for the backend
             */
            virtual std::string getName() = 0;

            /**
             * Can this backend process the language with given description?
             *
             * @param lang A description for a language (eg. "c++", "cxx", "cpp")
             * @return Can this backend process it
             */
            virtual bool canProcessLang(std::string lang);

            /**
             * The function that gets called to generate the actual lexer
             *
             * @param getOstreamForFileName A function that takes a filename and returns a std::ostream that the backend can write to for that filename
             * @param lexerName The name that should be given to the lexer
             * @param dfa The automaton that should be used in generating the lexer
             */
            virtual void generateLexer(std::function<std::unique_ptr<std::ostream>(std::string)> getOstreamForFileName, std::string lexerName, const DFA& dfa) = 0;

        protected:
            /**
             * Render a template (with given (file)name) to the given ostream with the information provided
             *
             * @param out The ostream to write the rendered template to
             * @param templateName An identifier for the template, is combined with `getName()` to construct the actual path
             * @param context The information that should be provided to the template when rendering
             */
            void doTemplate(std::ostream& out, std::string templateName, templ::TemplateContext context);

        private:
            /**
             * Find the template with given name
             *
             * @param templateName the template name, gets combined with `getName()`
             */
            std::string findTemplate(std::string templateName);
    };
}

#endif //LEXESIS_BACKEND_H

