#!/usr/bin/env bash
# This script was generated by bashly 1.2.1 (https://bashly.dannyb.co)
# Modifying it manually is not recommended

# :wrapper.bash3_bouncer
if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then
  printf "bash version 4 or higher is required\n" >&2
  exit 1
fi

# :command.master_script

# :command.version_command
version_command() {
  echo "$version"
}

# :command.usage
dcu_usage() {
  printf "dcu - Dasharo Configuration Utility\n\n"

  printf "%s\n" "Usage:"
  printf "  dcu COMMAND\n"
  printf "  dcu [COMMAND] --help | -h\n"
  printf "  dcu --version | -v\n"
  echo
  # :command.usage_commands
  printf "%s\n" "Commands:"
  printf "  %s   Get/set MAC address in a firmware image\n" "mac     "
  printf "  %s   Edit SMBIOS data in a firmware image\n" "smbios  "
  printf "  %s   Insert custom logo boot splash into firmware image\n" "logo    "
  printf "  %s   Edit Dasharo configuration variables\n" "variable"
  echo

  # :command.long_usage
  if [[ -n $long_usage ]]; then
    printf "%s\n" "Options:"

    # :command.usage_fixed_flags
    printf "  %s\n" "--help, -h"
    printf "    Show this help\n"
    echo
    printf "  %s\n" "--version, -v"
    printf "    Show version number\n"
    echo

    # :command.usage_examples
    printf "%s\n" "Examples:"
    printf "  dcu setmac coreboot.rom 12:34:45:56:78:9A\n"
    printf "  dcu smbios coreboot.rom -u 96bcfa1a-42b4-6717-a44c-d8bbc18cbea4 -s D07229051\n"
    printf "  dcu logo coreboot.rom -l bootsplash.bmp\n"
    printf "  dcu variable coreboot.rom --get EnableWifiBt\n"
    echo

  fi
}

# :command.usage
dcu_mac_usage() {
  printf "dcu mac - Get/set MAC address in a firmware image\n\n"
  printf "Alias: m\n"
  echo

  printf "%s\n" "Usage:"
  printf "  dcu mac DASHARO_ROM_FILE [OPTIONS]\n"
  printf "  dcu mac --help | -h\n"
  echo

  # :command.long_usage
  if [[ -n $long_usage ]]; then
    printf "%s\n" "Options:"

    # :command.usage_flags
    # :flag.usage
    printf "  %s\n" "--set, -s MAC"
    printf "    Set mac address\n"
    echo

    # :command.usage_fixed_flags
    printf "  %s\n" "--help, -h"
    printf "    Show this help\n"
    echo

    # :command.usage_args
    printf "%s\n" "Arguments:"

    # :argument.usage
    printf "  %s\n" "DASHARO_ROM_FILE"
    printf "    Dasharo firmware file (e.g. coreboot.rom)\n"
    echo

    # :command.usage_examples
    printf "%s\n" "Examples:"
    printf "  dcu mac coreboot.rom --set AB:CD:EF:01:23:45\n"
    printf "  dcu mac coreboot.rom --get\n"
    echo

  fi
}

# :command.usage
dcu_smbios_usage() {
  printf "dcu smbios - Edit SMBIOS data in a firmware image\n\n"
  printf "Alias: s\n"
  echo

  printf "%s\n" "Usage:"
  printf "  dcu smbios DASHARO_ROM_FILE [OPTIONS]\n"
  printf "  dcu smbios --help | -h\n"
  echo

  # :command.long_usage
  if [[ -n $long_usage ]]; then
    printf "%s\n" "Options:"

    # :command.usage_flags
    # :flag.usage
    printf "  %s\n" "--uuid, -u UUID"
    printf "    UUID in RFC4122 format to be set in SMBIOS type 1 structure\n"
    echo

    # :flag.usage
    printf "  %s\n" "--serial-number, -s SERIAL"
    printf "    Serial number to be set in SMBIOS type 1 and type 2 structure\n"
    echo

    # :command.usage_fixed_flags
    printf "  %s\n" "--help, -h"
    printf "    Show this help\n"
    echo

    # :command.usage_args
    printf "%s\n" "Arguments:"

    # :argument.usage
    printf "  %s\n" "DASHARO_ROM_FILE"
    printf "    Dasharo firmware file (e.g. coreboot.rom)\n"
    echo

    # :command.usage_examples
    printf "%s\n" "Examples:"
    printf "  dcu smbios coreboot.rom -u 96bcfa1a-42b4-6717-a44c-d8bbc18cbea4\n"
    printf "  dcu smbios coreboot.rom -s D07229051\n"
    printf "  dcu smbios coreboot.rom -u 96bcfa1a-42b4-6717-a44c-d8bbc18cbea4 -s D07229051\n"
    echo

  fi
}

