#!/usr/bin/env bash
#
# TROUBLESHOOTING
#   - Take a look at the "Optional features" section.  Some features have dependencies,
#       either make sure you have them or disable those features.
#       eg. mpw_color=0 ./build
#
# BUGS
#   masterpassword@lyndir.com
#
# AUTHOR
#   Maarten Billemont
#
cd "${BASH_SOURCE%/*}"
shopt -s extglob
set -e


### CONFIGURATION
# Targets to build.
if [[ $targets ]]; then
    read -ra targets <<< "$targets"
else
    # Default targets.
    # Modify here or override using targets='mpw mpw-bench' ./build
    targets=(
        mpw                         # C CLI version of Master Password (needs: mpw_sodium, optional: mpw_color, mpw_json).
       #mpw-bench                   # C CLI Master Password benchmark utility (needs: mpw_sodium).
       #mpw-tests                   # C Master Password algorithm test suite (needs: mpw_sodium, mpw_xml).
    )
fi

# Optional features.
mpw_sodium=${mpw_sodium:-1} # Implement crypto functions with sodium (depends on libsodium).
mpw_json=${mpw_json:-1}     # Support JSON-based user configuration format (depends on libjson-c).
mpw_color=${mpw_color:-1}   # Colorized identicon (depends on libncurses).
mpw_xml=${mpw_xml:-1}       # XML parsing (depends on libxml2).

# Default build flags.
cflags=( -O3 $CFLAGS )
ldflags=( $LDFLAGS )

# Version.
if { mpw_version=$(git describe --match '*-cli*' --long --dirty --broken) || mpw_version=$(<VERSION); } 2>/dev/null; then
    cflags+=( -D"MP_VERSION=$mpw_version" )
fi
echo 2>&1 "Current mpw source version ${mpw_version:-<unknown>}..."


### TARGET: MPW
mpw() {
    # dependencies
    use_mpw_sodium
    use_mpw_color
    use_mpw_json

    # target
    cflags=(
        "${cflags[@]}"

        # library paths
        -I"lib/include"
        # mpw paths
        -I"core" -I"cli"
    )
    local ldflags=(
        "${ldflags[@]}"
    )

    # build
    cc "${cflags[@]}" "$@"                  -c core/base64.c            -o core/base64.o
    cc "${cflags[@]}" "$@"                  -c core/mpw-algorithm.c     -o core/mpw-algorithm.o
    cc "${cflags[@]}" "$@"                  -c core/mpw-types.c         -o core/mpw-types.o
    cc "${cflags[@]}" "$@"                  -c core/mpw-util.c          -o core/mpw-util.o
    cc "${cflags[@]}" "$@"                  -c core/mpw-marshall-util.c -o core/mpw-marshall-util.o
    cc "${cflags[@]}" "$@"                  -c core/mpw-marshall.c      -o core/mpw-marshall.o
    cc "${cflags[@]}" "$@" "core/base64.o" "core/mpw-algorithm.o" "core/mpw-types.o" "core/mpw-util.o" "core/mpw-marshall-util.o" "core/mpw-marshall.o" \
       "${ldflags[@]}"     "cli/mpw-cli.c" -o "mpw"
    echo "done!  Now run ./install or use ./$_"
}


### TARGET: MPW-BENCH
mpw-bench() {
    # dependencies
    use_mpw_sodium

    # target
    cflags=(
        "${cflags[@]}"

        # library paths
        -I"lib/include"
        # mpw paths
        -I"core" -I"cli"
    )
    local ldflags=(
        "${ldflags[@]}"
    )

    # build
    cc "${cflags[@]}" "$@"                  -c core/base64.c        -o core/base64.o
    cc "${cflags[@]}" "$@"                  -c core/mpw-algorithm.c -o core/mpw-algorithm.o
    cc "${cflags[@]}" "$@"                  -c core/mpw-types.c     -o core/mpw-types.o
    cc "${cflags[@]}" "$@"                  -c core/mpw-util.c      -o core/mpw-util.o
    cc "${cflags[@]}" "$@" "core/base64.o" "core/mpw-algorithm.o" "core/mpw-types.o" "core/mpw-util.o" \
       "${ldflags[@]}"     "cli/mpw-bench.c" -o "mpw-bench"
    echo "done!  Now use ./$_"
}


