#!/usr/bin/env sh

#
# Argument Parsing
#

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

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

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


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

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

# Process all arguments
for arg in $SCRIPT_ARGS; do
    case "$arg" in
        --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=""
            ;;
        --bin-name=*)
            BIN_NAME=$(echo "$arg" | cut -d '=' -f 2-)
            ;;
        --version=*)
            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

CFLAGS="${CFLAGS} '-DTELODENDRIA_VERSION=\"${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
}

prefix() {
    prefix="$1"
    shift

    for thing in $@; do
        printf "${prefix}${thing} "
    done
}

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

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

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

	pref=$(cc -I${INCLUDE} -MM -MT "${obj}" "${src}")
    echo "$pref $(collect ${SCHEMA}/ .json .h ${INCLUDE}/Schema/ print_obj)"
	echo "${TAB}@mkdir -p $(dirname ${obj})"
	echo "${TAB}\$(CC) \$(CFLAGS) -fPIC -c -o \"${obj}\" \"${src}\""
}

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

    depObjs=$(prefix ${BUILD}/ CanonicalJson.o Telodendria.o)
    
    echo "${out}: ${src}"
    echo "${TAB}@mkdir -p ${OUT}/bin"
    echo "${TAB}\$(CC) \$(CFLAGS) -o \"${out}\" \"${src}\" $depObjs \$(LDFLAGS) ${STATIC}"
}

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

    if echo "${src}" | grep "Schema" > /dev/null; then
        return
    fi

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

print_doc() {
    if echo "${src}" | grep "Schema" > /dev/null; then
        return
    fi
	printf '%s ' "$2"
}

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

    echo "${INCLUDE}/Schema/${out}.h:"
    echo "${TAB}@mkdir -p ${INCLUDE}/Schema ${SRC}/Schema"
    echo "${TAB}j2s -s \"${src}\" -h \"${INCLUDE}/Schema/${out}.h\" -c \"${SRC}/Schema/${out}.c\""

    echo "${SRC}/Schema/${out}.c:"
    echo "${TAB}@mkdir -p ${INCLUDE}/Schema ${SRC}/Schema"
    echo "${TAB}j2s -s \"${src}\" -h \"${INCLUDE}/Schema/${out}.h\" -c \"${SRC}/Schema/${out}.c\""
}

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

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

install_man() {
	src="${OUT}/man/man3/${BIN_NAME}-$(basename $1 .h).3"
	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')

# If objects don't include the schema (this is the first configure),
# then include them manually.
if ! echo "${OBJS}" | grep "Schema" > /dev/null; then
    OBJS="${OBJS} $(collect ${SCHEMA}/ .json .o ${BUILD}/Schema/ print_obj)"
fi

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: ${BIN_NAME} docs tools
docs: $(collect ${INCLUDE}/ .h .3 ${OUT}/man/man3/${BIN_NAME}- print_doc)
tools: $(collect ${TOOLS}/ .c '' ${OUT}/bin/ print_obj)

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

${BIN_NAME}: ${OUT}/bin/${BIN_NAME}

install: ${BIN_NAME}
${TAB}install -D ${OUT}/bin/${BIN_NAME} \$(PREFIX)/bin/${BIN_NAME}

uninstall:
${TAB}rm \$(PREFIX)/bin/${BIN_NAME}

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

${OUT}/bin/${BIN_NAME}: ${OBJS}
${TAB}@mkdir -p "${OUT}/bin"
${TAB}\$(CC) -o "${OUT}/bin/${BIN_NAME}" ${OBJS} \$(CFLAGS) \$(LDFLAGS)

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

EOF

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