# :command.usage
dcu_logo_usage() {
  printf "dcu logo - Insert custom logo boot splash into firmware image\n\n"
  printf "Alias: l\n"
  echo

  printf "%s\n" "Usage:"
  printf "  dcu logo DASHARO_ROM_FILE [OPTIONS]\n"
  printf "  dcu logo --help | -h\n"
  echo

  # :command.long_usage
  if [[ -n $long_usage ]]; then
    printf "%s\n" "Options:"

    # :command.usage_flags
    # :flag.usage
    printf "  %s\n" "--logo, -l LOGO (required)"
    printf "    Custom logo in BMP/PNG/JPG/SVG format to be displayed on boot\n"
    echo

    # :command.usage_fixed_flags
    printf "  %s\n" "--help, -h"
    printf "    Show this help\n"
    echo

    # :command.usage_args
    printf "%s\n" "Arguments:"

    # :argument.usage
    printf "  %s\n" "DASHARO_ROM_FILE"
    printf "    Dasharo firmware file (e.g. coreboot.rom)\n"
    echo

    # :command.usage_examples
    printf "%s\n" "Examples:"
    printf "  dcu logo coreboot.rom -l bootsplash.bmp\n"
    echo

  fi
}

# :command.usage
dcu_variable_usage() {
  printf "dcu variable - Edit Dasharo configuration variables\n\n"
  printf "Alias: v\n"
  echo

  printf "%s\n" "Usage:"
  printf "  dcu variable DASHARO_ROM_FILE [OPTIONS]\n"
  printf "  dcu variable --help | -h\n"
  echo

  # :command.long_usage
  if [[ -n $long_usage ]]; then
    printf "%s\n" "Options:"

    # :command.usage_flags
    # :flag.usage
    printf "  %s\n" "--get VAR"
    printf "    Name of the variable to get\n"
    echo

    # :flag.usage
    printf "  %s\n" "--list"
    printf "    List variables in a binary\n"
    echo

    # :flag.usage
    printf "  %s\n" "--list-supported"
    printf "    List variables supported by this tool\n"
    echo

    # :flag.usage
    printf "  %s\n" "--set VAR"
    printf "    Name of the variable to set\n"
    echo

    # :flag.usage
    printf "  %s\n" "--value VAL"
    printf "    Value to set a variable to\n"
    echo

    # :command.usage_fixed_flags
    printf "  %s\n" "--help, -h"
    printf "    Show this help\n"
    echo

    # :command.usage_args
    printf "%s\n" "Arguments:"

    # :argument.usage
    printf "  %s\n" "DASHARO_ROM_FILE"
    printf "    Dasharo firmware file (e.g. coreboot.rom)\n"
    echo

    # :command.usage_examples
    printf "%s\n" "Examples:"
    printf "  dcu variable coreboot.rom --get EnableWifiBt\n"
    printf "  dcu variable coreboot.rom --set EnableWifiBt --value Disabled\n"
    echo

  fi
}