### TARGET: MPW-TESTS
mpw-tests() {
    # dependencies
    use_mpw_xml
    use_mpw_sodium

    # target
    cflags=(
        "${cflags[@]}"

        # library paths
        -I"lib/include"
        # mpw paths
        -I"core" -I"cli"
    )
    local ldflags=(
        "${ldflags[@]}"
    )

    # build
    cc "${cflags[@]}" "$@"                  -c core/base64.c        -o core/base64.o
    cc "${cflags[@]}" "$@"                  -c core/mpw-algorithm.c -o core/mpw-algorithm.o
    cc "${cflags[@]}" "$@"                  -c core/mpw-types.c     -o core/mpw-types.o
    cc "${cflags[@]}" "$@"                  -c core/mpw-util.c      -o core/mpw-util.o
    cc "${cflags[@]}" "$@"                  -c cli/mpw-tests-util.c -o cli/mpw-tests-util.o
    cc "${cflags[@]}" "$@" "core/base64.o" "core/mpw-algorithm.o" "core/mpw-types.o" "core/mpw-util.o" \
       "${ldflags[@]}"     "cli/mpw-tests-util.o" "cli/mpw-tests.c" -o "mpw-tests"
    echo "done!  Now use ./$_"
}


### TOOLS
haslib() {
    cc -l"$1" -x c -o /dev/null - <<< 'int main() { return 0; }'
}
cc() {
    if hash llvm-gcc 2>/dev/null; then
        llvm-gcc "$@"
    elif hash gcc 2>/dev/null; then
        gcc -std=gnu99 "$@"
    elif hash clang 2>/dev/null; then
        clang "$@"
    else
        echo >&2 "Need a compiler.  Please install GCC or LLVM."
        exit 1
    fi
}


### DEPENDENCIES
use_mpw_sodium() {
    ! (( mpw_sodium )) && return

    if ! haslib sodium; then
        echo >&2 "WARNING: mpw_sodium enabled but missing sodium library, will disable mpw_sodium."

    else
        echo >&2 "Enabled mpw_sodium (libsodium)."
        cflags+=( -D"MPW_SODIUM=1" ) ldflags+=( -l"sodium" )
    fi
}
use_mpw_color() {
    ! (( mpw_color )) && return

    if ! haslib curses; then
        echo >&2 "WARNING: mpw_color enabled but missing curses library, will disable mpw_color."

    else
        echo >&2 "Enabled mpw_color (libcurses)."
        cflags+=( -D"MPW_COLOR=1" ) ldflags+=( -l"curses" )
    fi
}
use_mpw_json() {
    ! (( mpw_json )) && return

    if ! haslib json-c; then
        echo >&2 "WARNING: mpw_json enabled but missing json-c library, will disable mpw_json."

    else
        echo >&2 "Enabled mpw_json (libjson-c)."
        cflags+=( -D"MPW_JSON=1" ) ldflags+=( -l"json-c" )
    fi
}
use_mpw_xml() {
    ! (( mpw_xml )) && return

    if ! haslib xml2; then
        echo >&2 "WARNING: mpw_xml enabled but missing xml2 library, will disable mpw_xml."

    else
        echo >&2 "Enabled mpw_xml (libxml2)."
        cflags+=( -D"MPW_XML=1" -I"/usr/include/libxml2" -I"/usr/local/include/libxml2" ) ldflags+=( -l"xml2" )
    fi
}


### BUILD TARGETS
echo "Will build targets: ${targets[*]}..."
for target in "${targets[@]}"; do
    echo
    echo "Building target: $target..."
    ( "$target" "$@" )
done