#!/usr/bin/env sh

#
# Argument Parsing
#

echo "Build Configuration"
echo "-------------------"

BUILD="build"
OUT="out"
SRC="src"
INCLUDE="src/include"
TOOLS="tools"

CFLAGS="-Wall -Wextra -pedantic -std=c89 -O3 -pipe -D_DEFAULT_SOURCE -I${INCLUDE}"
LIBS="-lm -pthread"


# Set default args for all platforms
SCRIPT_ARGS="--prefix=/usr/local --enable-ld-extra --lib-name=Cytoplasm --lib-version=0.4.0 --static $@"

# Set platform specific args
case "$(uname)" in
    OpenBSD)
        SCRIPT_ARGS="--with-libressl $SCRIPT_ARGS"
        ;;
    *)
        SCRIPT_ARGS="--with-openssl $SCRIPT_ARGS"
        ;;
esac

echo "Processing options..."
echo "Ran with arguments: $SCRIPT_ARGS"

# Process all arguments
for arg in $SCRIPT_ARGS; do
    case "$arg" in
        --with-openssl)
            TLS_IMPL="TLS_OPENSSL"
            TLS_LIBS="-lcrypto -lssl"
            ;;
        --with-libressl)
            TLS_IMPL="TLS_LIBRESSL"
            TLS_LIBS="-ltls -lcrypto -lssl"
            ;;
        --disable-tls)
            TLS_IMPL=""
            TLS_LIBS=""
            ;;
        --prefix=*)
            PREFIX=$(echo "$arg" | cut -d '=' -f 2-)
            ;;
        --enable-ld-extra)
            LD_EXTRA="-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections"
            ;;
        --disable-ld-extra)
            LD_EXTRA=""
            ;;
        --lib-name=*)
            LIB_NAME=$(echo "$arg" | cut -d '=' -f 2-)
            ;;
        --lib-version=*)
            LIB_VERSION=$(echo "$arg" | cut -d '=' -f 2-)
            ;;
        --enable-debug)
            DEBUG="-O0 -g"
            echo "Notice: --enable-debug implies --disable-ld-extra and --no-static."
            echo "You must explicitly provide --enable-ld-extra and/or --static after"
            echo "specifying --enable-debug if you wish to enable these features in debug mode."
            LD_EXTRA=""
            STATIC=""
            ;;
        --disable-debug)
            DEBUG=""
            ;;
        --static)
            STATIC="-static -Wl,-static"
            ;;
        --no-static)
            STATIC=""
            ;;
        *)
            echo "Invalid argument: $1"
            exit 1
            ;;
    esac
done

if [ -n "$TLS_IMPL" ]; then
    CFLAGS="${CFLAGS} -DTLS_IMPL=${TLS_IMPL}"
    LIBS="${LIBS} ${TLS_LIBS}"
fi

CFLAGS="${CFLAGS} '-DLIB_NAME=\"${LIB_NAME}\"' '-DLIB_VERSION=\"${LIB_VERSION}\"' ${DEBUG}"
LDFLAGS="${LIBS} ${LD_EXTRA}"

#
# Makefile generation
#

collect() {
	from="$1"
	orig_ext="$2"
	new_ext="$3"
	prefix="$4"
	exec="$5"

	find "${from}" -name "*${orig_ext}" -type f | while IFS= read -r src; do
		src=$(echo "$src" | sed -e "s|^${from}||g")
		obj=$(echo "$src" | sed -e "s|${orig_ext}\$|${new_ext}|g")

		obj="${prefix}${obj}"
		src="${from}${src}"

		"${exec}" "${src}" "${obj}"
	done
}

print_src() {
	printf '%s ' "$1"
}

print_obj() {
	printf '%s ' "$2"
}

compile_obj() {
	src="$1"
	obj="$2"

	cc -I${INCLUDE} -MM -MT "${obj}" "${src}"
	echo "${TAB}@mkdir -p $(dirname ${obj})"
	echo "${TAB}\$(CC) \$(CFLAGS) -fPIC -c -o \"${obj}\" \"${src}\""
}

compile_bin() {
	src="$1"
	out="$2"

    echo "${out}: ${OUT}/lib/lib${LIB_NAME}.a ${OUT}/lib/lib${LIB_NAME}.so ${src}"
    echo "${TAB}@mkdir -p ${OUT}/bin"
    echo "${TAB}\$(CC) \$(CFLAGS) -o \"${out}\" \"${src}\" -L${OUT}/lib \$(LDFLAGS) -l${LIB_NAME} ${STATIC}"
}