# :command.normalize_input
# :command.normalize_input_function
normalize_input() {
  local arg passthru flags
  passthru=false

  while [[ $# -gt 0 ]]; do
    arg="$1"
    if [[ $passthru == true ]]; then
      input+=("$arg")
    elif [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then
      input+=("${BASH_REMATCH[1]}")
      input+=("${BASH_REMATCH[2]}")
    elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then
      input+=("${BASH_REMATCH[1]}")
      input+=("${BASH_REMATCH[2]}")
    elif [[ $arg =~ ^-([a-zA-Z0-9][a-zA-Z0-9]+)$ ]]; then
      flags="${BASH_REMATCH[1]}"
      for ((i = 0; i < ${#flags}; i++)); do
        input+=("-${flags:i:1}")
      done
    elif [[ "$arg" == "--" ]]; then
      passthru=true
      input+=("$arg")
    else
      input+=("$arg")
    fi

    shift
  done
}

# :command.inspect_args
inspect_args() {
  if ((${#args[@]})); then
    readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
    echo args:
    for k in "${sorted_keys[@]}"; do
      echo "- \${args[$k]} = ${args[$k]}"
    done
  else
    echo args: none
  fi

  if ((${#other_args[@]})); then
    echo
    echo other_args:
    echo "- \${other_args[*]} = ${other_args[*]}"
    for i in "${!other_args[@]}"; do
      echo "- \${other_args[$i]} = ${other_args[$i]}"
    done
  fi

  if ((${#deps[@]})); then
    readarray -t sorted_keys < <(printf '%s\n' "${!deps[@]}" | sort)
    echo
    echo deps:
    for k in "${sorted_keys[@]}"; do
      echo "- \${deps[$k]} = ${deps[$k]}"
    done
  fi

  if ((${#env_var_names[@]})); then
    readarray -t sorted_names < <(printf '%s\n' "${env_var_names[@]}" | sort)
    echo
    echo "environment variables:"
    for k in "${sorted_names[@]}"; do
      echo "- \$$k = ${!k:-}"
    done
  fi
}

# :command.command_functions
# :command.function
dcu_mac_command() {
  # src/mac_command.sh
  # SPDX-FileCopyrightText: 2023 3mdeb <contact@3mdeb.com>
  #
  # SPDX-License-Identifier: Apache-2.0

  # inspect_args

  DASHARO_ROM="${args[dasharo_rom_file]}"
  MAC="${args[--set]}"
  GBE_FLASHREGION_FILENAME="flashregion_3_gbe.bin"
  GBE_FLASHREGION_PATH=$GBE_FLASHREGION_FILENAME
  set_mac() {
    local _mac="$1"
    if "${NVMTOOL}" "$GBE_FLASHREGION_PATH" copy 0; then
      echo "Copying region 0 to region 1"
    else
      echo "Failed to copy region 0 to region 1"
      if "${NVMTOOL}" "$GBE_FLASHREGION_PATH" copy 1; then
        echo "Copying region 1 to region 0"
      else
        echo "Failed to copy region 1 to region 0"
        echo "Both regions are invalid, aborting"
        cleanup
        return 23
      fi
    fi

    "${NVMTOOL}" "$GBE_FLASHREGION_PATH" setmac "${_mac}" 1> /dev/null || { cleanup; return 22; }
    "${IFDTOOL}" -i gbe:"$GBE_FLASHREGION_PATH" "${DASHARO_ROM}" 1> /dev/null || { cleanup; return 21; }
    echo "Moving ${DASHARO_ROM}.new to ${DASHARO_ROM}"
    mv "${DASHARO_ROM}.new" "${DASHARO_ROM}" -f
    echo "Success"
  }

  get_mac() {
    # dump sections
    dump=$("${NVMTOOL}" "$GBE_FLASHREGION_PATH" "dump" 2>&1 || true)
    bad=$(printf "%s" "$dump" | grep "BAD checksum" 2>&1 || true)
    dump=$(echo "$dump" | sed "/BAD checksum in part 0/d" | sed "/BAD checksum in part 1/d")
    echo "$bad"
    echo "$dump"
    echo "Success"
  }

  init() {
    if [[ ! -f "${DASHARO_ROM}" ]]; then
      echo "Error, file does not exist: ${DASHARO_ROM}"
      cleanup
      return 1
    fi
    "${IFDTOOL}" -x "${DASHARO_ROM}" &> /dev/null
    if [[ ! -f "$GBE_FLASHREGION_PATH" ]]; then
      echo "Managing the MAC address in this binary is currently not supported"
      cleanup
      return 21
    fi
  }

  cleanup() {
    rm -f flashregion*
  }
  DASHARO_ROM=$(realpath -- "$DASHARO_ROM")
  GBE_FLASHREGION_PATH=$(realpath -- "$GBE_FLASHREGION_PATH")
  echo "Using ${DASHARO_ROM}"

  init

  if [ -n "${MAC}" ]; then
    set_mac "${MAC}"
  else
    get_mac
  fi

  cleanup

}

# :command.function
dcu_smbios_command() {
  # src/smbios_command.sh
  # SPDX-FileCopyrightText: 2023 3mdeb <contact@3mdeb.com>
  #
  # SPDX-License-Identifier: Apache-2.0

  # inspect_args

  DASHARO_ROM="${args[dasharo_rom_file]}"
  SYSTEM_UUID="${args[--uuid]}"
  SERIAL_NUMBER="${args[--serial-number]}"

  set_uuid() {
    local _uuid="$1"

    if ! echo "${CB_CONFIG}" | grep -q "CONFIG_DRIVERS_GENERIC_CBFS_UUID=y"; then
      echo "Configurable UUID not supported by the coreboot image"
      exit 7
    fi

    if uuidparse "${SYSTEM_UUID}" | grep -q "invalid"; then
      echo "Invalid UUID format"
      exit 8
    fi

    echo "Setting System UUID to ${_uuid}"
    echo -n "${_uuid}" > /tmp/system_uuid
    # We do not care if this one fails. It can fail if serial_number is not
    # already, there, which is fine.
    "${CBFSTOOL}" "${DASHARO_ROM}" remove -n system_uuid -r COREBOOT > /dev/null 2> /dev/null || true
    CBFSTOOL_ERR="$(${CBFSTOOL} ${DASHARO_ROM} add -f /tmp/system_uuid -n system_uuid -t raw -r COREBOOT 2>&1)"
    rm /tmp/system_uuid

    if echo "${CBFSTOOL_ERR}" | grep -q "The image will be left unmodified"; then
      echo "An error occurred when adding setting the UUID"
      echo "cbfstool output:"
      echo "${CBFSTOOL_ERR}"
      exit 9
    fi
    echo "Success"
  }

  set_serial_number() {
    local _serial="$1"

    if ! echo "${CB_CONFIG}" | grep -q "CONFIG_DRIVERS_GENERIC_CBFS_SERIAL=y"; then
      echo "Configurable Serial Number not supported by the coreboot image"
      exit 10
    fi

    echo "Setting Serial Number to ${_serial}"
    echo -n "$_serial" > /tmp/serial_number
    # We do not care if this one fails. It can fail if serial_number is not
    # already, there, which is fine.
    "${CBFSTOOL}" "${DASHARO_ROM}" remove -n serial_number -r COREBOOT > /dev/null 2> /dev/null || true
    CBFSTOOL_ERR="$(${CBFSTOOL} ${DASHARO_ROM} add -f /tmp/serial_number -n serial_number -t raw -r COREBOOT 2>&1)"
    rm /tmp/serial_number

    if echo "${CBFSTOOL_ERR}" | grep -q "The image will be left unmodified"; then
      echo "An error occurred when adding setting the Serial Number"
      echo "cbfstool output:"
      echo "${CBFSTOOL_ERR}"
      exit 11
    fi
    echo "Success"
  }

  if ! "${CBFSTOOL}" "${DASHARO_ROM}" extract -n config -r COREBOOT -f /tmp/cb_config > /dev/null 2> /dev/null; then
    echo "Failed to extract coreboot configuration from the image"
    exit 6
  fi

  CB_CONFIG="$(cat /tmp/cb_config)"
  rm /tmp/cb_config

  echo "Will modify ${DASHARO_ROM}"
  echo ""

  if [ -n "${SYSTEM_UUID}" ]; then
    set_uuid "${SYSTEM_UUID}"
  fi

  if [ -n "${SERIAL_NUMBER}" ]; then
    set_serial_number "${SERIAL_NUMBER}"
  fi

}

# :command.function
dcu_logo_command() {
  # src/logo_command.sh
  # SPDX-FileCopyrightText: 2023 3mdeb <contact@3mdeb.com>
  #
  # SPDX-License-Identifier: Apache-2.0

  # inspect_args

  DASHARO_ROM="${args[dasharo_rom_file]}"
  LOGO_FILE="${args[--logo]}"

  if [ ! -f "${LOGO_FILE}" ]; then
    echo "Logo file not found or invalid path: ${LOGO_FILE}"
    exit 12
  fi

  if ! file "${LOGO_FILE}" | grep -qE 'PNG image|JPEG image|Scalable Vector Graphics image|PC bitmap'; then
    echo "Invalid or unsupported logo file format"
    exit 13
  fi

  if ! "${CBFSTOOL}" "${DASHARO_ROM}" layout -w | grep -q "BOOTSPLASH"; then
    echo "BOOTSPLASH region not found"
    echo "Customizable logo not supported by the ${DASHARO_ROM} image"
    exit 14
  fi

  echo "Setting ${LOGO_FILE} as custom logo"
  convert -background None ${LOGO_FILE} BMP3:/tmp/logo.bmp &> /dev/null
  # We do not care if this one fails. It can fail if serial_number is not
  # already, there, which is fine.
  "${CBFSTOOL}" "${DASHARO_ROM}" remove -n logo.bmp -r BOOTSPLASH > /dev/null 2> /dev/null || true
  CBFSTOOL_ERR="$(${CBFSTOOL} ${DASHARO_ROM} add -f /tmp/logo.bmp -r BOOTSPLASH -n logo.bmp -t raw -c lzma 2>&1)"
  rm /tmp/logo.bmp

  if echo "${CBFSTOOL_ERR}" | grep -q "too big"; then
    echo "Logo file too big to fit in the coreboot image"
    exit 15
  fi

  if echo "$CBFSTOOL_ERR" | grep -q "The image will be left unmodified"; then
    echo "An error occurred when adding the logo to coreboot image"
    exit 16
  fi

  echo "Success"

}

# :command.function
dcu_variable_command() {
  # src/variable_command.sh
  # SPDX-FileCopyrightText: 2024 3mdeb <contact@3mdeb.com>
  #
  # SPDX-License-Identifier: Apache-2.0

  # inspect_args

  DASHARO_ROM="${args[dasharo_rom_file]}"
  SMMSTORETOOL="smmstoretool"
  GET="${args[--get]}"
  VALUE="${args[--value]}"
  SET="${args[--set]}"
  LIST="${args[--list]}"
  LIST_SUPPORTED="${args[--list-supported]}"

  supported_variables=$(echo "LockBios NetworkBoot UsbDriverStack SmmBwp"\
                      "Ps2Controller BootManagerEnabled PCIeResizeableBarsEnabled"\
                      "EnableCamera EnableWifiBt SerialRedirection SerialRedirection2"\
                      "MeMode FanCurveOption CpuThrottlingThreshold")

  typeof()
  {
    # TODO: determine type programmatically
    case $1 in
      LockBios \
      |NetworkBoot \
      |UsbDriverStack \
      |UsbMassStorage \
      |SmmBwp \
      |Ps2Controller \
      |BootManagerEnabled \
      |PCIeResizeableBarsEnabled \
      |EnableCamera \
      |EnableWifiBt \
      |SerialRedirection \
      |SerialRedirection2)
        echo "enum_bool"
        ;;
      MeMode)
        echo "enum_memode"
        ;;
      FanCurveOption)
        echo "enum_fancurve"
        ;;
      CpuThrottlingThreshold)
        echo "uint8"
        ;;
      *)
        echo "unknown"
        ;;
    esac
  }

  valueof()
  {
    case `typeof $1` in
      enum_bool)
        _result="$(${SMMSTORETOOL} "${DASHARO_ROM}" get -g dasharo -n $1 -t bool)"
        error_check "Variable store was not initialized yet. You need to set some variable first via --set option." 17
        if [ "${_result}" = "false" ]; then
          echo "Disabled"
        elif [ "${_result}" = "true" ]; then
          echo "Enabled"
        else
          echo "Error!"
          exit 18
        fi
        ;;
      enum_memode)
        _result="$(${SMMSTORETOOL} "${DASHARO_ROM}" get -g dasharo -n $1 -t uint8)"
        error_check "Variable store was not initialized yet. You need to set some variable first via --set option." 17
        if [ "${_result}" = "0" ]; then
          echo "Enabled"
        elif [ "${_result}" = "1" ]; then
          echo "Disabled (Soft)"
        elif [ "${_result}" = "2" ]; then
          echo "Disabled (HAP)"
        else
          echo "Error!"
          exit 18
        fi
        ;;
      enum_fancurve)
        _result="$(${SMMSTORETOOL} "${DASHARO_ROM}" get -g dasharo -n $1 -t uint8)"
        error_check "Variable store was not initialized yet. You need to set some variable first via --set option." 17
        if [ "${_result}" = "0" ]; then
          echo "Silent"
        elif [ "${_result}" = "1" ]; then
          echo "Performance"
        else
          echo "Error!"
          exit 18
        fi
        ;;
      uint8)
        _result="$(${SMMSTORETOOL} "${DASHARO_ROM}" get -g dasharo -n $1 -t uint8)"
        error_check "Variable store was not initialized yet. You need to set some variable first via --set option." 17
        echo ${_result}
        ;;
      *)
        echo "Variable \"${1}\" is not supported by the DCU tool yet".
        exit 20
        ;;
    esac
  }

  acceptedvaluesfor()
  {
    case `typeof $1` in
      enum_bool)
        echo "Disabled / Enabled"
        ;;
      enum_memode)
        echo "Enabled / Disabled (Soft) / Disabled (HAP)"
        ;;
      enum_fancurve)
        echo "Silent / Performance"
        ;;
      uint8)
        echo "0-255 (Actual supported values may vary)"
        ;;
      *)
        ;;
    esac
  }

  get_variable()
  {
    echo "$(valueof ${GET})"
  }

  set_variable()
  {
    if [ -z "${VALUE}" ]
    then
      echo "Value to set not provided, exiting" >&2
      exit 1
    fi

    if [[ $(typeof ${SET}) == enum_* ]]
    then
      # Enums: Find the index of the value in the list of accepted values, and
      # write it to the underlying variable as uint8.
      _accepted_values="$(acceptedvaluesfor ${SET})"
      _accepted_values_split=$(echo ${_accepted_values} | sed 's/\//\n/g')
      _accepted_values_count=$(echo "${_accepted_values_split}" | wc -l)

      if [ -z "${_accepted_values}" ]; then
        echo "Variable \"${SET}\" is not supported by the DCU tool yet".
        exit 20
      fi
      i=0
      export IFS="/"
      for a in ${_accepted_values} ; do
        a=$(echo $a | awk '{$1=$1};1')
        if [ "$a" = "${VALUE}" ]; then
          break
        fi
        i=$(($i + 1))
      done
      if [ ${i} -ge ${_accepted_values_count} ]; then
        echo "Value ${VALUE} is out of range (expected one of: ${_accepted_values})"
        exit 1
      fi
      set_value=${i}
      set_type="uint8"
    elif [[ $(typeof ${SET}) == "unknown" ]]; then
      echo "Variable \"${SET}\" is not supported by the DCU tool yet".
      exit 20
    else
      # All other types: Pass the type and value directly.
      set_value=${VALUE}
      set_type=$(typeof ${SET})
    fi

    ${SMMSTORETOOL} "${DASHARO_ROM}" set -g dasharo -n ${SET} -t ${set_type} -v ${set_value}
    echo "Successfully set variable ${SET} in the variable store."
  }

  list_variables()
  {
    echo "Settings in ${DASHARO_ROM}:"
    variables=$(${SMMSTORETOOL} "${DASHARO_ROM}" list | grep "dasharo" | sed 's/.*://; s/(.*//')
    tabs 30
    echo -e "NAME\tVALUE\tACCEPTED VALUES"
    for var in $variables; do
      case `typeof $var` in
        enum_bool \
        |enum_memode \
        |enum_fancurve \
        |uint8)
          echo -e "$var\t$(valueof $var)\t$(acceptedvaluesfor $var)"
          ;;
        *)
          ;;
      esac
    done
  }

  list_supported_variables()
  {
    echo "Settings that can be modified using this tool":
    tabs 30
    echo -e "NAME\tACCEPTED VALUES"
    for var in $supported_variables; do
      echo -e "$var\t$(acceptedvaluesfor $var)"
    done
  }

  if [ -n "${GET}" ]
  then
    get_variable
  elif [ -n "${LIST}" ]
  then
    list_variables
  elif [ -n "${SET}" ]
  then
    set_variable
  elif [ -n "${LIST_SUPPORTED}" ]
  then
    list_supported_variables
  fi

}

# :command.parse_requirements
parse_requirements() {
  # :command.fixed_flags_filter
  while [[ $# -gt 0 ]]; do
    case "${1:-}" in
      --version | -v)
        version_command
        exit
        ;;

      --help | -h)
        long_usage=yes
        dcu_usage
        exit
        ;;

      *)
        break
        ;;

    esac
  done

  # :command.dependencies_filter
  if command -v cbfstool >/dev/null 2>&1; then
    deps['cbfstool']="$(command -v cbfstool | head -n1)"
  else
    printf "missing dependency: cbfstool\n" >&2
    printf "%s\n" "You can build one from source code: https://github.com/Dasharo/dcu#compiling-cbfstool or use DCU tool in container: https://github.com/Dasharo/dcu?tab=readme-ov-file#dasharo-configuration-container\n" >&2
    exit 1
  fi

  if command -v uuidparse >/dev/null 2>&1; then
    deps['uuidparse']="$(command -v uuidparse | head -n1)"
  else
    printf "missing dependency: uuidparse\n" >&2
    printf "%s\n" "Please install util-linux package" >&2
    exit 1
  fi

  if command -v convert >/dev/null 2>&1; then
    deps['convert']="$(command -v convert | head -n1)"
  else
    printf "missing dependency: convert\n" >&2
    printf "%s\n" "Please install imagemagick package" >&2
    exit 1
  fi

  if command -v smmstoretool >/dev/null 2>&1; then
    deps['smmstoretool']="$(command -v smmstoretool | head -n1)"
  else
    printf "missing dependency: smmstoretool\n" >&2
    printf "%s\n" "You can build one from source code: https://github.com/Dasharo/dcu#compiling-smmstoretool or use DCU tool in container: https://github.com/Dasharo/dcu?tab=readme-ov-file#dasharo-configuration-container\n" >&2
    exit 1
  fi

  if command -v nvm >/dev/null 2>&1; then
    deps['nvmtool']="$(command -v nvm | head -n1)"
  else
    printf "missing dependency: nvmtool\n" >&2
    printf "%s\n" "You can build one from source code: https://github.com/Dasharo/dcu#compiling-nvmtool or use DCU tool in container: https://github.com/Dasharo/dcu?tab=readme-ov-file#dasharo-configuration-container\n" >&2
    exit 1
  fi

  if command -v ifdtool >/dev/null 2>&1; then
    deps['ifdtool']="$(command -v ifdtool | head -n1)"
  else
    printf "missing dependency: ifdtool\n" >&2
    printf "%s\n" "You can build one from source code: https://github.com/Dasharo/dcu#compiling-nvmtool or use DCU tool in container: https://github.com/Dasharo/dcu?tab=readme-ov-file#dasharo-configuration-container\n" >&2
    exit 1
  fi

  # :command.command_filter
  action=${1:-}

  case $action in
    -*) ;;

    mac | m)
      action="mac"
      shift
      dcu_mac_parse_requirements "$@"
      shift $#
      ;;

    smbios | s)
      action="smbios"
      shift
      dcu_smbios_parse_requirements "$@"
      shift $#
      ;;

    logo | l)
      action="logo"
      shift
      dcu_logo_parse_requirements "$@"
      shift $#
      ;;

    variable | v)
      action="variable"
      shift
      dcu_variable_parse_requirements "$@"
      shift $#
      ;;

    # :command.command_fallback
    "")
      dcu_usage >&2
      exit 1
      ;;

    *)
      printf "invalid command: %s\n" "$action" >&2
      exit 1
      ;;

  esac

  # :command.parse_requirements_while
  while [[ $# -gt 0 ]]; do
    key="$1"
    case "$key" in

      -?*)
        printf "invalid option: %s\n" "$key" >&2
        exit 1
        ;;

      *)
        # :command.parse_requirements_case
        # :command.parse_requirements_case_simple
        printf "invalid argument: %s\n" "$key" >&2
        exit 1

        ;;

    esac
  done

}

