#!/bin/sh

#
# Lol Engine build script
# Usage:
#   lol-build [<flags>...] <action> [<platform>]
#
# Supported flags:
#  --enable-debug
#  --enable-devel
#  --enable-release
#
# Where <action> is one of:
#  - bootstrap
#  - configure
#  - build
#  - check
#  - clean
#
# And <platform> is one of:
#  - linux-i386
#  - linux-amd64
#  - ios-arm
#  - osx-amd64
#  - android-arm
#  - win*-i386
#  - win*-amd64
#  - raspi-arm
#  - web-html
#  - web-js
#

set -e

###############################################################################
# Commandline parsing
#
action=""
platform=""
configure_flags=""
while [ "$#" -gt 0 ]; do
    case "$1" in
      --enable-debug|--enable-devel|--enable-release)
        configure_flags="${configure_flags} $1"
        ;;
      --*)
        echo "E: invalid flag $1"
        exit 1
        ;;
      *)
        if [ -z "$action" ]; then
            action="$1"
        else
            platform="$1"
        fi
        ;;
    esac
    shift
done

###############################################################################
# Initialisation code
#
#  - sets the top_srcdir variable
#  - sets the LOL_PARALLEL variable
#  - fix PATH and MKPATH if necessary
#
__init__()
{
    top_srcdir="$(dirname "$0")/.."
    cd "$top_srcdir"
    top_srcdir="`pwd`"

    # Try to count CPU cores. First obvious try: /proc/cpuinfo on Linux
    case "$cpu_count" in
      [1-9]|[1-9][0-9]|[1-9][0-9][0-9]) ;;
      *) if [ -r "/proc/cpuinfo" ]; then
           cpu_count="$(grep -c '^processor\>' /proc/cpuinfo 2>/dev/null || true)"
         fi ;;
    esac
    # If that didn't work, try sysctl (for OS X machines)
    case "$cpu_count" in
      [1-9]|[1-9][0-9]|[1-9][0-9][0-9]) ;;
      *) cpu_count="$(sysctl -n hw.ncpu 2>/dev/null || true)" ;;
    esac
    # Otherwise, CPUInfo.exe (from Xoreax's XGE) may help on Windows
    case "$cpu_count" in
      [1-9]|[1-9][0-9]|[1-9][0-9][0-9]) ;;
      *) cpu_count="$(CPUInfo.exe | sed -ne 's/CPU Cores.* \([0-9][0-9]*\)/\1/p')" ;;
    esac
    # Otherwise, Windows may define NUMBER_OF_PROCESSORS
    case "$cpu_count" in
      [1-9]|[1-9][0-9]|[1-9][0-9][0-9]) ;;
      *) cpu_count="$NUMBER_OF_PROCESSORS" ;;
    esac
    # Otherwise, be conservative and assume 1 CPU core
    case "$cpu_count" in
      [1-9]|[1-9][0-9]|[1-9][0-9][0-9]) ;;
      *) cpu_count=1 ;;
    esac
    # Now decide how many parallel threads to launch
    case "$cpu_count" in
      1) LOL_PARALLEL=1 ;;
      2) LOL_PARALLEL=3 ;;
      *) LOL_PARALLEL="$(expr $cpu_count '*' 3 / 2)" ;;
    esac

    case "${MSYSTEM}" in
        MINGW32|MINGW64)
            PATH="$PATH:./external/gtk-2.22.1/bin"
            M4PATH="$M4PATH:./external/gtk-2.22.1/share/aclocal"
            ;;
    esac

    # Ensure we don’t launch weird Windows binaries when cross-compiling
    WINEDLLOVERRIDES="winemenubuilder.exe,wineboot.exe,explorer.exe,winedbg.exe=d"
    export WINEDLLOVERRIDES

    # Ensure SDL does not redirect stdout/stderr to local files
    SDL_STDIO_REDIRECT=0
    export SDL_STDIO_REDIRECT
}

bootstrap()
{
    cd "$top_srcdir"
    case "$platform" in
        *)
            PATH="$PATH" M4PATH="$M4PATH" ./bootstrap
            ;;
    esac
}

do_configure()
{
    ./configure ${configure_flags} "$@"
}

