#!/usr/bin/env bash

# Here the quick 'n dirty guide to adding a new OS to quickget
#
#  1. Add the new OS, all lowercase, to os_support()
#  2. Add a "pretty name" display name to pretty_name()
#  3. Create a releases_newos() generator that outputs the currently supported release versions
#  4. Add the new OS to make_vm_config()
#  5. Create a get_newos() function that does something like this:
#     function get_newos() {
#         local HASH=""
#         local ISO=""
#         local URL=""
#
#         validate_release "releases_newos"
#         ISO="newos-${RELEASE}-amd64.iso"
#         URL="https://www.newos.org/download/${ISO}"
#         web_get "${URL}" "${VM_PATH}"
#         web_get "${URL}/SHA256SUMS" "${VM_PATH}"
#         HASH=$(cat "${VM_PATH}/SHA256SUMS" | cut -d' ' -f1)
#         check_hash "${VM_PATH}/${ISO}" "${HASH}" sha256sum
#         make_vm_config "${ISO}"
#     }
#  6. Add new OS to the argument parser at the bottom of the script

function pretty_name() {
  local SIMPLE_NAME=""
  local PRETTY_NAME=""
  SIMPLE_NAME="${1}"
  case ${SIMPLE_NAME} in
    elementary)         PRETTY_NAME="elementary OS";;
    freebsd)            PRETTY_NAME="FreeBSD";;
    linuxmint-cinnamon) PRETTY_NAME="Linux Mint Cinnamon";;
    linuxmint-mate)     PRETTY_NAME="Linux Mint MATE";;
    linuxmint-xfce)     PRETTY_NAME="Linux Mint XFCE";;
    macos)              PRETTY_NAME="macOS";;
    opensuse)           PRETTY_NAME="openSUSE";;
    popos)              PRETTY_NAME="Pop!_OS";;
    ubuntu-budgie)      PRETTY_NAME="Ubuntu Budgie";;
    ubuntu-kylin)       PRETTY_NAME="Ubuntu Kylin";;
    ubuntu-mate)        PRETTY_NAME="Ubuntu MATE";;
    ubuntu-studio)      PRETTY_NAME="Ubuntu Studio";;
    *)                  PRETTY_NAME="${SIMPLE_NAME^}";;
  esac
  echo "${PRETTY_NAME}"
}

function validate_release() {
  local DISPLAY_NAME=""
  local RELEASE_GENERATOR="${1}"
  local RELEASES=""

  DISPLAY_NAME="$(pretty_name "${OS}")"
  RELEASES=$(${RELEASE_GENERATOR})
  if [[ "${RELEASES}" != *"${RELEASE}"* ]]; then
      echo "ERROR! ${DISPLAY_NAME} ${RELEASE} is not a supported release."
      echo "${RELEASES}"
      exit 1
  fi
}

function list_all() {
  local DISPLAY_NAME
  local FUNC
  local LANG
  local OS
  local RELEASE
  echo "Display Name,OS,Release,Language"
  for OS in $(os_support); do
    DISPLAY_NAME="$(pretty_name "${OS}")"
    if [[ "${OS}" == *"ubuntu"* ]]; then
      FUNC="ubuntu"
    elif [[ "${OS}" == *"linuxmint"* ]]; then
      FUNC="linuxmint"
    else
      FUNC="${OS}"
    fi

    for RELEASE in $("releases_${FUNC}"); do
      if [ "${OS}" == "windows" ]; then
        for LANG in "${LANGS[@]}"; do
          echo "${DISPLAY_NAME},${OS},${RELEASE},${LANG}",
        done
      else
        echo "${DISPLAY_NAME},${OS},${RELEASE},,"
      fi
    done
  done
  exit 0
}

function os_support() {
    echo elementary \
    freebsd \
    fedora \
    kubuntu \
    linuxmint-cinnamon \
    linuxmint-mate \
    linuxmint-xfce \
    lubuntu \
    macos \
    opensuse \
    popos \
    ubuntu \
    ubuntu-budgie \
    ubuntu-kylin \
    ubuntu-mate \
    ubuntu-studio \
    windows \
    xubuntu
}

