################################################################################
# initialization
################################################################################

# define RSTT version
RSTT_VERSION := 3.2.0

# detect os
OS := $(shell uname -s | tr [:upper:] [:lower:])

# detect bit size
UNAME_M := $(shell uname -m)
ifeq ($(UNAME_M),x86_64)
	ARCH := 64
else
	ARCH := 32
endif

# aliases
FC       := gfortran
JAVA     := java
JAVAC    := javac
PY3      := python3
ifneq (, $(shell which $(PY3)))  # python3 is installed
	PYLIBEXT := $(shell $(PY3) -c 'import importlib.machinery as il; print(il.EXTENSION_SUFFIXES[-1])')
endif
MAKE     := make
MKDIR    := mkdir -p
RM  := rm -rfv
ifeq ($(OS),darwin)
	# MacOS
	LIBEXT := dylib
	LIBEXT_JAVA := jnilib
else
	# linux
	LIBEXT := so
	LIBEXT_JAVA := so
endif

# color definitions
blue := $(shell tput setaf 6)
sgr0 := $(shell tput sgr0)


################################################################################
# recipes
################################################################################

# default make command
default: initialize geotess slbm slbmc slbmfort slbmjni slbmpy \
         slbm_test slbmc_test slbmfort_test slbmjni_test slbmpy_test \
         clean msg_python

# recipe to make everything (except documentation) and run tests
all: initialize geotess \
     slbm slbmc slbmfort slbmjni slbmpy \
     geotess_docs slbm_docs slbmc_docs slbmfort_docs slbmjni_docs slbmpy_docs \
     slbm_test slbmc_test slbmfort_test slbmjni_test slbmpy_test \
     clean msg_python

# language-specific
cpp:     cc
cc:      initialize slbm         slbm_test clean
c:       initialize slbmc       slbmc_test clean
fortran: initialize slbmfort slbmfort_test clean
java:    initialize slbmjni   slbmjni_test clean
python:  initialize slbmpy     slbmpy_test clean msg_python
docs:    initialize geotess_docs slbm_docs slbmc_docs slbmfort_docs slbmjni_docs slbmpy_docs
cpp_docs:          cc_docs
cc_docs:         slbm_docs
c_docs:          slbmc_docs
fortran_docs: slbmfort_docs
java_docs:     slbmjni_docs
python_docs:    slbmpy_docs

# command that tells us which recipes don't build source files
.PHONY: default all initialize msg_intro make_dirs msg_python clean cleanall \
        cpp cc c fortran java python \
        docs cpp_docs cc_docs c_docs java_docs python_docs \
        geotess slbm slbmc slbmfort slbmjni slbmpy \
        slbm_test slbmc_test slbmfort_test slbmjni_test slbmpy_test

# initialize some folders and print status message
initialize: msg_intro make_dirs

msg_intro:
	@echo "$(blue)------------------------------------------------------------$(sgr0)"
	@echo "$(blue)Building Regional Seismic Travel Time v$(RSTT_VERSION)$(sgr0)"
	@echo "$(blue)------------------------------------------------------------$(sgr0)"

# create lib and bin directories, if necessary
make_dirs: lib bin

lib:
	@printf "$(blue)(Make directory) $(sgr0)"
	$(MKDIR) lib

bin:
	@printf "$(blue)(Make directory) $(sgr0)"
	$(MKDIR) bin


# geotess library and docs
geotess: make_dirs lib/libgeotesscpp.$(LIBEXT)
lib/libgeotesscpp.$(LIBEXT):
	@printf "$(blue)(Making GeoTessCPP) $(sgr0)"
	$(MAKE) -C GeoTessCPP

geotess_docs: 
	@printf "$(blue)(Making docs) $(sgr0)"
	$(MAKE) -C GeoTessCPP docs


# slbm c++ library, test, and docs
slbm: geotess lib/libslbm.$(LIBEXT)
lib/libslbm.$(LIBEXT):
	@printf "$(blue)(Making SLBM) $(sgr0)"
	$(MAKE) -C SLBM

slbm_test: slbm bin/slbmtestcc
	@printf "$(blue)(Running C++ test) $(sgr0)"
	./bin/slbmtestcc