# :command.parse_requirements
dcu_mac_parse_requirements() {
  # :command.fixed_flags_filter
  while [[ $# -gt 0 ]]; do
    case "${1:-}" in
      --help | -h)
        long_usage=yes
        dcu_mac_usage
        exit
        ;;

      *)
        break
        ;;

    esac
  done

  # :command.command_filter
  action="mac"

  # :command.parse_requirements_while
  while [[ $# -gt 0 ]]; do
    key="$1"
    case "$key" in
      # :flag.case
      --set | -s)

        # :flag.case_arg
        if [[ -n ${2+x} ]]; then
          args['--set']="$2"
          shift
          shift
        else
          printf "%s\n" "--set requires an argument: --set, -s MAC" >&2
          exit 1
        fi
        ;;

      -?*)
        printf "invalid option: %s\n" "$key" >&2
        exit 1
        ;;

      *)
        # :command.parse_requirements_case
        # :command.parse_requirements_case_simple
        # :argument.case
        if [[ -z ${args['dasharo_rom_file']+x} ]]; then
          args['dasharo_rom_file']=$1
          shift
        else
          printf "invalid argument: %s\n" "$key" >&2
          exit 1
        fi

        ;;

    esac
  done

  # :command.required_args_filter
  if [[ -z ${args['dasharo_rom_file']+x} ]]; then
    printf "missing required argument: DASHARO_ROM_FILE\nusage: dcu mac DASHARO_ROM_FILE [OPTIONS]\n" >&2

    exit 1
  fi

}