function releases_elementary() {
    echo 6.0
}

function releases_freebsd(){
    echo 12.2 \
    13.0
}

function releases_fedora(){
    echo 33 \
    34 \
    35_beta
}

function releases_linuxmint(){
    echo 20.2
}

function releases_opensuse(){
    echo 15.0 \
    15.1 \
    15.2 \
    15.3 \
    microos \
    tumbleweed
}

function releases_macos() {
    echo high-sierra \
    mojave \
    catalina \
    big-sur
}

function releases_popos() {
    echo 20.04 \
    21.04
}

function releases_ubuntu() {
    echo bionic \
    focal \
    hirsute \
    impish \
    devel
}

function languages_windows() {
    LANGS=(Arabic
    "Brazilian Portuguese"
    Bulgarian
    "Chinese (Simplified)"
    "Chinese (Traditional)"
    Croatian
    Czech
    Danish
    Dutch
    English
    "English International"
    Estonian
    Finnish
    French
    "French Canadian"
    German
    Greek
    Hebrew
    Hungarian
    Italian
    Japanese
    Korean
    Latvian
    Lithuanian
    Norwegian
    Polish
    Portuguese
    Romanian
    Russian
    "Serbian Latin"
    Slovak
    Slovenian
    Spanish
    "Spanish (Mexico)"
    Swedish
    Thai
    Turkish
    Ukrainian)
}


function releases_windows() {
    echo 8 \
    10 \
    11
}

