#pragma once


#include <unordered_map>
#include <vector>
#include <string>


//template <typename EnumType>
class enum_map
{
public:
    enum_map(const char* enum_name)
      : enumName(enum_name)
    {
    }

    template <typename EnumType>
    void addMapping(EnumType val, const char* name)
    {
        // TODO : check that val is in the range of int
        enumValues.push_back(name);
        enumToStringMap.insert(std::make_pair(static_cast<int>(val), name));
        stringToEnumMap.insert(std::make_pair(name, static_cast<int>(val)));
    }

    const std::vector<std::string> values() const
    {
        return enumValues;
    }

    template <typename EnumType>
    const std::string& to_string(EnumType val) const
    {
        // TODO : check val is valid
        return enumToStringMap.at(static_cast<int>(val));
    }

    int from_string(std::string str) const
    {
        // TODO : check val is valid
        return stringToEnumMap.at(str);
    }

    template <typename EnumType>
    EnumType from_string2(std::string str) const
    {
        // TODO : check val is valid
        return static_cast<EnumType>(stringToEnumMap.at(str));
    }

    bool inited = false;

private:
    std::string enumName;
    std::vector<std::string> enumValues;
    std::unordered_map<int, std::string> enumToStringMap;
    std::unordered_map<std::string, int> stringToEnumMap;
};

    
std::unordered_map<std::string, const enum_map*> allEnums;


class RegisterEnum
{
public:
    RegisterEnum(const char* enum_name, const enum_map& e)
    {
        allEnums.insert(std::make_pair(enum_name, &e));
    }
};

//template <typename EnumType>
//const enum_map<EnumType>& enum_mapping(EnumType e = 0);
//const enum_map& enum_mapping(EnumType e);

template <typename EnumType>
std::string to_string(EnumType e)
{
  return enum_mapping(e).to_string(e);
}

template <typename EnumType>
EnumType from_string(std::string str)
{
  // return static_cast<EnumType>(enum_mapping(static_cast<EnumType>(0)).template from_string<EnumType>(str));
  return static_cast<EnumType>(enum_mapping(static_cast<EnumType>(0)).from_string(str));
}

