#include <utility>

#ifndef PORYGONLANG_STATICSCOPE_HPP
#define PORYGONLANG_STATICSCOPE_HPP

#include <map>
#include "../Utilities/HashedString.hpp"
#include "../Binder/BoundVariables/BoundVariable.hpp"
#include "../Evaluator/EvalValues/EvalValue.hpp"
#include "BasicLibrary.hpp"

using namespace std;
namespace Porygon::StandardLibraries{
    /*!
    \class StaticScope
    \brief The static shared scope for all scripts. Variables registered in here should be stateless.
    */
    class StaticScope {
        class InternalScope{
        public:
            map<Utilities::HashedString, Binder::BoundVariable *> _boundVariables;
            map<Utilities::HashedString, Evaluation::EvalValue*> _variables;

            InternalScope(){
                BasicLibrary::RegisterVariables(&_boundVariables, &_variables);
            }

            ~InternalScope(){
                for (const auto& b: _boundVariables){
                    delete b.second;
                }
                for (const auto& v: _variables){
                    delete v.second;
                }
            }
        };

        static InternalScope _internal;
    public:
        static void RegisterVariable(const Utilities::HashedString& identifier, shared_ptr<ScriptType> type, Evaluation::EvalValue* value){
            _internal._boundVariables.insert({identifier, new Binder::BoundVariable(std::move(type))});
            _internal._variables.insert({identifier, value});
        }

        static Binder::BoundVariable* GetBoundVariable(const Utilities::HashedString &identifier){
            auto found = _internal._boundVariables.find(identifier);
            if (found != _internal._boundVariables.end()) {
                return found->second;
            }
            return nullptr;
        }

        inline static Evaluation::EvalValuePointer GetVariable(const Utilities::HashedString &identifier){
            return _internal._variables[identifier]->Clone();
        }
    };
}


#endif //PORYGONLANG_STATICSCOPE_HPP
