module UnitConversion
  INTEGER_REGEX = /-?[0-9]+/
  DECIMAL_REGEX = /(?:-?[0-9]+)?\.[0-9]+/
  RATIONAL_REGEX = /-?(?:[0-9]+ )?[0-9]+\/[0-9]+/
  UNIT_REGEX = /[\[\]a-zA-Z][\[\]a-zA-Z\/.\-()0-9 ]*/
  UNIT_PARSING_REGEX = /^(?<value>#{INTEGER_REGEX}|#{DECIMAL_REGEX}|#{RATIONAL_REGEX})(?:\s+(?<unit>#{UNIT_REGEX}))?$/

  STANDARD_UNIT_ALIASES = {
      '[cup_us]': %w(cup cups c),
      '[tbs_us]': %w(tablespoon tablespoons tbsp tbs),
      '[tsp_us]': %w(teaspoon teaspoons tsp),
      '[oz_av]': %w(ounce ounces oz),
      '[lb_av]': %w(pound pounds lb lbs),
      '[pt_us]': %w(pint pints),
      '[qt_us]': %w(quart quarts qt),
      '[gal_us]': %w(gallon gallons ga),
      '[foz_us]': %w(foz floz),
      '[in_i]': %w(inch inches in)
  }

  METRIC_UNIT_ALIASES = {
      g: %w(gram grams),
      kg: %w(kilogram kilograms),

      ml: %w(milliliter milliliters),
      cl: %w(centiliter centiliters),
      dl: %w(deciliter deciliters),
      l: %w(liter liters),

      m: %w(meter meters),
      cm: %w(centimeter centimeters)
  }

  UNIT_ALIASES = STANDARD_UNIT_ALIASES.merge(METRIC_UNIT_ALIASES)

  UNIT_ALIAS_MAP = Hash[UNIT_ALIASES.map { |unit, values| values.map { |v| [v, unit] } }.flatten(1)]

  # map that gives comfortable ranges for a given set of units
  UNIT_RANGES = {
      '[tsp_us]': (0.125...3.0),
      '[tbs_us]': (0.5...4.0),
      '[cup_us]': (0.25...4.0),
      '[qt_us]': (1.0..3.9),
      '[gal_us]': (0.5..9999),

      '[oz_av]': (0..16),
      '[lb_av]': (1.0..9999),

      g: (1.0..750),
      kg: (0.5..9999),

      ml: (1.0..750),
      l: (0.5..9999)
  }

  UNIT_ORDERS = {
      standard_volume: [
          :'[tsp_us]',
          :'[tbs_us]',
          :'[cup_us]',
          :'[qt_us]',
          :'[gal_us]'
      ],

      metric_volume: [
          :ml,
          :l
      ],

      standard_mass: [
          :'[oz_av]',
          :'[lb_av]'
      ],

      metric_mass: [
          :g,
          :kg
      ]
  }
end