function unattended_windows() {
    cat << 'EOF' > "${1}"
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend"
  xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <!--
       For documentation on components:
       http://technet.microsoft.com/en-us/library/ff699038.aspx
  -->

  <settings pass="generalize">
    <!--
         The PersistAllDeviceInstalls setting indicates whether all plug and
         play devices on the destination computer remain installed during the
         generalize configuration pass.
    -->
    <component name="Microsoft-Windows-PnPSysprep"
      processorArchitecture="amd64"
      publicKeyToken="31bf3856ad364e35"
      language="neutral"
      versionScope="nonSxS">
      <PersistAllDeviceInstalls>true</PersistAllDeviceInstalls>
    </component>
  </settings>

  <settings pass="windowsPE">
    <component name="Microsoft-Windows-Setup" processorArchitecture="amd64"
      publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
      <DiskConfiguration>
        <Disk wcm:action="add">
          <DiskID>0</DiskID>
          <WillWipeDisk>true</WillWipeDisk>
          <CreatePartitions>
            <CreatePartition wcm:action="add">
              <Order>1</Order>
              <Type>EFI</Type>
              <Size>100</Size>
            </CreatePartition>
            <CreatePartition wcm:action="add">
              <Order>2</Order>
              <Type>MSR</Type>
              <Size>512</Size>
            </CreatePartition>
            <CreatePartition wcm:action="add">
              <Order>3</Order>
              <Type>Primary</Type>
              <Extend>true</Extend>
            </CreatePartition>
          </CreatePartitions>
          <ModifyPartitions>
            <ModifyPartition wcm:action="add">
              <Order>1</Order>
              <PartitionID>1</PartitionID>
              <Label>System</Label>
              <Format>FAT32</Format>
            </ModifyPartition>
            <ModifyPartition wcm:action="add">
              <Order>2</Order>
              <PartitionID>3</PartitionID>
              <Label>Windows</Label>
              <Letter>C</Letter>
              <Format>NTFS</Format>
            </ModifyPartition>
          </ModifyPartitions>
        </Disk>
        <WillShowUI>OnError</WillShowUI>
      </DiskConfiguration>
      <ImageInstall>
        <OSImage>
          <WillShowUI>OnError</WillShowUI>
          <InstallTo>
            <DiskID>0</DiskID>
            <PartitionID>3</PartitionID>
          </InstallTo>
          </OSImage>
      </ImageInstall>
      <UserData>
        <AcceptEula>true</AcceptEula>
        <ProductKey>
          <key>VK7JG-NPHTM-C97JM-9MPGT-3V66T</key>
          <WillShowUI>Never</WillShowUI>
        </ProductKey>
      </UserData>
      <DynamicUpdate>
        <Enable>true</Enable>
        <WillShowUI>Never</WillShowUI>
      </DynamicUpdate>
    </component>

    <component name="Microsoft-Windows-PnpCustomizationsWinPE"
      publicKeyToken="31bf3856ad364e35" language="neutral"
      versionScope="nonSxS" processorArchitecture="amd64">

      <!--
           This makes the VirtIO drivers available to Windows, assuming that
           the VirtIO driver disk
           (https://github.com/virtio-win/virtio-win-pkg-scripts/blob/master/README.md)
           is available as drive E:
      -->
      <DriverPaths>
        <PathAndCredentials wcm:action="add" wcm:keyValue="1">
          <Path>E:\qemufwcfg\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="2">
          <Path>E:\vioinput\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="3">
          <Path>E:\vioscsi\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="4">
          <Path>E:\viostor\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="5">
          <Path>E:\vioserial\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="6">
          <Path>E:\qxldod\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="7">
          <Path>E:\amd64\w10</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="8">
          <Path>E:\viogpudo\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="9">
          <Path>E:\viorng\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="10">
          <Path>E:\NetKVM\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="11">
          <Path>E:\viofs\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="12">
          <Path>E:\Balloon\w10\amd64</Path>
        </PathAndCredentials>
      </DriverPaths>
    </component>
  </settings>

  <settings pass="specialize">
    <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64"
      publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
      <ComputerName>*</ComputerName>
      <OEMInformation>
        <Manufacturer>Wimpys World</Manufacturer>
        <Model>Quickemu</Model>
        <SupportHours>24/7</SupportHours>
        <SupportPhone></SupportPhone>
        <SupportProvider>Wimpys World</SupportProvider>
        <SupportURL>https://github.com/wimpysworld/quickemu/issues</SupportURL>
      </OEMInformation>
      <OEMName>Wimpys World</OEMName>
    </component>
  </settings>

  <settings pass="oobeSystem">
    <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64"
      publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
      <OOBE>
        <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
        <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
      </OOBE>
      <FirstLogonCommands>
        <SynchronousCommand wcm:action="add">
          <CommandLine>msiexec /i E:\guest-agent\qemu-ga-x86_64.msi /quiet /passive /qn</CommandLine>
          <Description>Install Virtio Guest Agent</Description>
          <Order>1</Order>
        </SynchronousCommand>
        <SynchronousCommand wcm:action="add">
          <CommandLine>msiexec /i F:\spice-webdavd-x64-latest.msi /quiet /passive /qn</CommandLine>
          <Description>Install spice-webdavd file sharing agent</Description>
          <Order>2</Order>
        </SynchronousCommand>
        <SynchronousCommand wcm:action="add">
          <CommandLine>msiexec /i F:\UsbDk_1.0.22_x64.msi /quiet /passive /qn</CommandLine>
          <Description>Install usbdk USB sharing agent</Description>
          <Order>3</Order>
        </SynchronousCommand>
        <SynchronousCommand wcm:action="add">
          <CommandLine>msiexec /i F:\spice-vdagent-x64-0.10.0.msi /quiet /passive /qn</CommandLine>
          <Description>Install spice-vdagent SPICE agent</Description>
          <Order>4</Order>
        </SynchronousCommand>
      </FirstLogonCommands>
    </component>
  </settings>
</unattend>
EOF
}

function check_hash() {
    local iso=""
    local hash=""
    local hash_algo=""
    iso="${1}"
    hash="${2}"
    hash_algo="${3}"

    echo -n "Checking ${iso} with ${hash_algo}... "
    if ! echo "${hash} ${iso}" | ${hash_algo} --check --status; then
        echo "ERROR!"
        echo "${iso} doesn't match ${hash}. Try running 'quickget' again."
        exit 1
    else
        echo "Good!"
    fi
}

function web_get() {
    local DIR="${2}"
    local FILE=""
    local URL="${1}"
    if [ -n "${3}" ]; then
        FILE="${3}"
    else
        FILE="${URL##*/}"
    fi

    if ! mkdir -p "${DIR}" 2>/dev/null; then
      echo "ERROR! Unable to create directory ${DIR}"
      exit 1
    fi

    if ! wget --quiet --continue --show-progress --progress=bar:force:noscroll "${URL}" -O "${DIR}/${FILE}"; then
        echo "ERROR! Failed to download ${URL}. Try running 'quickget' again."
        exit 1
    fi
}

function zsync_get() {
    local DIR="${2}"
    local FILE=""
    local OUT=""
    local URL="${1}"
    FILE="${URL##*/}"
    if [ -n "${3}" ]; then
        OUT="${3}"
    else
        OUT="${FILE}"
    fi

    if ! mkdir -p "${DIR}" 2>/dev/null; then
      echo "ERROR! Unable to create directory ${DIR}"
      exit 1
    fi

    if ! zsync "${URL}.zsync" -i "${DIR}/${OUT}" -o "${DIR}/${OUT}" 2>/dev/null; then
        echo "ERROR! Failed to download ${URL}.zsync"
        exit 1
    fi

    if [ -e "${DIR}/${FILE}.zs-old" ]; then
        rm -v "${DIR}/${FILE}.zs-old"
    fi
}

function start_vm_info() {
    echo
    echo "To start your ${OS} ${RELEASE} virtual machine run:"
    echo "    quickemu --vm ${OS}-${RELEASE}.conf"
    echo
}

function make_vm_config() {
    local IMAGE_FILE=""
    local ISO_FILE=""
    local IMAGE_TYPE=""
    local GUEST=""
    IMAGE_FILE="${1}"
    ISO_FILE="${2}"
    if [ "${OS}" == "elementary" ]; then
        GUEST="linux"
        IMAGE_TYPE="iso"
    elif [ "${OS}" == "freebsd" ]; then
        GUEST="freebsd"
        IMAGE_TYPE="iso"
    elif [ "${OS}" == "fedora" ]; then
        GUEST="linux"
        IMAGE_TYPE="iso"
    elif [[ "${OS}" == *"linuxmint"* ]]; then
        GUEST="linux"
        IMAGE_TYPE="iso"
    elif [ "${OS}" == "opensuse" ]; then
        GUEST="linux"
        IMAGE_TYPE="iso"
    elif [ "${OS}" == "popos" ]; then
        GUEST="linux"
        IMAGE_TYPE="iso"
    elif [[ "${OS}" == *"ubuntu"* ]]; then
        GUEST="linux"
        IMAGE_TYPE="iso"
    elif [ "${OS}" == "macos" ]; then
        GUEST="macos"
        IMAGE_TYPE="img"
    elif [ "${OS}" == "windows" ]; then
        GUEST="windows"
        IMAGE_TYPE="iso"
    fi

    if [ ! -e "${OS}-${RELEASE}.conf" ]; then
        echo "Making VM configuration for ${OS}-${RELEASE}..."
        cat << EOF > "${OS}-${RELEASE}.conf"
guest_os="${GUEST}"
disk_img="${VM_PATH}/disk.qcow2"
${IMAGE_TYPE}="${VM_PATH}/${IMAGE_FILE}"
EOF
        if [ -n "${ISO_FILE}" ]; then
            echo "fixed_iso=\"${VM_PATH}/${ISO_FILE}\"" >> "${OS}-${RELEASE}.conf"
        fi

        if [ "${OS}" == "macos" ]; then
            echo "macos_release=\"${RELEASE}\"" >> "${OS}-${RELEASE}.conf"
        fi

        # Enable TPM for Windows 11
        if [ "${OS}" == "windows" ] && [ "${RELEASE}" -ge 11 ]; then
            echo "tpm=\"on\"" >> "${OS}-${RELEASE}.conf"
        fi
    fi
    start_vm_info
}

function get_elementary() {
    local ISO=""
    local URL=""

    validate_release "releases_elementary"
    ISO="elementaryos-${RELEASE}-stable.20211005.iso"
    URL="https://ams3.dl.elementary.io/download/MTYzNDU5MDA5NA==/${ISO}"
    web_get "${URL}" "${VM_PATH}"
    make_vm_config "${ISO}"
}

function get_freebsd() {
    local ISO=""
    local URL=""

    validate_release "releases_freebsd"
    ISO="FreeBSD-${RELEASE}-RELEASE-amd64-dvd1.iso"
    URL="https://download.freebsd.org/ftp/releases/amd64/amd64/ISO-IMAGES/${RELEASE}/${ISO}"
    web_get "${URL}" "${VM_PATH}"
    make_vm_config "${ISO}"
}

function get_fedora() {
    local FEDORA_RELEASE=""
    local FEDORA_VERSIONS=""
    local HASH=""
    local ISO=""
    local URL=""
    local VERSION_NUM=""

    validate_release "releases_fedora"

    FEDORA_VERSIONS=$(wget -q -O- "https://getfedora.org/releases.json" | jq '.[] | select((.variant=="Workstation" or .variant=="Spins") and .arch=="x86_64")')
    if [[ "${RELEASE}" == *"beta"* ]]; then
        VERSION_NUM=${RELEASE%"_beta"}
        FEDORA_RELEASE=$(echo "${FEDORA_VERSIONS}" | jq -c '. | select(.version | contains("Beta"))' | jq '. | select(.variant=="Workstation")')
        ISO="Fedora-Workstation-Live-x86_64-${VERSION_NUM}_Beta-1.2.iso"
    else
        FEDORA_RELEASE=$(echo "${FEDORA_VERSIONS}" | jq '. | select(.variant=="Workstation" and .version=="'${RELEASE}'")')
        ISO="Fedora-Workstation-Live-x86_64-${RELEASE}-1.2.iso"
    fi

    URL=$(echo "${FEDORA_RELEASE}" | jq -r '.link')
    HASH=$(echo "${FEDORA_RELEASE}" | jq -r '.sha256')
    web_get "${URL}" "${VM_PATH}"
    check_hash "${VM_PATH}/${ISO}" "${HASH}" sha256sum
    make_vm_config "${ISO}"
}

function get_linuxmint() {
    local FLAVOR=""
    local ISO=""
    local URL=""

    validate_release "releases_linuxmint"
    FLAVOR=$(echo "${OS}" | cut -d'-' -f2)
    ISO="linuxmint-${RELEASE}-${FLAVOR}-64bit.iso"
    URL="https://mirrors.edge.kernel.org/linuxmint/stable/${RELEASE}/${ISO}"
    web_get "${URL}" "${VM_PATH}"
    make_vm_config "${ISO}"
}

function get_opensuse() {
    local ISO=""
    local RELEASES=""
    local URL=""

    validate_release "releases_opensuse"
    if [ "${RELEASE}" == "tumbleweed" ]; then
        ISO="openSUSE-Tumbleweed-DVD-x86_64-Current.iso"
        URL="https://download.opensuse.org/tumbleweed/iso/${ISO}"
    elif [ "${RELEASE}" == "microos" ]; then
        ISO="openSUSE-MicroOS-DVD-x86_64-Current.iso"
        URL="https://download.opensuse.org/tumbleweed/iso/${ISO}"
    else
        ISO="openSUSE-Leap-${RELEASE}-DVD-x86_64.iso"
        URL="https://download.opensuse.org/distribution/leap/${RELEASE}/iso/${ISO}"
    fi
    web_get "${URL}" "${VM_PATH}"
    make_vm_config "${ISO}"
}

function get_macos() {
    local CWD=""
    local MACRECOVERY=""

    case ${RELEASE} in
        high-sierra)
            BOARD_ID="Mac-7BA5B2D9E42DDD94"
            MLB="00000000000J80300";;
        mojave)
            BOARD_ID="Mac-7BA5B2DFE22DDD8C"
            MLB="00000000000KXPG00";;
        catalina)
            BOARD_ID="Mac-CFF7D910A743CAAF"
            MLB="00000000000PHCD00";;
        big-sur)
            BOARD_ID="Mac-E43C1C25D4880AD6"
            MLB="00000000000000000";;
        *) echo "ERROR! Unknown release: ${RELEASE}"
           releases_macos
           exit 1;;
    esac

    # Use a bundled macrecovery if possible
    CWD="$(dirname ${0})"
    if [ -x "${CWD}/macrecovery" ]; then
        MACRECOVERY="${CWD}/macrecovery"
    elif [ -x /usr/bin/macrecovery ]; then
        MACRECOVERY="/usr/bin/macrecovery"
    else
        web_get "https://raw.githubusercontent.com/acidanthera/OpenCorePkg/master/Utilities/macrecovery/macrecovery.py" "${HOME}/.quickemu"
        MACRECOVERY="python3 ${HOME}/.quickemu/macrecovery.py"
        sed -i 's/\<env python\>/env python3/g' "${MACRECOVERY}"
    fi

    if [ -z "${MACRECOVERY}" ]; then
        echo "ERROR! Can not find a usable macrecovery.py."
        exit 1
    fi

    # Get firmware
    web_get "https://github.com/kholia/OSX-KVM/raw/master/OpenCore-Catalina/OpenCore.qcow2" "${VM_PATH}"
    web_get "https://github.com/kholia/OSX-KVM/raw/master/OVMF_CODE.fd" "${VM_PATH}"
    if [ ! -e "${VM_PATH}/OVMF_VARS-1024x768.fd" ]; then
        web_get "https://github.com/kholia/OSX-KVM/raw/master/OVMF_VARS-1024x768.fd" "${VM_PATH}"
    fi

    if [ ! -e "${VM_PATH}/RecoveryImage.chunklist" ]; then
        echo "Downloading ${RELEASE}..."
        ${MACRECOVERY} \
            --board-id "${BOARD_ID}" \
            --mlb "${MLB}" \
            --basename RecoveryImage \
            --outdir "${VM_PATH}" \
            download
    fi

    if [ -e "${VM_PATH}/RecoveryImage.dmg" ] && [ ! -e "${VM_PATH}/RecoveryImage.img" ]; then
        echo "Converting RecoveryImage..."
        qemu-img convert "${VM_PATH}/RecoveryImage.dmg" -O raw "${VM_PATH}/RecoveryImage.img"
    fi

    make_vm_config RecoveryImage.img
}

