
IS.@scoped_enum(
    InputCategory,
    BRANCH = 1,
    BUS = 2,
    DC_BRANCH = 3,
    GENERATOR = 4,
    LOAD = 5,
    RESERVE = 6,
    SIMULATION_OBJECTS = 7,
    STORAGE = 8,
)

const ENUMS = (
    AngleUnits,
    BusTypes,
    GeneratorCostModels,
    InputCategory,
    LoadModels,
    PrimeMovers,
    StateTypes,
    ThermalFuels,
    UnitSystem,
)

const ENUM_MAPPINGS = Dict()

for enum in ENUMS
    ENUM_MAPPINGS[enum] = Dict()
    for value in instances(enum)
        ENUM_MAPPINGS[enum][lowercase(string(value))] = value
    end
end

"""Get the enum value for the string. Case insensitive."""
function get_enum_value(enum, value::String)
    if !haskey(ENUM_MAPPINGS, enum)
        throw(ArgumentError("enum=$enum is not valid"))
    end

    val = lowercase(value)
    if !haskey(ENUM_MAPPINGS[enum], val)
        throw(ArgumentError("enum=$enum does not have value=$val"))
    end

    return ENUM_MAPPINGS[enum][val]
end

Base.convert(::Type{AngleUnits}, val::String) = get_enum_value(AngleUnits, val)
Base.convert(::Type{BusTypes}, val::String) = get_enum_value(BusTypes, val)
Base.convert(::Type{GeneratorCostModels}, val::String) =
    get_enum_value(GeneratorCostModels, val)
Base.convert(::Type{LoadModels}, val::String) = get_enum_value(LoadModels, val)
Base.convert(::Type{PrimeMovers}, val::String) = get_enum_value(PrimeMovers, val)
Base.convert(::Type{StateTypes}, val::String) = get_enum_value(StateTypes, val)
Base.convert(::Type{ThermalFuels}, val::String) = get_enum_value(ThermalFuels, val)
