#! /usr/bin/env bash

if [ "${TRAVIS}" == "true" ]
then
  BUILDDIR=${1:-build}
  mkdir $BUILDDIR && cd $BUILDDIR
else
  EXTRA_ARGS=$@
fi

### The following assumes you are building in a subdirectory of ACCESS Root
### If not, then define "ACCESS" to point to the root of the SEACAS source code.
if [ "$ACCESS" == "" ]
then
    ACCESS=$(cd ..; pwd)
fi

### The SEACAS code will install in ${INSTALL_PATH}/bin, ${INSTALL_PATH}/lib, and ${INSTALL_PATH}/include.
INSTALL_PATH=${INSTALL_PATH:-${ACCESS}}

### Possible subset of what is built ---
APPLICATIONS=${APPLICATIONS:-ON}
LEGACY=${LEGACY:-ON}
FORTRAN=${FORTRAN:-ON}
ZOLTAN=${ZOLTAN:-ON}

### Python Version...
PYTHON_VER=${PYTHON_VER:-"3.0"}

### Set to ON for parallel compile; otherwise OFF for serial (default)
netcdf_parallel=$($INSTALL_PATH/bin/nc-config --has-parallel)
if [ "${netcdf_parallel}" == "yes" ]
then
    MPI=ON
else
    MPI=OFF
fi

echo "MPI set to ${MPI}"

if [ "${MPI}" == "OFF" ]
then
  ### Change this to point to the compilers you want to use
    ## Travis build (and others) set this to EXTERNAL to set
    ## CXX, CC, and FC externally.
  COMPILER=${COMPILER:-gnu}

  if [ "$COMPILER" == "gnu" ]
  then
      CXX=g++
      CC=gcc
      FC=gfortran
      CFLAGS="-Wall -Wunused -pedantic"
      CXXFLAGS="-Wall -Wunused -pedantic"
  fi

  if [ "$COMPILER" == "clang" ]
  then
      CXX=clang++
      CC=clang
      FC=gfortran-mp-7
      CFLAGS="-Wall -Wunused -pedantic"
      CXXFLAGS="-Wall -Wunused -pedantic"
  fi

  if [ "$COMPILER" == "intel" ]
  then
      CXX=icpc
      CC=icc
      FC=ifort
      CFLAGS="-Wall -Wunused"
      CXXFLAGS="-Wall -Wunused"
  fi

  if [ "$COMPILER" == "ibm" ]
  then
      CXX=xlC
      CC=xlc
      FC=xlf
  fi

fi

if [ "${APPLICATIONS}" == "ON" ] && [ "${LEGACY}" == "ON" ]
then
     SUBSET_OPTIONS="-DSEACASProj_ENABLE_ALL_PACKAGES:BOOL=ON \
                     -DSEACASProj_ENABLE_ALL_OPTIONAL_PACKAGES:BOOL=ON \
                     -DSEACASProj_ENABLE_SECONDARY_TESTED_CODE:BOOL=ON"
else
     SUBSET_OPTIONS="-DSEACASProj_ENABLE_ALL_PACKAGES:BOOL=OFF \
                     -DSEACASProj_ENABLE_ALL_OPTIONAL_PACKAGES:BOOL=OFF \
		     -DSEACASProj_ENABLE_SECONDARY_TESTED_CODE:BOOL=OFF \
                     -DSEACASProj_ENABLE_SEACASIoss:BOOL=ON \
		     -DSEACASProj_ENABLE_SEACASExodus:BOOL=ON \
		     -DSEACASProj_ENABLE_SEACASExodus_for:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASExoIIv2for32:BOOL=ON"

if [ "${APPLICATIONS}" == "ON" ]
then
     SUBSET_OPTIONS="${SUBSET_OPTIONS} \
                     -DSEACASProj_ENABLE_SEACASAprepro:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASAprepro_lib:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASConjoin:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASEjoin:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASEpu:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASExo2mat:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASExo_format:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASExodiff:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASMat2exo:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASNemslice:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASNemspread:BOOL=ON"

     if [ "${FORTRAN}" == "ON" ]
	then
	    SUBSET_OPTIONS="${SUBSET_OPTIONS} \
            		  -DSEACASProj_ENABLE_SEACASExplore:BOOL=ON \
			  -DSEACASProj_ENABLE_SEACASGrepos:BOOL=ON"
     fi