bin/slbmtestcc:
	@printf "$(blue)(Making SLBM_test_cc) $(sgr0)"
	$(MAKE) -C SLBM_test_cc


slbm_docs: 
	@printf "$(blue)(Making docs) $(sgr0)"
	$(MAKE) -C SLBM docs


# slbm c library, test, and docs
slbmc: slbm lib/libslbmCshell.$(LIBEXT)
lib/libslbmCshell.$(LIBEXT):
	@printf "$(blue)(Making SLBM_C_shell) $(sgr0)"
	$(MAKE) -C SLBM_C_shell

slbmc_test: slbmc bin/slbmtestc
	@printf "$(blue)(Running C test) $(sgr0)"
	./bin/slbmtestc
bin/slbmtestc:
	@printf "$(blue)(Making SLBM_test_c) $(sgr0)"
	$(MAKE) -C SLBM_test_c

slbmc_docs:
	@printf "$(blue)(Making docs) $(sgr0)"
	$(MAKE) -C SLBM_C_shell docs


# slbm fortran library, test, and docs
ifeq (, $(shell which $(FC)))  # gfortran is not installed
slbmfort:
	@printf "$(blue)(Making SLBM_Fort_shell) $(sgr0)"
	@echo "$(FC) is not installed. Skipping..."

else  # gfortran is installed
slbmfort: slbm lib/libslbmFshell.$(LIBEXT)
lib/libslbmFshell.$(LIBEXT):
	@printf "$(blue)(Making SLBM_Fort_shell) $(sgr0)"
	$(MAKE) -C SLBM_Fort_shell

slbmfort_test: slbmfort bin/slbmtestfort
	@printf "$(blue)(Running Fortran test) $(sgr0)"
	./bin/slbmtestfort
bin/slbmtestfort:
	@printf "$(blue)(Making SLBM_test_fort) $(sgr0)"
	$(MAKE) -C SLBM_test_fort

slbmfort_docs:
	@printf "$(blue)(Making docs) $(sgr0)"
	$(MAKE) -C SLBM_Fort_shell docs

endif


# slbm java library and test
ifeq (, $(shell which $(JAVAC)))  # javac is not installed
slbmjni:
	@printf "$(blue)(Making SLBM_JNI) $(sgr0)"
	@echo "$(JAVAC) is not installed. Skipping..."

else  # javac is installed
slbmjni: slbm lib/slbmjni.jar lib/libslbmjni.$(LIBEXT_JAVA)
lib/slbmjni.jar: lib/libslbmjni.$(LIBEXT_JAVA)
lib/libslbmjni.$(LIBEXT_JAVA):
	@printf "$(blue)(Making SLBM_JNI) $(sgr0)"
	$(MAKE) -C SLBM_JNI

slbmjni_test: slbmjni bin/slbmtest.jar
	@printf "$(blue)(Running Java test) $(sgr0)"
	$(JAVA) -jar -Djava.library.path=$(PWD)/lib bin/slbmtest.jar
bin/slbmtest.jar:
	@printf "$(blue)(Making SLBM_test_java) $(sgr0)"
	$(MAKE) -C SLBM_test_java

slbmjni_docs:
	@printf "$(blue)(Making docs) $(sgr0)"
	$(MAKE) -C SLBM_JNI docs

endif


# slbm python library, test, and docs
ifeq (, $(shell which $(PY3)))  # python3 is not installed
slbmpy:
	@printf "$(blue)(Making SLBM_Py_shell) $(sgr0)"
	@echo "$(PY3) is not installed. Skipping..."

else  # python3 is installed
slbmpy: slbm lib/rstt/libslbmPyshell$(PYLIBEXT)
lib/rstt/libslbmPyshell$(PYLIBEXT):
	@printf "$(blue)(Making SLBM_Py_shell) $(sgr0)"
	$(MAKE) -C SLBM_Py_shell

slbmpy_test: slbmpy bin/slbmtest.py
	@printf "$(blue)(Running Python test) $(sgr0)"
	RSTT_ROOT=$(PWD) ./bin/slbmtest.py