compile_doc() {
	src="$1"
	out="$2"

    if [ -z "${STATIC}" ]; then
        pref="LD_LIBRARY_PATH=${OUT}/lib "
    fi

	echo "${out}: ${OUT}/bin/hdoc ${src}"
	echo "${TAB}@mkdir -p ${OUT}/man/man3"
	echo "${TAB}${pref}${OUT}/bin/hdoc -D \"Os=${LIB_NAME}\" -i \"${src}\" -o \"${out}\""
}

install_out() {
	src="$1"
	out="$2"

	echo "${TAB}install -D \"$src\" \"$out\""
}

install_man() {
	src="${OUT}/man/man3/${LIB_NAME}-$(basename $1 .h).3"
	out="$2"

	echo "${TAB}install -D \"$src\" \"$out\""
}

install_tool() {
    src=${OUT}/bin/$(basename "$1" .c)
    out="$2"

    echo "${TAB}install -D \"$src\" \"$out\""
}

uninstall_out() {
	src="$1"
	out="$2"

	echo "${TAB}rm \"$out\""
}

echo "Generating Makefile..."

OBJS=$(collect ${SRC}/ .c .o ${BUILD}/ print_obj)
TAB=$(printf '\t')

cat << EOF > Makefile
.POSIX:

# Generated by '$0' on $(date).
# This file should generally not be manually edited.

CC = cc
PREFIX = ${PREFIX}
CFLAGS = ${CFLAGS}
LDFLAGS = ${LDFLAGS}

all: ${LIB_NAME} docs tools
docs: $(collect ${INCLUDE}/ .h .3 ${OUT}/man/man3/${LIB_NAME}- print_obj)
tools: $(collect ${TOOLS}/ .c '' ${OUT}/bin/ print_obj)

print-libs:
${TAB}@echo ${LIBS}

format:
${TAB}find . -name '*.c' | while IFS= read -r src; do \\
${TAB}  if indent "\$\$src"; then \\
${TAB}    rm \$\$(basename "\$\$src").BAK; \\
${TAB}  fi \\
${TAB}done

license:
${TAB}find . -name '*.[ch]' | while IFS= read -r src; do \\
${TAB}  srcHeader=\$\$(grep -n -m 1 '^ \*/' "\$\$src" | cut -d ':' -f 1); \\
${TAB}  head -n\$\$srcHeader \$\$src | \\
${TAB}    diff -u -p - "LICENSE.txt" | \\
${TAB}    patch "\$\$src" | grep -v "^Hmm"; \\
${TAB}done

${LIB_NAME}: ${OUT}/lib/lib${LIB_NAME}.a ${OUT}/lib/lib${LIB_NAME}.so

install: ${LIB_NAME}
${TAB}install -D ${OUT}/lib/lib${LIB_NAME}.a \$(PREFIX)/lib/lib${LIB_NAME}.a
${TAB}install -D ${OUT}/lib/lib${LIB_NAME}.so \$(PREFIX)/lib/lib${LIB_NAME}.so
$(collect ${INCLUDE}/ '' '' \$\(PREFIX\)/include/${LIB_NAME}/ install_out)
$(collect ${INCLUDE}/ .h .3 \$\(PREFIX\)/man/man3/${LIB_NAME}- install_man)
$(collect ${TOOLS}/ '.c' '' \$\(PREFIX\)/bin/ install_tool)

uninstall:
${TAB}rm -r \$(PREFIX)/lib/lib${LIB_NAME}.*
${TAB}rm -r \$(PREFIX)/include/${LIB_NAME}
${TAB}rm -r \$(PREFIX)/man/man3/${LIB_NAME}-*
$(collect ${TOOLS}/ '.c' '' \$\(PREFIX\)/bin/ uninstall_out)

clean:
${TAB}rm -r "${BUILD}" "${OUT}"

${OUT}/lib/lib${LIB_NAME}.a: ${OBJS}
${TAB}@mkdir -p ${OUT}/lib
${TAB}\$(AR) rcs ${OUT}/lib/lib${LIB_NAME}.a ${OBJS}

${OUT}/lib/lib${LIB_NAME}.so: ${OBJS}
${TAB}@mkdir -p ${OUT}/lib
${TAB}\$(CC) -shared -o ${OUT}/lib/lib${LIB_NAME}.so ${OBJS} ${LDFLAGS}

$(collect ${SRC}/ .c .o ${BUILD}/ compile_obj)
$(collect ${TOOLS}/ .c '' ${OUT}/bin/ compile_bin)
$(collect ${INCLUDE}/ .h .3 ${OUT}/man/man3/${LIB_NAME}- compile_doc)

EOF

echo "Done. Run 'make' to build ${LIB_NAME}."