elif [ "${LEGACY}" == "ON" ] && [ "${FORTRAN}" == "ON" ]
then
     SUBSET_OPTIONS="${SUBSET_OPTIONS} \
                     -DSEACASProj_ENABLE_SEACASAlgebra:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASBlot:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASEx1ex2v2:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASEx2ex1v2:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASExomatlab:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASExotec2:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASExotxt:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASFastq:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASGen3D:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASGenshell:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASGjoin:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASMapvar:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASMapvar-kd:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASNemesis:BOOL=ON \
                     -DSEACASProj_ENABLE_SEACASTxtexo:BOOL=ON"
fi
fi

GENERATOR=${GENERATOR:-"Unix Makefiles"}

# If using an XLF compiler on an IBM system, may need to add the following:
# -DCMAKE_Fortran_FLAGS="-qfixed=72" \
# -DCMAKE_EXE_LINKER_FLAGS:STRING="-lxl -lxlopt"

SHARED="${SHARED:-ON}"

### Switch for Debug or Release build:
### Check that both `DEBUG` and `BUILD_TYPE` are not set
if [ ! -z ${DEBUG+x} ] && [ ! -z ${BUILD_TYPE+x} ]
then
    echo "ERROR: Both DEBUG and BUILD_TYPE are set. Only one is allowed."
    exit
fi

BUILD_TYPE="${BUILD_TYPE:-RELEASE}"

if [ ! -z ${DEBUG+x} ]
then
    if [ "${DEBUG}" == "ON" ] || [ "${DEBUG}" == "YES" ]
    then
	BUILD_TYPE="DEBUG"
    elif [ "${DEBUG}" == "OFF" ] || [ "${DEBUG}" == "NO" ]
    then
	BUILD_TYPE="RELEASE"
    else
	echo "ERROR: Invalid value for DEBUG ('$DEBUG'). Must be 'ON', 'OFF', 'YES', 'NO'."
	exit
    fi
fi


### If you do not have the X11 developer package on your system
### which provides X11/Xlib.h and the libX11, then change the "ON"
### below to "OFF". It will disable blot and fastq
HAVE_X11=${X11:-ON}

### Set to ON to enable the building of a thread-safe version of the Exodus and IOSS libraries.
THREADSAFE=${THREADSAFE:-OFF}
if [ "$THREADSAFE" == "ON" ] ; then
  THREAD_SAFE_OPT="-DSEACASProj_EXTRA_LINK_FLAGS=-lpthread"
fi


### TPLs --
### Make sure these point to the locations to find the libraries and includes in lib and include
### subdirectories of the specified paths.
### For example, netcdf.h should be in ${NETCDF_PATH}/include
NETCDF_PATH=${INSTALL_PATH}
PNETCDF_PATH=${INSTALL_PATH}
MATIO_PATH=${INSTALL_PATH}
HDF5_PATH=${INSTALL_PATH}
CGNS_PATH=${INSTALL_PATH}
DATAWAREHOUSE_PATH=${INSTALL_PATH}
ADIOS2_PATH=${INSTALL_PATH}
GTEST_PATH=${INSTALL_PATH}
KOKKOS_PATH=${INSTALL_PATH}

function check_enable()
{
    local path=$1
    if [ -e "${path}" ]
    then
	echo "ON"
    else
	echo "OFF"
    fi
}

