#!/bin/sh
# Configuration script for Tennix
# 2013-07-27 Thomas Perl <m@thp.io>

V="1.3.4"
SILENT="1"
PYTHON="1"
PREFIX="/usr/local"
DEFAULT_CFLAGS="-I. -Wall -fPIC"

if [ -z "$CC" ]; then
    CC="gcc"
fi

if [ -z "$CXX" ]; then
    CXX="g++"
fi

if [ -z "$CFLAGS" ]; then
    CFLAGS=""
fi

if [ -z "$LDFLAGS" ]; then
    LDFLAGS=""
fi

if [ -z "$SDL_CONFIG" ]; then
    SDL_CONFIG="sdl2-config"
fi

CFLAGS="$DEFAULT_CFLAGS $CFLAGS"

PLATFORM=""

GENERATED_HEADER="Generated: $(date)"
CONFIG_H="/* $GENERATED_HEADER */"
CONFIG_MK="# $GENERATED_HEADER"

NL='
'

fail() {
    echo "ERROR: $1"
    exit 1
}

set_make_variable() {
    CONFIG_MK="$CONFIG_MK$NL$1 := $2"
}

define_macro() {
    CONFIG_H="$CONFIG_H$NL#define $1"
}

undefine_macro() {
    CONFIG_H="$CONFIG_H$NL#undef $1"
}

add_definition() {
    define_macro $1
    set_make_variable $1 1
}

no_definition() {
    undefine_macro $1
    set_make_variable $1 0
}

cond_definition() {
    if [ $1 -eq 0 ]; then
        add_definition $2
    else
        no_definition $2
    fi
}

check_cc() {
    echo "int main() { return 0; }" | $CC $CFLAGS -x c -c -o configtest.o - 2>/dev/null
}

check_cxx() {
    echo "class A { public: A() {} }; int main() { A a; }" | $CXX $CFLAGS -x c++ -c -o configtest.o -
}

check_linker_cc() {
    echo "int main() { return 0; }" | $CC $CFLAGS $LDFLAGS -l$1 -x c -o configtest.o - 2>/dev/null
}

check_header_cc() {
    echo "#include <$1>" | $CC $CFLAGS -c -x c -o configtest.o -c - 2>/dev/null
}

message_wrapper() {
    printf "$1 ... "
    shift
    $*
    if [ $? -eq 0 ]; then
        echo "yes"
        return 0
    else
        echo "no"
        return 1
    fi
}

check_sdl_lib() {
    if ! which "$SDL_CONFIG" >/dev/null 2>&1; then
        return 1
    fi

    CFLAGS="$("$SDL_CONFIG" --cflags) $CFLAGS"
    LDFLAGS="$("$SDL_CONFIG" --libs) $LDFLAGS"
    return 0
}

check_os() {
    printf "Detecting operating system ... "
    UNAME=$(uname -s)
    case $UNAME in
        Linux)
            echo "Linux"
            PLATFORM="linux"
            ;;
        Darwin)
            echo "macOS"
            PLATFORM="osx"
            ;;
        *)
            echo "???"
            fail "Unknown platform: $UNAME"
            ;;
    esac
}

check_compiler() {
    message_wrapper "Testing working C compiler ($CC)" check_cc || fail "C compiler ($CC) not working"
    message_wrapper "Testing working C++ compiler ($CXX)" check_cxx || fail "C++ compiler ($CXX) not working"
}

check_sdl2() {
    message_wrapper "Checking for SDL2" check_sdl_lib
    cond_definition $? HAVE_SDL
}

require_sdl2() {
    check_sdl2 || fail "SDL2 not found"
}

check_voice_files() {
    message_wrapper "Checking for voice files" [ -f voice/deuce.ogg ]
    cond_definition $? HAVE_VOICE_FILES
}

check_python_lib() {
    if [ -z "$PYTHON3_CONFIG" ]; then
        PYTHON3_CONFIG="python3-config"
    fi

    if ! which "$PYTHON3_CONFIG" >/dev/null 2>&1; then
        return 1
    fi

    CFLAGS="$("$PYTHON3_CONFIG" --cflags) $CFLAGS"
    if "$PYTHON3_CONFIG" --embed --libs >/dev/null 2>&1; then
        # Python 3.8 and newer
        LDFLAGS="$("$PYTHON3_CONFIG" --embed --libs) $LDFLAGS"
    else
        # Python 3.7 and older
        LDFLAGS="$("$PYTHON3_CONFIG" --libs) $LDFLAGS"
    fi
    return 0
}

check_tool_path() {
    COMMAND=$1
    VARIABLE=$2

    if ! which $COMMAND >/dev/null 2>&1; then
        return 1
    fi

    if [ "$VARIABLE" != "" ]; then
        set_make_variable $VARIABLE $(which $COMMAND 2>/dev/null)
    fi
}

