#!/bin/sh

cmake=cmake

main() {
    cd "$(dirname $0)"

    while [ $# -gt 0 ]; do
        case "$1" in
            -h|--help|--usage)
                usage
                quit 0
                ;;
            *)
                break
                ;;
        esac
    done

    if [ $# -gt 1 ]; then
        usage
        quit 1
    fi

    target=$1

    mktmp

    case "$(uname -s)" in
        Linux)
            linux_installdeps
            ;;
        Darwin)
            osx_installdeps
            ;;
        MSYS*)
            error 'You must run this program from a MINGW 32 bit or 64 bit shell, not the MSYS shell'
            ;;
        MINGW*)
            msys2_installdeps
            ;;
        *)
            error "Don't know how to install deps on your OS"
            ;;
    esac

    quit 0
}

mktmp() {
    tmp="/tmp/installdeps_$$"
    mkdir "$tmp" || quit 1
    chmod 700 "$tmp" 2>/dev/null
    trap "quit 1" PIPE HUP INT QUIT ILL TRAP KILL BUS TERM
}

quit() {
    [ -n "$tmp" ] && rm -rf "$tmp" 2>/dev/null
    exit ${1:-0}
}

usage() {
    cat <<'EOF'
Usage: [32m./installdeps [1;35m[TARGET][0m
Try to install the dependencies needed for this project appropriately on the
host OS.

This program may require [1;35msudo[0m.

A cross-compile target may be specified as the only parameter, of either
[1;35mwin32[0m, [1;35mMinGW-w64-i686[0m or [1;35mMinGW-w64-x86_64[0m.
[1;35mwin32[0m is an alias for [1;35mMinGW-w64-i686[0m.
This is only supported on Debian/Ubuntu, Arch Linux and MSYS2.

On MSYS2 dependencies are installed for 32 or 64 bit native Windows targets
based on which shell you started (the value of $MSYSTEM) unless you specify one
or the other. MSYS2 POSIX layer builds are not supported.

  [1m-h, --help, --usage[0m                Show this help screen and exit.

Examples:
  [32m./installdeps[0m                        # install dependencies for a host build
  [32m./installdeps [1;35mwin32[0m                  # cross-compile for 32 bit windows (Debian/Ubuntu, Arch Linux or MSYS2)
  [32m./installdeps [1;35mMinGW-w64-i686[0m         # likewise
  [32m./installdeps [1;35mMinGW-w64-x86_64[0m       # cross-compile for 64 bit windows (Debian/Ubuntu, Arch Linux or MSYS2)
EOF
}

error() {
    printf '\n[31mERROR[0m: %s.\n\n' "$1" >&2
    [ -z "$2" ] && quit 1
}

warning() {
    [ -z "$1" ] && return 0
    printf '\n[35mWARNING[0m: %s.\n\n' "$1" >&2
}


info_msg() {
    [ -z "$1" ] && return 0
    printf '\n[32mINFO[0m: %s.\n\n' "$1" >&2
}

installing() {
    echo '[32mInstalling deps....[0m'
    echo
}

check() {
    "$@"
    if [ $? -ne 0 ]; then
        error 'command failed' NOQUIT
        echo 'The failing command was:'
        echo "$@"
        quit 1
    fi
}

countdown() {
    secs=$1
    echo
    while [ "$secs" -ne 0 ]; do
        printf '%s\r' "Starting in $secs seconds..."
        sleep 1
        secs=$((secs-1))
    done
    printf '\n\n'
}

linux_installdeps() {
    # detect host architecture
    case "$(uname -a)" in
        *x86_64*)
            amd64=1
            ;;
        *i686*)
            i686=1
            ;;
    esac

    if [ -f /etc/debian_version ]; then
        debian_installdeps
    elif [ -f /etc/fedora-release ]; then
        fedora_installdeps
    elif [ -f /etc/arch-release ]; then
        archlinux_installdeps
    else
        error "Don't know how to install deps on your version of Linux"
    fi
}

check_cross() {
    if [ -z "$target" ]; then
        if [ -n "$msys2" ]; then
            case "$MSYSTEM" in
                MINGW32)
                    target='mingw-w64-i686'
                    ;;
                MINGW64)
                    target='mingw-w64-x86_64'
                    ;;
                *)
                    error 'unknown value for $MSYSTEM: '"$MSYSTEM"' '
                    ;;
            esac
        else
            return
        fi
    fi

    if [ -z "$arch_linux" -a -z "$msys2" -a -z "$debian" -a -z "$fedora" ]; then
        error 'cross compiling targets are only supported on Debian/Ubuntu, Fedora, Arch Linux and MSYS2 at the moment'
    fi

    target=$(echo "$target" | tr 'A-Z' 'a-z')

    case "$target" in
        win32)
            target='mingw-w64-i686'
            ;;
        mingw-w64-i686)
            ;;
        mingw-w64-x86_64)
            ;;
        *)
            error "target must be one of 'MinGW-w64-i686' or 'MinGW-w64-x86_64'"
            ;;
    esac

    # all good, get the necessary win32 headers
    check git submodule update --init --recursive
}

debian_installdeps() {
    debian=1
    check_cross
    installing

    if [ -z "$target" ]; then
        check sudo apt-get -qq update
        check sudo apt-get -qy install build-essential g++ nasm cmake gettext zlib1g-dev libgl1-mesa-dev libavcodec-dev libavformat-dev libswscale-dev libavutil-dev libgettextpo-dev libpng-dev libsdl2-dev libsfml-dev libopenal-dev libwxgtk3.0-dev libgtk2.0-dev libgtk-3-dev libcairo2-dev
    else
        case "$target" in
            mingw-w64-i686)
                target='i686-w64-mingw32.static'
                ;;
            mingw-w64-x86_64)
                target='x86-64-w64-mingw32.static'
                ;;
            *)
                error "unknown cross target (you shouldn't see this)"
                ;;
        esac

        cmake="/usr/lib/mxe/usr/bin/${target}-cmake"

        mxe_apt_sources='/etc/apt/sources.list.d/mxeapt.list'

        check sudo apt-get -qq update
        if [ -z "$(apt-cache search '^mxe-source$')" ]; then
            if [ ! -f "$mxe_apt_sources" ]; then
                echo "deb http://pkg.mxe.cc/repos/apt/debian wheezy main" | sudo -- sh -c "cat > $mxe_apt_sources"
                check sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys D43A795B73B16ABE9643FE1AFD8FFF16DB45C6AB
            else
                error "$mxe_apt_sources exists but mxe packages are not found in apt, either delete it or fix it"
            fi
        fi

        set --
        for dep in gcc zlib ffmpeg gettext sdl2 sfml openal wxwidgets cairo; do
            set -- "$@" "mxe-${target}-$dep"
        done
        check sudo apt-get -qy install build-essential cmake "$@"
    fi

    build_instructions
}

fedora_installdeps() {
    fedora=1
    check_cross
    installing

    warning=

    # make sure rpmfusion is installed for ffmpeg
    check sudo su -c 'dnf -y install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm'

    # non-multiarch packages first
    check sudo dnf -y install gcc gcc-c++ make cmake git nasm redhat-rpm-config pkgconfig

    # older fedora has separate 32 bit and 64 bit pkgconfig packages
    # try to install both, ignoring errors
    if [ -n "$amd64" ]; then
        sudo dnf -y install pkgconfig.x86_64 >/dev/null 2>&1
        sudo dnf -y install pkgconfig.i686   >/dev/null 2>&1
    fi

    set --
    if [ -z "$target" ]; then
        # try to install both 64 bit and 32 bit versions on 64 bit hosts (see below)
        if [ -n "$amd64" ]; then
            # this is sometimes necessary for rawhide
            set -- --exclude='glibc32*'
        fi
        for pkg in zlib-devel mesa-libGL-devel ffmpeg-devel gettext-devel libpng-devel SDL2-devel SFML-devel openal-soft-devel wxGTK3-devel gtk2-devel gtk3-devel; do
            if [ -n "$amd64" ]; then
                set -- "$@" "${pkg}.x86_64" "${pkg}.i686"
            else
                set -- "$@" "$pkg"
            fi
        done
    else # mingw build
        set -- "$@" pkgconfig
        case "$target" in
            mingw-w64-i686)
                target=mingw32
                cmake_flags='-DCMAKE_TOOLCHAIN_FILE=../CMakeScripts/Toolchain-cross-MinGW-w64-i686.cmake -DENABLE_LINK=NO'
                ;;
            mingw-w64-x86_64)
                target=mingw64
                cmake_flags='-DCMAKE_TOOLCHAIN_FILE=../CMakeScripts/Toolchain-cross-MinGW-w64-x86_64.cmake -DENABLE_LINK=NO'
                ;;
            *)
                error 'unknown cross target (this should not happen)'
                ;;
        esac
        # install static deps
        for pkg in zlib gettext libpng SDL2 wxWidgets; do
            set -- "$@" "${target}-${pkg}-static"
        done
        # install deps that are not available as static
        for pkg in openal-soft; do
            set -- "$@" "${target}-${pkg}"
        done

        warning='SFML is required for LINK support, Fedora does not currently have a MinGW SFML package, if you want LINK support you will need to install it manually'
    fi

    if ! sudo dnf -y install "$@"; then
        if [ -n "$amd64" ]; then
            # try without 32 bit packages, this is a problem on rawhide currently
            warning 'installing 32 bit packages failed, trying to install 64 bit only packages...'
            unset amd64
            fedora_installdeps
            return $?
        else
            error 'installing dependencies for Fedora failed' NOQUIT
            echo 'The failing command was:'
            echo sudo dnf -y install "$@"
            quit 1
        fi
    fi

    warning "$warning"

    build_instructions
}

archlinux_installdeps() {
    arch_linux=1

    pacman='sudo pacman'
    command -v pacaur >/dev/null && pacman='pacaur --noedit'
    command -v yaourt >/dev/null && pacman='yaourt --aur --m-arg=--skipinteg'

    check_cross
    installing

    # check for gcc-multilib
    gcc_pkg=gcc
    if $pacman -Q gcc-multilib >/dev/null 2>&1; then
        gcc_pkg=gcc-multilib
    fi

    # update catalogs
    check $pacman -Sy

    if [ -z "$target" ]; then
        # native build
        check $pacman --noconfirm --needed -S base-devel "$gcc_pkg" nasm zlib mesa cairo cmake ffmpeg gettext libpng pkg-config sdl2 sfml openal wxgtk gtk2 gtk3
    else
        # windows cross build
        case "$target" in
            *i686*)
                cmake_flags='-DCMAKE_TOOLCHAIN_FILE=../CMakeScripts/Toolchain-cross-MinGW-w64-i686.cmake -DENABLE_LINK=NO'
                ;;
            *x86_64*)
                cmake_flags='-DCMAKE_TOOLCHAIN_FILE=../CMakeScripts/Toolchain-cross-MinGW-w64-x86_64.cmake -DENABLE_LINK=NO'
                ;;
            *)
                # this will never be reached, it's checked in check_cross()
                error 'unknown cross target (you should not see this)'
                ;;
        esac

        # base devel packages
        check $pacman --noconfirm --needed -S base-devel "$gcc_pkg" nasm cmake git

        # now install yaourt if we don't have it
        if ! command -v yaourt >/dev/null; then
            (
                cd "$tmp"
                git clone https://aur.archlinux.org/package-query.git
                cd package-query
                makepkg --noconfirm -si
                cd ..
                git clone https://aur.archlinux.org/yaourt.git
                cd yaourt
                makepkg --noconfirm -si
            )
            [ $? -ne 0 ] && error 'could not install yaourt'
        fi
        pacman='yaourt --aur --m-arg=--skipinteg'

        pkg_prefix='mingw-w64-'

        # cross toolchain (without headers and crt, we'll use -git versions)
        set --
        for p in binutils gcc winpthreads; do
            set -- "$@" "${pkg_prefix}${p}"
        done
        check $pacman --noconfirm --needed -S "$@"

        # build library deps from AUR

        info_msg 'We will now build dependencies from AUR, this will take quite a while and has a high probability of failure. In fact, it is definitely broken at the time of this writing. Press CTRL-C now to abort'

        countdown 16

        # pass appropriate make -jX flag through makepkg
        export MAKEPKG_CONF=${MAKEPKG_CONF:-/etc/makepkg.conf}

        grep -Ev '^[ 	]*MAKEFLAGS=' "$MAKEPKG_CONF" > "$tmp/makepkg.conf"

        export MAKEFLAGS="-j$(($(cat /proc/cpuinfo | grep -E '^processor	' | wc -l)+1))"
        echo "MAKEFLAGS=\"$MAKEFLAGS\"" >> "$tmp/makepkg.conf"

        export MAKEPKG_CONF="$tmp/makepkg.conf"

        # now do the AUR builds

        # first we need -headers-git and -crt-git (unless the non-git packages are installed)
        for p in "${pkg_prefix}headers" "${pkg_prefix}crt"; do
          if ! $pacman -Q "$p" >/dev/null 2>&1; then
              check $pacman --noconfirm --needed -S "${p}-git"
          else
              warning "${pkg_prefix}headers-git and ${pkg_prefix}crt-git are recommended over the regular versions, if you have build failures try to install them"
          fi
        done

        # and the actual deps
        for p in zlib gettext libpng pkg-config sdl2 openal wxmsw; do
            pkg="${pkg_prefix}${p}"
            # check if already installed
            if ! $pacman -Q "$pkg" >/dev/null 2>&1; then
                set -- "$@" "${pkg_prefix}${p}"
            fi
        done
        [ $# -gt 0 ] && check $pacman --noconfirm --needed -S "$@"

        warning 'SFML is required for LINK support, the SFML package in AUR is currently broken, if you want LINK support you will need to install it manually'
    fi

    build_instructions
}

msys2_installdeps() {
    msys2=1

    check_cross
    installing

    # update catalogs
    check pacman -Sy

    set --
    for p in SDL2 cairo ffmpeg openal sfml wxWidgets zlib binutils cmake crt-git extra-cmake-modules gcc gcc-libs gdb headers-git make pkg-config tools-git windows-default-manifest libmangle-git nasm; do
        if ! pacman -Q "${target}-${p}" >/dev/null 2>&1; then
            set -- "$@" "${target}-${p}"
        fi
    done

    # install
    check pacman --noconfirm --needed -S git make zip "$@"

    cmake_flags="-G 'MSYS Makefiles'"

    build_instructions
}

osx_installdeps() {
    if ! xcode-select -p >/dev/null 2>&1 && \
       ! pkgutil --pkg-info=com.apple.pkg.CLTools_Executables >/dev/null 2>&1 && \
       ! pkgutil --pkg-info=com.apple.pkg.DeveloperToolsCLI >/dev/null 2>&1; then

        error 'Please install XCode and the XCode Command Line Tools, then run this script again. On newer systems this can be done with: xcode-select --install   '
    fi

    if command -v brew >/dev/null; then
        brew_installdeps
    elif command -v port >/dev/null; then
        macports_installdeps
    elif command -v fink >/dev/null; then
        fink_installdeps
    else
        error 'You have no package manager, please install homebrew, macports or fink'
    fi
}

brew_installdeps() {
    check_cross
    installing

    check brew -v update

    set --
    for f in cairo nasm cmake ffmpeg gettext libpng pkg-config sdl2 sfml wxmac; do
        if brew info "$f" | grep -Eq '^Not installed$'; then
            set -- "$@" "$f"
        fi
    done
    [ $# -gt 0 ] && check brew -v install "$@"

    brew -v cleanup

    build_instructions
}

macports_installdeps() {
    check_cross
    installing

    check sudo port -v selfupdate
    check sudo port -v install cairo cmake nasm ffmpeg gettext libpng pkgconfig libsdl2 sfml wxWidgets-3.0 libiconv
    check sudo port select wxWidgets wxWidgets-3.0

    build_instructions
}

fink_installdeps() {
    check_cross
    installing

    check sudo fink -vy selfupdate
    check sudo fink -vy install cairo cmake nasm ffmpeg libgettext8-dev gettext-tools libpng16 pkgconfig sdl2 wxwidgets300-osxcocoa libiconv-dev

    warning 'SFML is required for LINK support, there is currently no SFML package for Fink, if you want LINK support you will need to install it manually'

    cmake_flags='-DENABLE_LINK=NO'

    build_instructions
}

build_instructions() {
    cat <<EOF

[32mDone! To build do:[0m

mkdir build && cd build
$cmake .. $cmake_flags
make -j8
EOF
}

main "$@"
