#### libremiliacr
#### Copyright(C) 2020-2024 Remilia Scarlet <remilia@posteo.jp>
####
#### This program is free software: you can redistribute it and/or modify
#### it under the terms of the GNU General Public License as published
#### the Free Software Foundation, either version 3 of the License, or
#### (at your option) any later version.
####
#### This program is distributed in the hope that it will be useful,
#### but WITHOUT ANY WARRANTY; without even the implied warranty of
#### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
#### GNU General Public License for more details.
####
#### You should have received a copy of the GNU General Public License
#### along with this program.If not, see<http:####www.gnu.org/licenses/.>

module RemiLib
  # Defines an `Enum` that that allows you to map keys to specific strings.  The
  # enum keys still have numerical values just like any other `Enum`, but these
  # numerical values cannot be specified.
  macro defineStringEnum(name, *values)
    enum {{name.id}}
      {% for val in values %}
        {% if val.is_a?(Assign) %}
           {{val.target.id}}
        {% else %}
          {% raise "Only assignments are supported for string-like Enums" %}
        {% end %}
      {% end %}

      def to_s(io : IO) : Nil
        case self
            {% for val in values %}
              {% if val.is_a?(Assign) %}
              in {{name.id}}::{{val.target.id}} then io << {{val.value}}
              {% end %}
            {% end %}
        end
      end

      def to_s : String
        case self
            {% for val in values %}
              {% if val.is_a?(Assign) %}
              in {{name.id}}::{{val.target.id}} then {{val.value}}
              {% end %}
            {% end %}
        end
      end

      def self.parse?(string : String) : self?
        case string
            {% for val in values %}
              {% if val.is_a?(Assign) %}
              when {{val.value}} then {{name.id}}::{{val.target.id}}
              {% end %}
            {% end %}
        else nil
        end
      end

      def self.parse(string : String) : self
        self.parse?(string) || raise ArgumentError.new("Cannot parse string to a #{ {{@type}} }: #{string}")
      end
    end
  end
end