function get_popos() {
    local ISO=""
    local URL=""

    validate_release "releases_popos"
    ISO="pop-os_${RELEASE}_amd64_intel_9.iso"
    URL="https://pop-iso.sfo2.cdn.digitaloceanspaces.com/${RELEASE}/amd64/intel/9/${ISO}"
    web_get "${URL}" "${VM_PATH}"
    make_vm_config "${ISO}"
}

function get_ubuntu() {
    local DEVEL="daily-live"
    local ISO=""
    local HASH=""
    local PROJECT=""
    local URL=""

    case ${OS} in
      kubuntu|lubuntu|ubuntu|ubuntu-budgie|ubuntu-mate|xubuntu)
        PROJECT="${OS}";;
      ubuntu-kylin)
        PROJECT="ubuntukylin";;
      ubuntu-studio)
        PROJECT="ubuntustudio"
        DEVEL="dvd";;
      *) echo "ERROR! ${OS} is not a recognised Ubuntu flavour."
         exit 1;;
    esac

    validate_release "releases_ubuntu"
    if [ "${RELEASE}" == "devel" ]; then
        URL="http://cdimage.ubuntu.com/${PROJECT}/${DEVEL}/current"
    elif [ "${PROJECT}" == "ubuntu" ]; then
        URL="http://releases.ubuntu.com/${RELEASE}"
    else
        URL="http://cdimage.ubuntu.com/${PROJECT}/releases/${RELEASE}/release"
    fi

    web_get "${URL}/SHA256SUMS" "${VM_PATH}"
    ISO=$(grep 'desktop\|dvd' "${VM_PATH}/SHA256SUMS" | grep amd64 | cut -d' ' -f2 | sed 's|*||g')
    HASH=$(cat "${VM_PATH}/SHA256SUMS" | cut -d' ' -f1)
    if [ "${RELEASE}" == "devel" ]; then
        zsync_get "${URL}/${ISO}" "${VM_PATH}" "${OS}-${RELEASE}.iso"
        make_vm_config "${OS}-${RELEASE}.iso"
    else
        web_get "${URL}/${ISO}" "${VM_PATH}"
        check_hash "${VM_PATH}/${ISO}" "${HASH}" sha256sum
        make_vm_config "${ISO}"
    fi
}

