################################################################################
# configuration
################################################################################

# paths to relevant compilers and shells
# (don't worry if you do not have one installed; it will not matter unless you
#  try to compile an rstt interface in that language)
export MAKE    := make#           # GNU Makefiles
export CC      := gcc#            # C compiler
export CXX     := g++#            # C++ compiler
export FC      := gfortran#       # Fortran compiler
export DOX     := doxygen#        # C, C++, Fortran documentation
export JAVA    := java#           # Java virtual machine
export JAVAC   := javac#          # Java compiler
export JAVADOC := javadoc#        # Java documentation
export JAR     := jar#            # Java jar files
export PY3     := python3#        # Python 3.x
export PIP     := $(PY3) -m pip#  # Python pip
export SPHINX  := sphinx-build#   # Python documentation


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

# define RSTT version
RSTT_VERSION := 3.2.1

# aliases
export MKDIR  := mkdir -p
export CP     := cp -rv
export MV     := mv -v
export RM     := rm -rfv

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

# detect os (linux, darwin)
export OS := $(shell uname -s | tr '[:upper:]' '[:lower:]')

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

# declare the library file extension for your system
ifeq ($(OS),darwin)
	# MacOS
	export LIBEXT := dylib
	export LIBEXT_JAVA := jnilib
else
	# linux
	export LIBEXT := so
	export LIBEXT_JAVA := so
endif

# get the extension for compiled python libraries, lib directory, and python library version
ifneq (, $(shell which $(PY3)))  # if python is installed
	export LIBEXT_PY := $(shell $(PY3) -c 'import sysconfig; print(sysconfig.get_config_var("EXT_SUFFIX"))')
endif

# set a flag indicating to child Makefiles that they've been called from the main Makefile
export CALLED_FROM_MAIN := true


################################################################################
# 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 tmp

# 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$(LIBEXT_PY)
lib/rstt/libslbmPyshell$(LIBEXT_PY):
	@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
	@printf "$(blue)(Cleaning SLBM_test_python) $(sgr0)"
	$(MAKE) -C SLBM_test_python clean

cleanall:
	@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) $(sgr0)"
	$(MAKE) -C GeoTessCPP cleanall
	@printf "$(blue)(Cleaning SLBM) $(sgr0)"
	$(MAKE) -C SLBM cleanall
	@printf "$(blue)(Cleaning SLBM_test_cc) $(sgr0)"
	$(MAKE) -C SLBM_test_cc cleanall
	@printf "$(blue)(Cleaning SLBM_C_shell) $(sgr0)"
	$(MAKE) -C SLBM_C_shell cleanall
	@printf "$(blue)(Cleaning SLBM_test_c) $(sgr0)"
	$(MAKE) -C SLBM_test_c cleanall
	@printf "$(blue)(Cleaning SLBM_Fort_shell) $(sgr0)"
	$(MAKE) -C SLBM_Fort_shell cleanall
	@printf "$(blue)(Cleaning SLBM_test_fort) $(sgr0)"
	$(MAKE) -C SLBM_test_fort cleanall
	@printf "$(blue)(Cleaning SLBM_JNI) $(sgr0)"
	$(MAKE) -C SLBM_JNI cleanall
	@printf "$(blue)(Cleaning SLBM_test_java) $(sgr0)"
	$(MAKE) -C SLBM_test_java cleanall
	@printf "$(blue)(Cleaning SLBM_Py_shell) $(sgr0)"
	$(MAKE) -C SLBM_Py_shell cleanall
	@printf "$(blue)(Cleaning SLBM_test_python) $(sgr0)"
	$(MAKE) -C SLBM_test_python cleanall
	@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 usage examples) $(sgr0)"
	cd usage_examples; $(RM) cpp_example c_example fortran_example java_example.class

msg_end: lib/libslbmPyshell$(LIBEXT_PY)
	@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)"