HAVE_NETCDF=$(check_enable "${NETCDF_PATH}/include/netcdf.h")
HAVE_MATIO=$(check_enable "${MATIO_PATH}/include/matio.h")
HAVE_CGNS=$(check_enable "${CGNS_PATH}/include/cgnslib.h")
HAVE_DATAWAREHOUSE=OFF
HAVE_ADIOS2=$(check_enable "${ADIOS2_PATH}/include/adios2.h")
HAVE_GTEST=$(check_enable "${GTEST_PATH}/include/gtest/gtest.h")
HAVE_KOKKOS=$(check_enable "${KOKKOS_PATH}/include/Kokkos_Core.hpp")

### DataWarp (Burst Buffer)
### I use the following for mutrino (10/16/2018):
###    module load datawarp
###    -D TPL_ENABLE_DataWarp:BOOL=ON \
###    -D DataWarp_LIBRARY_DIRS:PATH=/opt/cray/datawarp/2.1.16-6.0.5.1_2.61__g238b34d.ari/lib \
###    -D DataWarp_INCLUDE_DIRS:PATH=/opt/cray/datawarp/2.1.16-6.0.5.1_2.61__g238b34d.ari/include \

### Define to NO to *enable* exodus deprecated functions
OMIT_DEPRECATED=${OMIT_DEPRECATED:-NO}

# BUG needs to work with cray too.
if [ "${MPI}" == "ON" ] && [ "${CRAY}" == "ON" ]
then
   MPI_EXEC=$(which srun)
   MPI_SYMBOLS="-D MPI_EXEC=${MPI_EXEC} -D MPI_EXEC_NUMPROCS_FLAG=-n"
   CXX=CC
   CC=cc
   FC=ftn
   MPI_BIN=$(dirname $(which ${CC}))
   SHARED=OFF
elif [ "${MPI}" == "ON" ]
then
   if [ "${USE_SRUN}" == "ON" ]
   then
       MPI_EXEC=$(which srun)
       MPI_SYMBOLS="-D MPI_EXEC=${MPI_EXEC} -D MPI_EXEC_NUMPROCS_FLAG=-N"
       MPI_BIN=$(dirname "${MPI_EXEC}")
   else
       MPI_EXEC=$(which mpiexec)
       MPI_SYMBOLS="-D MPI_EXEC=${MPI_EXEC}"
       MPI_BIN=$(dirname "${MPI_EXEC}")
   fi
   CXX=mpicxx
   CC=mpicc
   FC=mpif77
fi

OS=$(uname -s)
if [ "$SHARED" == "ON" ]
then
    if [ "$OS" == "Darwin" ] ; then
	LD_EXT="dylib"
    else
	LD_EXT="so"
    fi
else
    LD_EXT="a"
fi

if [ "${HAVE_KOKKOS}" == "ON" ]
then
    KOKKOS_SYMBOLS="-DKOKKOS_SRC_PATH:PATH=${INSTALL_PATH}/TPL/kokkos/kokkos \
		    -DTPL_Kokkos_LIBRARY_DIRS:PATH=${KOKKOS_PATH}/lib \
		    -DTPL_Kokkos_INCLUDE_DIRS:PATH=${KOKKOS_PATH}/include \
		    -DTPL_Kokkos_LIBRARIES=${KOKKOS_PATH}/lib/libkokkos.${LD_EXT}"
fi

if [ "${HAVE_DATAWAREHOUSE}" == "ON" ]
then
    DW_SYMBOLS="-DTPL_ENABLE_DATAWAREHOUSE:BOOL=${HAVE_DATAWAREHOUSE} \
                -DDataWarehouse_LIBRARY_DIRS:PATH=${DATAWAREHOUSE_PATH}/lib \
                -DDataWarehouse_INCLUDE_DIRS:PATH=${DATAWAREHOUSE_PATH}/include"
fi

if [ "$OS" == "Darwin" ] ; then
  DARWIN_OPT="-D CMAKE_MACOSX_RPATH:BOOL=ON -D TPL_X11_INCLUDE_DIRS:PATH=/opt/X11/include"
else
  DARWIN_OPT=""
fi