# :command.parse_requirements
dcu_smbios_parse_requirements() {
  # :command.fixed_flags_filter
  while [[ $# -gt 0 ]]; do
    case "${1:-}" in
      --help | -h)
        long_usage=yes
        dcu_smbios_usage
        exit
        ;;

      *)
        break
        ;;

    esac
  done

  # :command.command_filter
  action="smbios"

  # :command.parse_requirements_while
  while [[ $# -gt 0 ]]; do
    key="$1"
    case "$key" in
      # :flag.case
      --uuid | -u)

        # :flag.case_arg
        if [[ -n ${2+x} ]]; then
          args['--uuid']="$2"
          shift
          shift
        else
          printf "%s\n" "--uuid requires an argument: --uuid, -u UUID" >&2
          exit 1
        fi
        ;;

      # :flag.case
      --serial-number | -s)

        # :flag.case_arg
        if [[ -n ${2+x} ]]; then
          args['--serial-number']="$2"
          shift
          shift
        else
          printf "%s\n" "--serial-number requires an argument: --serial-number, -s SERIAL" >&2
          exit 1
        fi
        ;;

      -?*)
        printf "invalid option: %s\n" "$key" >&2
        exit 1
        ;;

      *)
        # :command.parse_requirements_case
        # :command.parse_requirements_case_simple
        # :argument.case
        if [[ -z ${args['dasharo_rom_file']+x} ]]; then
          args['dasharo_rom_file']=$1
          shift
        else
          printf "invalid argument: %s\n" "$key" >&2
          exit 1
        fi

        ;;

    esac
  done

  # :command.required_args_filter
  if [[ -z ${args['dasharo_rom_file']+x} ]]; then
    printf "missing required argument: DASHARO_ROM_FILE\nusage: dcu smbios DASHARO_ROM_FILE [OPTIONS]\n" >&2

    exit 1
  fi

}