# Adapted from https://gist.github.com/hongkongkiwi/15a5bf16437315df256c118c163607cb
function get_windows() {
    local ARCH="x64"
    local LANG_CODE="en"
    local LATEST_WINDOWS_VERSION=""
    local WINDOWS_NAME=""
    local VERSION_ID=""
    local EDITION_ID=""
    local LANGUAGE_ID=""
    local FILE_NAME=""
    local ARCH_ID=""
    local DOWNLOAD_INFO=""
    local DOWNLOAD_ID=""
    local DOWNLOAD_URL=""

    validate_release "releases_windows"

    echo "Getting Windows ${RELEASE} URL..."
    WINDOWS_VERSIONS=$(wget -q -O- "https://tb.rg-adguard.net/php/get_version.php?type_id=1" | jq '.versions | sort_by(-(.version_id | tonumber))')
    LATEST_WINDOWS_VERSION=$(echo "${WINDOWS_VERSIONS}" | jq -c 'map(select(.name | contains("Windows '${RELEASE}'")))[0]')

    WINDOWS_NAME=$(echo "${LATEST_WINDOWS_VERSION}" | jq -r .name)
    VERSION_ID=$(echo "${LATEST_WINDOWS_VERSION}" | jq -r .version_id)

    case ${RELEASE} in
        8) EDITION_ID=$(wget -q -O- "https://tb.rg-adguard.net/php/get_edition.php?version_id=${VERSION_ID}&lang=name_${LANG_CODE}" | jq -r '.editions[] | select(.name_'${LANG_CODE}'=="Windows 8.1 Pro + Core").edition_id');;
        10|11) EDITION_ID=$(wget -q -O- "https://tb.rg-adguard.net/php/get_edition.php?version_id=${VERSION_ID}&lang=name_${LANG_CODE}" | jq -r '.editions[] | select(.name_'${LANG_CODE}'=="Windows '${RELEASE}'").edition_id');;
    esac

    LANGUAGE_ID=$(wget -q -O- "https://tb.rg-adguard.net/php/get_language.php?edition_id=${EDITION_ID}&lang=name_${LANG_CODE}" | jq -r '.languages[] | select(.name_'${LANG_CODE}'=="'"${LANG_NAME}"'").language_id')
    ARCH_INFO=$(wget -q -O- "https://tb.rg-adguard.net/php/get_arch.php?language_id=${LANGUAGE_ID}")
    FILE_NAME=$(echo "${ARCH_INFO}" | jq -r '.archs[] | select(.name | contains("'${ARCH}'")).name')
    ARCH_ID=$(echo "${ARCH_INFO}" | jq -r '.archs[] | select(.name | contains("'${ARCH}'")).arch_id')
    DOWNLOAD_INFO=$(wget -q -O- "https://tb.rg-adguard.net/dl.php?fileName=${ARCH_ID}&lang=en")
    DOWNLOAD_SHA1=$(echo "${DOWNLOAD_INFO}" | sed -e 's/<[^>]*>//g' | grep -o -P '(?<=SHA1: ).*(?= expire)' | sed 's/Link//')
    DOWNLOAD_ID=$(echo "${DOWNLOAD_INFO}" | grep -oP '(?<=https:\/\/tb\.rg-adguard\.net/dl\.php\?go=)[0-9a-z]+')
    DOWNLOAD_URL="https://tb.rg-adguard.net/dl.php?go=${DOWNLOAD_ID}"

    echo "Downloading ${WINDOWS_NAME}..."
    web_get "${DOWNLOAD_URL}" "${VM_PATH}" "${FILE_NAME}"

    # Windows 10 doesn't include a SHA1, so only check the integrity if the SHA1 is available.
    if [ -n "${DOWNLOAD_SHA1}" ]; then
      check_hash "${VM_PATH}/${FILE_NAME}" "${DOWNLOAD_SHA1}" sha1sum
    fi

    web_get "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso" "${VM_PATH}"

    rm -f "${VM_PATH}/unattended.iso"
    case ${RELEASE} in
        10|11)
            echo "Making unattended.iso"
            mkdir -p "${VM_PATH}/unattended" 2>/dev/null
            web_get https://www.spice-space.org/download/windows/spice-webdavd/spice-webdavd-x64-latest.msi "${VM_PATH}/unattended"
            web_get https://www.spice-space.org/download/windows/vdagent/vdagent-win-0.10.0/spice-vdagent-x64-0.10.0.msi "${VM_PATH}/unattended"
            web_get https://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.22_x64.msi "${VM_PATH}/unattended"
            unattended_windows "${VM_PATH}/unattended/autounattend.xml"
            mkisofs -quiet -l -o "${VM_PATH}/unattended.iso" "${VM_PATH}/unattended/"
            ;;
    esac
    make_vm_config "${FILE_NAME}" "virtio-win.iso"
}