# Only run doxygen if me and on master branch...
DOXYGEN=${DOXYGEN:-OFF}
if [[ "$DOXYGEN" == "OFF" && "$OS" == "Darwin" && "$MPI" == "OFF" ]] ; then
    branch=$(git branch |grep \* |cut -c3-)
    USER=$(id -nu)
    if [ "$USER" == "gdsjaar" ] && [ "$branch" == "master" ]; then
	DOXYGEN=ON
    fi
fi

FC=${FC:-gfortran}

EXTRA_WARNINGS=${EXTRA_WARNINGS:-NO}
SANITIZER=${SANITIZER:-NO}

if [ "$SANITIZER" != "NO" ] ; then
### To use the clang sanitizers:
#sanitizer=address     #: AddressSanitizer, a memory error detector.
#sanitizer=integer     #: Enables checks for undefined or suspicious integer behavior.
#sanitizer=thread      #: ThreadSanitizer, a data race detector.
#sanitizer=memory      #: MemorySanitizer, experimental detector of uninitialized reads.
#sanitizer=undefined   #: Fast and compatible undefined behavior checker.
#sanitizer=dataflow    #: DataFlowSanitizer, a general data flow analysis.
#sanitizer=cfi         #: control flow integrity checks. Requires -flto.
#sanitizer=safe-stack  #: safe stack protection against stack-based memory corruption errors.
SANITIZE="-fsanitize=${SANITIZER} -fno-omit-frame-pointer -fPIC"
fi
### You can add these below if you want more verbosity...
#-D CMAKE_VERBOSE_MAKEFILE:BOOL=ON \
#-D SEACASProj_VERBOSE_CONFIGURE=ON \

### You can add these below to regenerate the flex and bison files for
### aprepro and aprepro_lib May have to touch aprepro.l aprepro.y
### aprepro.ll and aprepro.yy to have them regenerate
#-D GENERATE_FLEX_FILES=ON \
#-D GENERATE_BISON_FILES=ON \

if [ "$EXTRA_WARNINGS" == "YES" ] ; then
### Additional gcc warnings:
if [ "$COMPILER" == "gnu" ]
then
  COMMON_WARNING_FLAGS="\
   -Wshadow -Wabsolute-value -Waddress -Waliasing -Wpedantic\
  "

  C_WARNING_FLAGS="${COMMON_WARNING_FLAGS}"

  CXX_WARNING_FLAGS="${COMMON_WARNING_FLAGS} -Wnull-dereference -Wzero-as-null-pointer-constant -Wuseless-cast -Weffc++ -Wsuggest-override"

  # -Wuseless-cast
  # -Wold-style-cast
  # -Wdouble-promotion
fi
if [ "$COMPILER" == "clang" ]
then
  C_WARNING_FLAGS="-Weverything -Wno-missing-prototypes -Wno-sign-conversion -Wno-reserved-id-macro"

  CXX_WARNING_FLAGS="-Weverything -Wno-c++98-compat -Wno-old-style-cast -Wno-sign-conversion -Wno-reserved-id-macro"
fi
fi