# :command.parse_requirements
dcu_logo_parse_requirements() {
  # :command.fixed_flags_filter
  while [[ $# -gt 0 ]]; do
    case "${1:-}" in
      --help | -h)
        long_usage=yes
        dcu_logo_usage
        exit
        ;;

      *)
        break
        ;;

    esac
  done

  # :command.command_filter
  action="logo"

  # :command.parse_requirements_while
  while [[ $# -gt 0 ]]; do
    key="$1"
    case "$key" in
      # :flag.case
      --logo | -l)

        # :flag.case_arg
        if [[ -n ${2+x} ]]; then
          args['--logo']="$2"
          shift
          shift
        else
          printf "%s\n" "--logo requires an argument: --logo, -l LOGO" >&2
          exit 1
        fi
        ;;

      -?*)
        printf "invalid option: %s\n" "$key" >&2
        exit 1
        ;;

      *)
        # :command.parse_requirements_case
        # :command.parse_requirements_case_simple
        # :argument.case
        if [[ -z ${args['dasharo_rom_file']+x} ]]; then
          args['dasharo_rom_file']=$1
          shift
        else
          printf "invalid argument: %s\n" "$key" >&2
          exit 1
        fi

        ;;

    esac
  done

  # :command.required_args_filter
  if [[ -z ${args['dasharo_rom_file']+x} ]]; then
    printf "missing required argument: DASHARO_ROM_FILE\nusage: dcu logo DASHARO_ROM_FILE [OPTIONS]\n" >&2

    exit 1
  fi

  # :command.required_flags_filter
  if [[ -z ${args['--logo']+x} ]]; then
    printf "missing required flag: --logo, -l LOGO\n" >&2
    exit 1
  fi

}