check_tool() {
    message_wrapper "Checking for $1" check_tool_path $*
}

require_tool() {
    check_tool $* || fail "Required command '$1' not found"
}

check_python() {
    message_wrapper "Checking for libpython3" check_python_lib
    cond_definition $? HAVE_PYTHON
}

check_header() {
    message_wrapper "Checking for $1" check_header_cc $1
}

check_linker() {
    message_wrapper "Checking for -l$1" check_linker_cc $1
}

check_library() {
    LIBRARY=$1
    HEADER=$2
    DEFINE=$3
    check_linker $LIBRARY
    HAVE_LINKER=$?
    check_header $HEADER
    HAVE_HEADER=$?
    if [ $HAVE_LINKER -eq 0 -a $HAVE_HEADER -eq 0 ]; then
        add_definition $DEFINE
        LDFLAGS="-l$LIBRARY $LDFLAGS"
    else
        no_definition $DEFINE
        return 1
    fi
    return 0
}

require_library() {
    check_library $* || fail "Library $1 ($2) not found"
}

generate_dependencies() {
    echo "Generating dependencies.mk"
    rm -f dependencies.mk
    (
    echo "# $GENERATED_HEADER"
    for filename in src/*.cc; do $CXX -MM $filename $CFLAGS -o -; done
    )>dependencies.mk
}

write_config() {
    echo "Writing config.h"
    rm -f config.h
    (
    echo "$CONFIG_H"
    echo "#define VERSION \"$V\""
    echo "#define PREFIX \"$PREFIX\""
    )>config.h

    echo "Writing config.mk"
    rm -f config.mk
    (
    echo "$CONFIG_MK"
    echo "V = $V"
    echo "SILENT = $SILENT"
    echo "PREFIX = $PREFIX"
    echo "PLATFORM = $PLATFORM"
    echo "CC = $CC"
    echo "CXX = $CXX"
    echo "CFLAGS = $CFLAGS"
    echo "CXXFLAGS = $CFLAGS"
    echo "LDFLAGS = $LDFLAGS"
    )>config.mk
}

usage() {
    cat <<EOF

    Usage: $0 [options]
    
    Supported options:
    --prefix PREFIX             Install into PREFIX (default: $PREFIX)
    --help | -h                 Show this help message
    --with-debug                Enable additional debugging output
    --enable-update-rect        Visualize screen updates
    --enable-nonfree-locations  Additional tennis courts on world map
    --enable-fps-limit          Limit frame rate
    --disable-silent            Disable silent make output
    --disable-python            Disable checking for Python

EOF
}

parse_arguments() {
    while [ $# -gt 0 ]; do
        case $1 in
            --prefix)
                [ $# -gt 1 ] || fail "Not enough arguments."
                PREFIX="$2"
                CFLAGS="-I$PREFIX/include $CFLAGS"
                LDFLAGS="-L$PREFIX/lib $LDFLAGS"
                shift
                ;;
            --with-debug)
                define_macro DEBUG
                CFLAGS="-g $CFLAGS"
                ;;
            --enable-update-rect)
                define_macro DRAW_UPDATE_RECTANGLE
                ;;
            --enable-nonfree-locations)
                define_macro NONFREE_LOCATIONS
                ;;
            --enable-fps-limit)
                define_macro ENABLE_FPS_LIMIT
                ;;
            --disable-silent)
                SILENT="0"
                ;;
            --disable-python)
                PYTHON="0"
                ;;
            -h|--help)
                usage
                exit 0
                ;;
            *)
                usage
                fail "Unknown argument: $1"
                ;;
        esac
        shift
    done
}

# Parse command-line arguments
parse_arguments $*

# Cleanup
trap "rm -f configtest.o" EXIT

# Check for compatible OS and working compiler
check_os
check_compiler

# Check for command-line tools needed for build
require_tool make

# Check for command-line tools required in makefile
require_tool ln LN
require_tool install INSTALL
require_tool rm RM

# Check for SDL 2 and libpython3
require_sdl2
[ "$PYTHON" != "0" ] && check_python

# Check for mandatory and optional libraries
require_library SDL2_image SDL_image.h HAVE_SDL_IMAGE
require_library SDL2_ttf SDL_ttf.h HAVE_SDL_TTF
check_library SDL2_net SDL_net.h HAVE_SDL_NET
require_library SDL2_mixer SDL_mixer.h HAVE_SDL_MIXER
require_library SDL2_gfx SDL2_rotozoom.h HAVE_SDL_GFX

# Check for optional game content
check_voice_files

# Save configuration results and generate dependency file
write_config
generate_dependencies