rm -f CMakeCache.txt
###------------------------------------------------------------------------
cmake -G "${GENERATOR}" \
-D CMAKE_CXX_COMPILER:FILEPATH=${CXX} \
-D CMAKE_C_COMPILER:FILEPATH=${CC} \
-D CMAKE_Fortran_COMPILER:FILEPATH=${FC} \
-D CMAKE_CXX_FLAGS="${CXXFLAGS} ${CXX_WARNING_FLAGS} ${SANITIZE}" \
-D CMAKE_C_FLAGS="${CFLAGS} ${C_WARNING_FLAGS} ${SANITIZE}" \
-D CMAKE_FORTRAN_FLAGS="${FFLAGS} ${F77_WARNING_FLAGS} ${SANITIZE}" \
-D SEACASProj_ENABLE_STRONG_C_COMPILE_WARNINGS=${EXTRA_WARNINGS} \
-D SEACASProj_ENABLE_STRONG_CXX_COMPILE_WARNINGS=${EXTRA_WARNINGS} \
-D CMAKE_INSTALL_RPATH:PATH=${INSTALL_PATH}/lib \
-D BUILD_SHARED_LIBS:BOOL=${SHARED} \
-D CMAKE_BUILD_TYPE=${BUILD_TYPE} \
${SUBSET_OPTIONS} \
-D SEACASProj_ENABLE_Zoltan:BOOL=${ZOLTAN} \
-D SEACASProj_ENABLE_TESTS=ON \
-D CMAKE_INSTALL_PREFIX:PATH=${INSTALL_PATH} \
-D SEACASProj_SKIP_FORTRANCINTERFACE_VERIFY_TEST:BOOL=ON \
-D SEACASProj_HIDE_DEPRECATED_CODE:BOOL=${OMIT_DEPRECATED_CODE} \
-D SEACASProj_ENABLE_DOXYGEN:BOOL=${DOXYGEN} \
-D SEACASProj_ENABLE_Fortran=${FORTRAN} \
\
-D TPL_ENABLE_Netcdf:BOOL=${HAVE_NETCDF} \
-D TPL_ENABLE_Matio:BOOL=${HAVE_MATIO} \
-D TPL_ENABLE_CGNS:BOOL=${HAVE_CGNS} \
-D TPL_ENABLE_ADIOS2:BOOL=${HAVE_ADIOS2} \
-D TPL_ENABLE_gtest:BOOL=${HAVE_GTEST} \
-D TPL_ENABLE_Kokkos:BOOL=${HAVE_KOKKOS} \
-D TPL_ENABLE_MPI:BOOL=${MPI} \
-D TPL_ENABLE_Pamgen:BOOL=OFF \
-D TPL_ENABLE_Pthread:BOOL=${THREADSAFE} \
${THREAD_SAFE_OPT} \
-D TPL_ENABLE_X11:BOOL=${HAVE_X11} \
\
-D SEACASExodus_ENABLE_THREADSAFE:BOOL=${THREADSAFE} \
-D SEACASIoss_ENABLE_THREADSAFE:BOOL=${THREADSAFE} \
\
${KOKKOS_SYMBOLS} \
${MPI_SYMBOLS} \
${DW_SYMBOLS} \
${DARWIN_OPT} \
\
-D MPI_BIN_DIR:PATH=${MPI_BIN} \
-D NetCDF_ROOT:PATH=${NETCDF_PATH} \
-D HDF5_ROOT:PATH=${HDF5_PATH} \
-D HDF5_NO_SYSTEM_PATHS=ON \
-D CGNS_ROOT:PATH=${CGNS_PATH} \
-D Matio_ROOT:PATH=${MATIO_PATH} \
-D PNetCDF_ROOT:PATH=${PNETCDF_PATH} \
-D PythonInterp_FIND_VERSION:STRING=${PYTHON_VER} \
\
$EXTRA_ARGS \
${ACCESS}

echo ""
echo "          OS: ${OS}"
echo "      ACCESS: ${ACCESS}"
echo "INSTALL_PATH: ${INSTALL_PATH}"
echo "  "
echo "         CC: ${CC}"
echo "        CXX: ${CXX}"
echo "         FC: ${FC}"
echo "        MPI: ${MPI}"
echo "     SHARED: ${SHARED}"
echo " BUILD_TYPE: ${BUILD_TYPE}"
echo " THREADSAFE: ${THREADSAFE}"
echo " PYTHON_VER: ${PYTHON_VER}"
echo " "
echo "     NETCDF: ${HAVE_NETCDF}"
echo "      MATIO: ${HAVE_MATIO}"
echo "       CGNS: ${HAVE_CGNS}"
echo "     KOKKOS: ${HAVE_KOKKOS}"
echo "     ZOLTAN: ${ZOLTAN}"
echo "     ADIOS2: ${HAVE_ADIOS2}"
echo "      GTEST: ${HAVE_GTEST}"
echo "    DOXYGEN: ${DOXYGEN}"
echo ""

if [ "${TRAVIS}" == "true" ]
then
  make -j2
  cd ${ACCESS}
fi