# :command.parse_requirements
dcu_variable_parse_requirements() {
  # :command.fixed_flags_filter
  while [[ $# -gt 0 ]]; do
    case "${1:-}" in
      --help | -h)
        long_usage=yes
        dcu_variable_usage
        exit
        ;;

      *)
        break
        ;;

    esac
  done

  # :command.command_filter
  action="variable"

  # :command.parse_requirements_while
  while [[ $# -gt 0 ]]; do
    key="$1"
    case "$key" in
      # :flag.case
      --get)

        # :flag.case_arg
        if [[ -n ${2+x} ]]; then
          args['--get']="$2"
          shift
          shift
        else
          printf "%s\n" "--get requires an argument: --get VAR" >&2
          exit 1
        fi
        ;;

      # :flag.case
      --list)

        # :flag.case_no_arg
        args['--list']=1
        shift
        ;;

      # :flag.case
      --list-supported)

        # :flag.case_no_arg
        args['--list-supported']=1
        shift
        ;;

      # :flag.case
      --set)

        # :flag.case_arg
        if [[ -n ${2+x} ]]; then
          args['--set']="$2"
          shift
          shift
        else
          printf "%s\n" "--set requires an argument: --set VAR" >&2
          exit 1
        fi
        ;;

      # :flag.case
      --value)

        # :flag.case_arg
        if [[ -n ${2+x} ]]; then
          args['--value']="$2"
          shift
          shift
        else
          printf "%s\n" "--value requires an argument: --value VAL" >&2
          exit 1
        fi
        ;;

      -?*)
        printf "invalid option: %s\n" "$key" >&2
        exit 1
        ;;

      *)
        # :command.parse_requirements_case
        # :command.parse_requirements_case_simple
        # :argument.case
        if [[ -z ${args['dasharo_rom_file']+x} ]]; then
          args['dasharo_rom_file']=$1
          shift
        else
          printf "invalid argument: %s\n" "$key" >&2
          exit 1
        fi

        ;;

    esac
  done

  # :command.required_args_filter
  if [[ -z ${args['dasharo_rom_file']+x} ]]; then
    printf "missing required argument: DASHARO_ROM_FILE\nusage: dcu variable DASHARO_ROM_FILE [OPTIONS]\n" >&2

    exit 1
  fi

}