configure()
{
    cd "$top_srcdir"
    case "$platform" in
        android-arm)
            PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$PWD/external/libcaca-0.99.beta18/lib/pkgconfig"
            LDFLAGS="$LDFLAGS -L$PWD/external/libcaca-0.99.beta18/lib/arm-linux-androideabi -lz"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/libcaca-0.99.beta18/include -DCACA_STATIC"
            ;;
        win*-i386)
            if test "x${MSYSTEM}" = xMINGW32; then
                :
            elif i586-mingw32msvc-g++ --version >/dev/null 2>&1; then
                HOSTFLAGS=--host=i586-mingw32msvc
                BUILDFLAGS=--build=none
            elif i686-w64-mingw32-g++ --version >/dev/null 2>&1; then
                HOSTFLAGS=--host=i686-w64-mingw32
                BUILDFLAGS=--build=none
            else
                echo "Error: could not find win32 compiler" >&2
                false
            fi
            if test "x${MSYSTEM}" = xMINGW64; then
                # If using mingw64, we're not really cross-compiling
                BUILDFLAGS=
            fi
            PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$PWD/external/gtkglarea-2.0.1/lib/pkgconfig"
            PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$PWD/external/libcaca-0.99.beta18/lib/pkgconfig"
            LDFLAGS="$LDFLAGS -L$PWD/external/ffmpeg-20141018/lib/i686-w64-mingw32"
            LDFLAGS="$LDFLAGS -L$PWD/external/glew-1.9.0/lib/i686-w64-mingw32"
            LDFLAGS="$LDFLAGS -L$PWD/external/sdl-2.0.3/lib/i686-w64-mingw32"
            LDFLAGS="$LDFLAGS -L$PWD/external/sdl-image-2.0.0/lib/i686-w64-mingw32"
            LDFLAGS="$LDFLAGS -L$PWD/external/sdl-mixer-2.0.0/lib/i686-w64-mingw32"
            LDFLAGS="$LDFLAGS -L$PWD/external/gtk-2.22.1/lib"
            LDFLAGS="$LDFLAGS -L$PWD/external/gtk-2.22.1/bin"
            LDFLAGS="$LDFLAGS -L$PWD/external/gtkglarea-2.0.1/lib"
            LDFLAGS="$LDFLAGS -L$PWD/external/libcaca-0.99.beta18/lib/i686-w64-mingw32"
            ;;
        win*-amd64)
            if test "x${MSYSTEM}" = xMINGW64; then
                :
            elif x86_64-w64-mingw32-g++ --version >/dev/null 2>&1; then
                HOSTFLAGS=--host=x86_64-w64-mingw32
                BUILDFLAGS=--build=none
            else
                echo "Error: could not find win64 compiler" >&2
                false
            fi
            if test "x${MSYSTEM}" = xMINGW32; then
                # If using mingw32, we're not really cross-compiling
                BUILDFLAGS=
            fi
            PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$PWD/external/gtkglarea-2.0.1/lib/pkgconfig"
            PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$PWD/external/libcaca-0.99.beta18/lib/pkgconfig"
            LDFLAGS="$LDFLAGS -L$PWD/external/ffmpeg-20141018/lib/x86_64-w64-mingw32"
            LDFLAGS="$LDFLAGS -L$PWD/external/glew-1.9.0/lib/x86_64-w64-mingw32"
            LDFLAGS="$LDFLAGS -L$PWD/external/sdl-2.0.3/lib/x86_64-w64-mingw32"
            LDFLAGS="$LDFLAGS -L$PWD/external/sdl-image-2.0.0/lib/x86_64-mingw32"
            LDFLAGS="$LDFLAGS -L$PWD/external/sdl-mixer-2.0.0/lib/x86_64-mingw32"
            LDFLAGS="$LDFLAGS -L$PWD/external/libcaca-0.99.beta18/lib/x86_64-w64-mingw32"
            ;;
        *-i386)
            # Ensure we're _really_ on i386
            CXXFLAGS="$CXXFLAGS -m32"
            ;;
        *-amd64)
            # Ensure we're _really_ on amd64
            CXXFLAGS="$CXXFLAGS -m64"
            ;;
        web-*)
            # Force cross-compilation because AC_TRY_LINK is going to check
            # whether our binaries have the executable bit set.
            HOSTFLAGS=--host=none
            BUILDFLAGS=--build=`$top_srcdir/.auto/config.guess`
            ;;
    esac
    case "$platform" in
        ios-arm)
            XCODE="/Applications/Xcode.app/Contents/Developer"
            SDKVER="6.1"
            DEVROOT="$XCODE/Platforms/iPhoneOS.platform/Developer"
            SDKROOT="$DEVROOT/SDKs/iPhoneOS$SDKVER.sdk"
            CC="$XCODE/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang"
            CXX="$XCODE/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++"
            do_configure --host=armv7-apple-darwin10 CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS" CC="$CC" CXX="$CXX"
            ;;
        android-arm)
            CPPFLAGS="$CPPFLAGS -Wno-psabi -I$ANDROID_NDK_ROOT/sources/cxx-stl/stlport/stlport -I$ANDROID_NDK_ROOT/sources/android/native_app_glue -fpic -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64"
            CFLAGS="$CFLAGS -march=armv5te -mtune=xscale -msoft-float -mthumb"
            CXXFLAGS="$CXXFLAGS -march=armv5te -mtune=xscale -msoft-float -mthumb -fno-rtti -fno-exceptions"
            LOL_LIBS="$LOL_LIBS -L$ANDROID_NDK_ROOT/sources/cxx-stl/stlport/libs/armeabi -lstlport_shared -lm -fpic -XCClinker -shared -u ANativeActivity_onCreate"
            PKG_CONFIG_PATH="$PKG_CONFIG_PATH" do_configure --host=arm-linux-androideabi ac_cv_exeext=.so CPPFLAGS="$CPPFLAGS" CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" LOL_LIBS="$LOL_LIBS"
            # FIXME: is this needed?
            # ant debug
            # ant debug install
            # ant clean
            ;;
        raspi-arm)
            do_configure --host=arm-bcm2708hardfp-linux-gnueabi CPPFLAGS="-I$RASPI_SDK_ROOT/firmware/opt/vc/include -I$RASPI_SDK_ROOT/firmware/opt/vc/include/interface/vmcs_host/linux -I$RASPI_SDK_ROOT/chroot/usr/include -I$RASPI_SDK_ROOT/chroot/usr/include/arm-linux-gnueabihf" LDFLAGS="-L$RASPI_SDK_ROOT/firmware/opt/vc/lib -L$RASPI_SDK_ROOT/chroot/lib/arm-linux-gnueabihf -Wl,-rpath-link -Wl,$RASPI_SDK_ROOT/chroot/lib/arm-linux-gnueabihf -L$RASPI_SDK_ROOT/chroot/usr/lib/arm-linux-gnueabihf -Wl,-rpath-link -Wl,$RASPI_SDK_ROOT/chroot/usr/lib/arm-linux-gnueabihf -Wl,--unresolved-symbols=ignore-in-shared-libs"
            ;;
        osx-amd64)
            # HACK: use clang++ because of a memory leak in llvm-g++.
            do_configure CXX=clang++ CC=clang
            ;;
        win*-i386|win*-amd64)
            CPPFLAGS="$CPPFLAGS -I$PWD/external/sdl-2.0.3/include"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/sdl-image-2.0.0/include"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/sdl-mixer-2.0.0/include"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/ffmpeg-20141018/include"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/glew-1.9.0/include/GL -DGLEW_STATIC"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/gtk-2.22.1/lib/glib-2.0/include"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/gtk-2.22.1/lib/gtk-2.0/include"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/gtk-2.22.1/include/glib-2.0"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/gtk-2.22.1/include/gtk-2.0"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/gtk-2.22.1/include/cairo"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/gtk-2.22.1/include/pango-1.0"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/gtk-2.22.1/include/gdk-pixbuf-2.0"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/gtk-2.22.1/include/atk-1.0"
            CPPFLAGS="$CPPFLAGS -I$PWD/external/gtkglarea-2.0.1/include"
            CPPFLAGS="$CPPFLAGS -I$PWD/src/3rdparty/imgui/include"
            CPPFLAGS="$CPPFLAGS -mms-bitfields"
            LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++"
            GTK_LIBS="$GTK_LIBS -lgtkgl-2.0 -lopengl32 -lglew32 -lgdi32"
            GTK_LIBS="$GTK_LIBS -lgtk-win32-2.0 -lgdk-win32-2.0"
            GTK_LIBS="$GTK_LIBS -lglib-2.0 -lgthread-2.0 -lgobject-2.0"

            CPPFLAGS="$CPPFLAGS -I$PWD/external/libcaca-0.99.beta18/include -DCACA_STATIC"

            PATH="$PATH" PKG_CONFIG_PATH="$PKG_CONFIG_PATH" do_configure $HOSTFLAGS $BUILDFLAGS CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS" GTK_LIBS="$GTK_LIBS"
            ;;
        web-*)
            # We use --enable-release otherwise builds are really too slow
            do_configure --enable-release $HOSTFLAGS $BUILDFLAGS CC=emcc CXX=em++ AR=emar RANLIB=emranlib PKG_CONFIG=/bin/false SDL_CONFIG=/bin/false ac_cv_exeext=".${platform##web-}" CPPFLAGS="-s USE_SDL=2" CXXFLAGS="-s USE_SDL=2" CFLAGS="-s USE_SDL=2"
            ;;
        *)
            PATH="$PATH" do_configure CFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS"
            ;;
    esac
}