LANGS=()
languages_windows

if [ -n "${1}" ]; then
    OS="${1,,}"
    if [ "${OS}" == "list" ]; then
        list_all
    fi
else
    echo "ERROR! You must specify an operating system:"
    os_support
    exit 1
fi

if [ -n "${2}" ]; then
    RELEASE="${2,,}"
    VM_PATH="${OS}-${RELEASE}"

    if [ "${OS}" == "elementary" ]; then
        get_elementary
    elif [ "${OS}" == "macos" ]; then
        get_macos
    elif [ "${OS}" == "freebsd" ]; then
        get_freebsd
    elif [ "${OS}" == "fedora" ]; then
        get_fedora
    elif [[ "${OS}" == *"linuxmint"* ]]; then
        get_linuxmint
    elif [ "${OS}" == "opensuse" ]; then
        get_opensuse
    elif [ "${OS}" == "popos" ]; then
        get_popos
    elif [[ "${OS}" == *"ubuntu"* ]]; then
        get_ubuntu
    elif [ "${OS}" == "windows" ]; then
        if [ -n "${3}" ]; then
            LANG_NAME="${3}"
            if [[ ! ${LANGS[*]} =~ ${LANG_NAME} ]]; then
                echo "ERROR! ${LANG_NAME} is not a supported language:"
                for LANG in "${LANGS[@]}"; do
                  echo "${LANG}"
                done
                exit 1
            fi
        else
            LANG_NAME="English International"
        fi
        get_windows "${LANG_NAME}"
    else
        echo "ERROR! ${OS} is unknown:"
        os_support
        exit 1
    fi
else
    echo "ERROR! You must specify a release for ${OS}:"
    if [ "${OS}" == "elementary" ]; then
        releases_elementary
    elif [ "${OS}" == "freebsd" ]; then
        releases_freebsd
    elif [ "${OS}" == "fedora" ]; then
        releases_fedora
    elif [[ "${OS}" == *"linuxmint"* ]]; then
        releases_linuxmint
    elif [ "${OS}" == "opensuse" ]; then
        releases_opensuse
    elif [ "${OS}" == "macos" ]; then
        releases_macos
    elif [ "${OS}" == "popos" ]; then
        releases_popos
    elif [[ "${OS}" == *"ubuntu"* ]]; then
        releases_ubuntu
    elif [ "${OS}" == "windows" ]; then
        releases_windows
    fi
    exit 1
fi