# :command.initialize
initialize() {
  version="0.2.1"
  long_usage=''
  set -e

  # src/initialize.sh
  # SPDX-FileCopyrightText: 2023 3mdeb <contact@3mdeb.com>
  #
  # SPDX-License-Identifier: Apache-2.0

  CBFSTOOL="cbfstool"
  SMMSTORETOOL="smmstoretool"
  NVMTOOL="nvm"
  IFDTOOL="ifdtool"

  error_exit() {
    _error_msg="$1"
    _exit_code="$2"
    if [ -n "$_error_msg" ]; then
      # Avoid printing empty line if no message was passed
      echo "$_error_msg"
    fi
    exit ${_exit_code}
  }

  error_check() {
    _error_code=$?
    _error_msg="$1"
    _exit_code="$2"
    [ $_error_code -ne 0 ] && error_exit "$_error_msg (error code: $_error_code)" ${_exit_code}
  }

}

# :command.run
run() {
  declare -A args=()
  declare -A deps=()
  declare -a other_args=()
  declare -a env_var_names=()
  declare -a input=()
  normalize_input "$@"
  parse_requirements "${input[@]}"

  case "$action" in
    "mac") dcu_mac_command ;;
    "smbios") dcu_smbios_command ;;
    "logo") dcu_logo_command ;;
    "variable") dcu_variable_command ;;
  esac
}

initialize
run "$@"