build()
{
    cd "$top_srcdir"
    case "$platform" in
        win*-i386)
            # Because of locking issues in Wine’s winepath.exe, we only
            # build the static libraries in parallel.
            make -j$LOL_PARALLEL -C src/3rdparty liblol-bullet.a
            make -j$LOL_PARALLEL -C src/3rdparty liblol-lua.a
            make -j$LOL_PARALLEL -C src/ liblol-core.a
            make
            ;;
        *)
            make -j$LOL_PARALLEL
            ;;
    esac
}

check()
{
    cd "$top_srcdir"
    case "$platform" in
        ios-arm)
            ;;
        android-arm)
            ;;
        raspi-arm)
            ;;
        web-*)
            ;;
        win*-i386)
            # If neither $MSYSTEM or $DISPLAY are set, and xvfb-run
            # exists, use it to run the test suite.
            if test "x${MSYSTEM}${DISPLAY}" = x \
               && xvfb-run --help 2>&1 >/dev/null; then
                xvfb-run -a make check VERBOSE=1
            else
                make check VERBOSE=1
            fi
            ;;
        win*-amd64)
            # No support for Wine64 yet
            ;;
        *)
            make check VERBOSE=1
            ;;
    esac
}

clean()
{
    cd "$top_srcdir"
    case "$platform" in
        *)
            make distclean
            ;;
    esac
}

__init__
echo "lol-build: executing action '$action' on platform '$platform'" >&2
eval "$action"