bin/slbmtest.py:
	@printf "$(blue)(Making SLBM_test_py) $(sgr0)"
	$(MAKE) -C SLBM_test_python

slbmpy_docs:
	@printf "$(blue)(Making docs) $(sgr0)"
	$(MAKE) -C SLBM_Py_shell docs

msg_python:
	$(MAKE) -C SLBM_Py_shell msg_outro

endif


# clean up object files
clean:
	@echo "$(blue)------------------------------------------------------------$(sgr0)"
	@echo "$(blue)Cleaning up objects...$(sgr0)"
	@echo "$(blue)------------------------------------------------------------$(sgr0)"
	@printf "$(blue)(Cleaning GeoTessCPP) $(sgr0)"
	$(MAKE) -C GeoTessCPP clean
	@printf "$(blue)(Cleaning SLBM) $(sgr0)"
	$(MAKE) -C SLBM clean
	@printf "$(blue)(Cleaning SLBM_test_cc) $(sgr0)"
	$(MAKE) -C SLBM_test_cc clean
	@printf "$(blue)(Cleaning SLBM_C_shell) $(sgr0)"
	$(MAKE) -C SLBM_C_shell clean
	@printf "$(blue)(Cleaning SLBM_test_c) $(sgr0)"
	$(MAKE) -C SLBM_test_c clean
	@printf "$(blue)(Cleaning SLBM_Fort_shell) $(sgr0)"
	$(MAKE) -C SLBM_Fort_shell clean
	@printf "$(blue)(Cleaning SLBM_test_fort) $(sgr0)"
	$(MAKE) -C SLBM_test_fort clean
	@printf "$(blue)(Cleaning SLBM_JNI) $(sgr0)"
	$(MAKE) -C SLBM_JNI clean
	@printf "$(blue)(Cleaning SLBM_test_java) $(sgr0)"
	$(MAKE) -C SLBM_test_java clean
	@printf "$(blue)(Cleaning SLBM_Py_shell) $(sgr0)"
	$(MAKE) -C SLBM_Py_shell clean

cleanall: clean
	@echo "$(blue)------------------------------------------------------------$(sgr0)"
	@echo "$(blue)Cleaning up everything...$(sgr0)"
	@echo "$(blue)------------------------------------------------------------$(sgr0)"
	@printf "$(blue)(Cleaning lib) $(sgr0)"
	$(RM) lib
	@printf "$(blue)(Cleaning bin) $(sgr0)"
	$(RM) bin
	@printf "$(blue)(Cleaning GeoTessCPP docs) $(sgr0)"
	$(RM) GeoTessCPP/doc/html
	@printf "$(blue)(Cleaning SLBM docs) $(sgr0)"
	$(RM) SLBM/doc/html
	@printf "$(blue)(Cleaning SLBM_C_shell docs) $(sgr0)"
	$(RM) SLBM_C_shell/doc/html
	@printf "$(blue)(Cleaning SLBM_Fort_shell docs) $(sgr0)"
	$(RM) SLBM_Fort_shell/doc/html
	@printf "$(blue)(Cleaning SLBM_JNI docs) $(sgr0)"
	$(RM) SLBM_JNI/java/SlbmInterface/doc
	@printf "$(blue)(Cleaning SLBM_Py_shell docs) $(sgr0)"
	$(RM) SLBM_Py_shell/doc/html
	@printf "$(blue)(Cleaning SLBM_Py_shell module) $(sgr0)"
	cd SLBM_Py_shell; $(RM) *.so wheel python/rstt/*.dylib python/rstt/*.so
	@printf "$(blue)(Cleaning usage examples) $(sgr0)"
	cd usage_examples; $(RM) cpp_example c_example fortran_example java_example.class

msg_end: lib/libslbmPyshell$(PYLIBEXT)
	@echo "$(blue)------------------------------------------------------------$(sgr0)"
	@printf "$(blue)To install the 'rstt' module, run:\n$(sgr0)"
	@echo " $$ $(PY3) -m pip install --no-index --find-links=$(shell pwd)/SLBM_Py_shell/wheel rstt"
	@echo "$(blue)------------------------------------------------------------$(sgr0)"
