# --*- Makefile -*--

# Run tests in a test directory (tests/ by default) and report if
# all tests pass.

# USAGE:
#     make clean
#     make distclean
#     make tests
#     make

#------------------------------------------------------------------------------
# Include local configuration files from this directory:

MAKECONF_FILES = ${filter-out %~, ${wildcard Makeconf*}}

ifneq ("${MAKECONF_FILES}","")
include ${MAKECONF_FILES}
endif

#------------------------------------------------------------------------------

JFLAGS = 

SRC_DIR = src
CLS_DIR = classes

SRC_FILES = ${wildcard ${SRC_DIR}/*.java}
PKG_FILES = $(shell find ${SRC_DIR}/net -name '*.java')

JFILES   = ${PKG_FILES} ${SRC_FILES}
CLSFILES = ${JFILES:${SRC_DIR}/%.java=${CLS_DIR}/%.class}

MANIFEST = MANIFEST.txt

JARFILE = jars/smiles-scripts-${VERSION}.jar
JARLINK = jars/smiles-scripts.jar
TARGET  = ${JARFILE}

MAIN_JFILES  = ${wildcard ${SRC_DIR}/[a-z]*.java}
MAIN_CLASSES = ${MAIN_JFILES:${SRC_DIR}/%.java=${CLS_DIR}/%.class}

# From https://stackoverflow.com/questions/2372056/how-to-turn-off-logging-from-slf4j:
# if needed, 'nop' loads slf4j-nop.jar which is a no-operation logger
SLF4J_LOGGER = simple

JUNIT_DIR     = tests/junit
JUNIT_SRC_DIR = ${JUNIT_DIR}/src
JUNIT_CLS_DIR = ${JUNIT_DIR}/classes
JUNIT_FILES  := $(shell find ${JUNIT_DIR} -name '*.java')
JUNIT_CLASSES = ${JUNIT_FILES:${JUNIT_SRC_DIR}/%.java=${JUNIT_CLS_DIR}/%.class}

CLASSPATH := ${JARFILE}${CLASSPATH}

export CLASSPATH

JUNIT_CLASSPATH = ${CLASSPATH}:/usr/share/java/junit4.jar

PATH := bin:scripts:${PATH}

export PATH

PERL5LIB := $(shell pwd)/lib/perl5:${PERL5LIB}

export PERL5LIB

#------------------------------------------------------------------------------

COMPILED = ${JARFILE} \
           ${PM_TO_BLIB_FILES} \
           ${BUILD_FILES}

#------------------------------------------------------------------------------

BIN_DIR  = .

TEST_DIR = tests/cases
OUTP_DIR = tests/outputs

INP_FILES  = ${wildcard ${TEST_DIR}/*.inp}
OPT_FILES  = ${wildcard ${TEST_DIR}/*.opt}
SH_FILES   = ${wildcard ${TEST_DIR}/*.sh}

INP_DIFFS = ${INP_FILES:${TEST_DIR}/%.inp=${OUTP_DIR}/%.diff}
INP_OUTS  = ${INP_FILES:${TEST_DIR}/%.inp=${OUTP_DIR}/%.out}

OPT_DIFFS = ${OPT_FILES:${TEST_DIR}/%.opt=${OUTP_DIR}/%.diff}
OPT_OUTS  = ${OPT_FILES:${TEST_DIR}/%.opt=${OUTP_DIR}/%.out}

SH_DIFFS = ${SH_FILES:${TEST_DIR}/%.sh=${OUTP_DIR}/%.diff}
SH_OUTS  = ${SH_FILES:${TEST_DIR}/%.sh=${OUTP_DIR}/%.out}

DIFF_FILES = $(sort ${INP_DIFFS} ${OPT_DIFFS} ${SH_DIFFS})
OUTP_FILES = $(sort ${INP_OUTS} ${OPT_OUTS} ${SH_OUTS})

.PHONY: all clean cleanAll distclean check test tests out outputs

all: ${COMPILED}

#------------------------------------------------------------------------------
# Include Makefiles with additional rules for this directory:

MAKELOCAL_FILES = ${filter-out %~, ${wildcard Makelocal*}}

ifneq ("${MAKELOCAL_FILES}","")
include ${MAKELOCAL_FILES}
endif

#------------------------------------------------------------------------------

${SRC_FILES:%.java=%.class}: ${PKG_FILES:%.java=%.class}

${JUNIT_CLS_DIR}/%.class: ${JUNIT_SRC_DIR}/%.java
	javac ${JFLAGS} -cp ${JUNIT_CLASSPATH} -d ${JUNIT_CLS_DIR} $<

${CLS_DIR}/%.class: ${SRC_DIR}/%.java
	javac ${JFLAGS} -cp ${CLS_DIR}:${CLASSPATH}:$$(grep '^ ' MANIFEST.txt | xargs | tr ' ' :) -d ${CLS_DIR} $<

${JARFILE}: ${MANIFEST} ${CLSFILES}
	jar cfm $@ ${MANIFEST} -C ${CLS_DIR} .
	ln -sf $(@F) ${JARLINK}

SMILES = --smiles c1ccccc1

.PHONY: echo display

echo display:
	@echo ${COMPILED}
	@echo ${JUNIT_FILES}
	@echo ${JUNIT_CLASSES}

run: ${MAIN_CLASSES}
	for FILE in $^; do ( \
		CLASS=$$(basename $$FILE .class); \
		set -x; \
		java $${CLASS} ${SMILES} \
	) done

#------------------------------------------------------------------------------

${MANIFEST}:
	echo 'Manifest-Version: 1.0\r' > $@
	echo 'Created-By: 1.8.0_151 (Oracle Corporation)\r' >> $@
	echo 'Class-Path: \r' >> $@
	find /usr/share/java -name 'cdk-*.jar' | grep -P 'cdk-[^-]+\.jar' | sort | xargs -i echo -e ' '{}' \r' >> $@
	find /usr/share/java -name 'freehep-graphicsio-*.jar' | grep -P 'freehep-graphicsio-[^-0-9]+\.jar' | sort | xargs -i echo -e ' '{}' \r' >> $@
	echo ' /usr/share/java/beam-core.jar \r' >> $@
	echo ' /usr/share/java/soptions.jar \r' >> $@
	echo ' /usr/share/java/freehep-graphics2d.jar \r' >> $@
	echo ' /usr/share/java/freehep-graphicsbase.jar \r' >> $@
	echo ' /usr/share/java/freehep-graphicsio.jar \r' >> $@
	echo ' /usr/share/java/guava.jar \r' >> $@
	echo ' /usr/share/java/jna.jar \r' >> $@
	echo ' /usr/share/java/jna-inchi-api.jar \r' >> $@
	echo ' /usr/share/java/log4j-1.2.jar \r' >> $@
	echo ' /usr/share/java/slf4j-api.jar \r' >> $@
	echo ' /usr/share/java/slf4j-$(SLF4J_LOGGER).jar \r' >> $@
	echo ' /usr/share/java/soptions.jar \r' >> $@
	echo ' /usr/share/java/vecmath.jar \r' >> $@

#------------------------------------------------------------------------------

DEPEND = .depend

include ${DEPEND}

${DEPEND}: ${JFILES} src/Version.java
	mkjavadepend ${SRC_DIR} ${CLS_DIR} > $@

#------------------------------------------------------------------------------

check test tests: ${DIFF_FILES}

out outputs: ${OUTP_FILES}

#------------------------------------------------------------------------------

define filter_output
perl -lpe 's,at [-+\.\/\w\d]+ line \d+\.?,at <script_name> line <line_no>.,'
endef

#------------------------------------------------------------------------------
# Rules to run script-specific tests:

${OUTP_DIR}/%.diff: ${TEST_DIR}/%.inp ${TEST_DIR}/%.opt ${OUTP_DIR}/%.out ${COMPILED}
	-@printf "%-50s " "$<:" ; \
	if [ ! -e ${TEST_DIR}/$*.chk ] || ${TEST_DIR}/$*.chk; then \
		test -f $(dir $<)/$*.env && . $(dir $<)/$*.env; \
		$(shell echo $* | sed -e 's/_[0-9]*$$//') \
		    $(shell grep -v '^#' ${word 2, $^}) \
	    	$< 2>&1 \
		| ${filter_output} \
		| diff ${OUTP_DIR}/$*.out - > $@ ; \
		if [ $$? = 0 ]; then echo "OK"; else echo "FAILED:"; cat $@; fi; \
	else \
		touch $@; \
	fi

${OUTP_DIR}/%.diff: ${TEST_DIR}/%.inp ${OUTP_DIR}/%.out ${COMPILED}
	-@printf "%-50s " "$<:" ; \
	if [ ! -e ${TEST_DIR}/$*.chk ] || ${TEST_DIR}/$*.chk; then \
		test -f $(dir $<)/$*.env && . $(dir $<)/$*.env; \
		$(shell echo $* | sed -e 's/_[0-9]*$$//') \
		    $< 2>&1 \
		| ${filter_output} \
		| diff ${OUTP_DIR}/$*.out - > $@ ; \
		if [ $$? = 0 ]; then echo "OK"; else echo "FAILED:"; cat $@; fi; \
	else \
		touch $@; \
	fi

${OUTP_DIR}/%.diff: ${TEST_DIR}/%.opt ${OUTP_DIR}/%.out ${COMPILED}
	-@printf "%-50s " "$<:" ; \
	if [ ! -e ${TEST_DIR}/$*.chk ] || ${TEST_DIR}/$*.chk; then \
		test -f $(dir $<)/$*.env && . $(dir $<)/$*.env; \
		$(shell echo $* | sed -e 's/_[0-9]*$$//') \
		    $(shell grep -v '^#' $<) \
		2>&1 \
		| ${filter_output} \
		| diff ${OUTP_DIR}/$*.out - > $@ ; \
		if [ $$? = 0 ]; then echo "OK"; else echo "FAILED:"; cat $@; fi; \
	else \
		touch $@; \
	fi

${OUTP_DIR}/%.diff: ${TEST_DIR}/%.sh ${OUTP_DIR}/%.out ${COMPILED}
	-@printf "%-50s " "$<:" ; \
	if [ ! -e ${TEST_DIR}/$*.chk ] || ${TEST_DIR}/$*.chk; then \
		test -f $(dir $<)/$*.env && . $(dir $<)/$*.env; \
		$< 2>&1 \
		| ${filter_output} \
		| diff ${OUTP_DIR}/$*.out - > $@ ; \
		if [ $$? = 0 ]; then echo "OK"; else echo "FAILED:"; cat $@; fi; \
	else \
		touch $@; \
	fi

# Rules to generate sample test outputs:

${OUTP_DIR}/%.out: ${TEST_DIR}/%.inp ${TEST_DIR}/%.opt ${COMPILED}
	-@test -f $@ || echo "$@:"
	-@test -f $(dir $<)/$*.env && . $(dir $<)/$*.env; \
	test -f $@ || \
	$(shell echo $* | sed -e 's/_[0-9]*$$//') \
	    $(shell grep -v '^#' ${word 2, $^}) \
	    $< \
	2>&1 \
	| ${filter_output} \
	| tee $@
	-@touch $@

${OUTP_DIR}/%.out: ${TEST_DIR}/%.inp ${COMPILED}
	-@test -f $@ || echo "$@:"
	-@test -f $(dir $<)/$*.env && . $(dir $<)/$*.env; \
	test -f $@ || \
	$(shell echo $* | sed -e 's/_[0-9]*$$//') \
	    $< \
	2>&1 \
	| ${filter_output} \
	| tee $@
	-@touch $@

${OUTP_DIR}/%.out: ${TEST_DIR}/%.opt ${COMPILED}
	-@test -f $@ || echo "$@:"
	-@test -f $(dir $<)/$*.env && . $(dir $<)/$*.env; \
	test -f $@ || \
	$(shell echo $* | sed -e 's/_[0-9]*$$//') \
	    $(shell grep -v '^#' $<) \
	2>&1 \
	| ${filter_output} \
	| tee $@
	-@touch $@

${OUTP_DIR}/%.out: ${TEST_DIR}/%.sh ${COMPILED}
	-@test -f $@ || echo "$@:"
	-@test -f $(dir $<)/$*.env && . $(dir $<)/$*.env; \
	test -f $@ || \
	$< 2>&1 \
	| ${filter_output} \
	| tee $@
	-@touch $@

#------------------------------------------------------------------------------
# Rules to run JUnit tests:

tests: junit-tests

.PHONY: junit-tests

JUNIT_LOG_DIR = ${OUTP_DIR}/junit
JUNIT_LOGS = ${JUNIT_CLASSES:${JUNIT_CLS_DIR}/%.class=${JUNIT_LOG_DIR}/%.log}

junit-tests: ${JUNIT_LOGS}

.PRECIOUS: ${JUNIT_CLS_DIR}/%.class

${JUNIT_LOG_DIR}/%.log: ${JUNIT_CLS_DIR}/%.class
	@mkdir -p $(dir $@)
	@CLASS=$$(echo $< | sed 's:^tests/junit/classes/::; s/\.class$$//; s:/:.:g'); \
	echo -n $$CLASS":\t"; \
	java -cp ${JUNIT_CLASSPATH}:${JUNIT_CLS_DIR} org.junit.runner.JUnitCore $${CLASS} \
	> $@ 2>&1; \
	if [ $$? -eq 0 ]; then echo "OK"; else echo "FAILED:"; cat $@; fi

#------------------------------------------------------------------------------

.PHONY: listdiff

listdiff:
	@-( \
	test -d "${OUTP_DIR}" && \
	find "${OUTP_DIR}" -name '*.diff' -size +0 \
	) | sort -u

#------------------------------------------------------------------------------

clean:
	rm -f ${DIFF_FILES}
	rm -f ${JUNIT_LOGS}

cleanAll distclean: clean
	rm -f ${CLSFILES}
	rm -f ${MANIFEST}
	rm -f ${JARFILE} ${JARLINK}
	rm -f ${JUNIT_CLASSES}
	rm -f .depend
	rm -rf ${JUNIT_CLS_DIR}/* ${CLS_DIR}/* ${JUNIT_LOG_DIR}/*
