#!/bin/sh
#
# configure for the Uno R package.
#
# Builds the Uno static library (and, in later milestones, its HiGHS QP/LP
# subproblem solver) from source via CMake, then generates src/Makevars.

R_UNO_PKG_HOME=`pwd`

: ${R_HOME=`R RHOME`}
if test -z "${R_HOME}"; then
    echo "'R_HOME' could not be found!"
    exit 1
fi

# Locate the MUMPS C API headers of the 'rmumps' package. build_uno.sh compiles
# Uno's MUMPSSolver.cpp against them (header-only; NO MUMPS library is linked):
# the dmumps_c entry point is bound at load time by src/dmumps_shim.c to the
# C-callables rmumps registers. Two generations of rmumps are supported:
#   * rmumps >= 5.2.1-44 installs <rmumps/rmumps_api.h> (-DUNO_RMUMPS_API): the
#     shim uses the entry points named after the DMUMPS_STRUC_C layout it was
#     compiled against (RMUMPS_DMUMPS_ABI), so a layout mismatch is a clean
#     load-time error; rmumps 5.9.1-1 brings MUMPS 5.9.1 this way;
#   * rmumps <= 5.2.1-43 has only the top-level dmumps_c.h: the legacy "dmumps_c"
#     callable and the MUMPS 5.2.1 layout.
# This enables the interior-point ("ipopt") preset. Skip with R_UNO_NO_MUMPS=1
# (filtersqp/HiGHS only; -DUNO_R_NO_MUMPS tells the shim).
RUNO_MUMPS_CPPFLAGS="-DUNO_R_NO_MUMPS"
if test -z "${R_UNO_NO_MUMPS}"; then
    RMUMPS_INC=`"${R_HOME}/bin/Rscript" -e 'cat(system.file("include", package="rmumps"))'`
    if test -n "${RMUMPS_INC}" && test -f "${RMUMPS_INC}/rmumps/rmumps_api.h"; then
        export MUMPS_R_INCLUDE_DIRS="${RMUMPS_INC}/rmumps"
        RUNO_MUMPS_CPPFLAGS="-DUNO_RMUMPS_API"
        echo "MUMPS headers (rmumps, versioned C interface): ${MUMPS_R_INCLUDE_DIRS}"
    elif test -n "${RMUMPS_INC}" && test -f "${RMUMPS_INC}/dmumps_c.h"; then
        export MUMPS_R_INCLUDE_DIRS="${RMUMPS_INC}"
        RUNO_MUMPS_CPPFLAGS=""
        echo "MUMPS headers (rmumps, legacy dmumps_c): ${MUMPS_R_INCLUDE_DIRS}"
    else
        echo "rmumps headers not found (looked in '${RMUMPS_INC}')."
        echo "Install 'rmumps' (>= 5.2.1-43), or set R_UNO_NO_MUMPS=1 to build without MUMPS."
        exit 1
    fi
fi

# Generate src/uno_status_names.h from the bundled C API header, so the status
# labels the binding returns follow Uno's enums (tools/gen_status_table.R).
"${R_HOME}/bin/Rscript" tools/gen_status_table.R \
    inst/uno/interfaces/C/Uno_C_API.h src/uno_status_names.h \
    || { echo "Generating src/uno_status_names.h failed!"; exit 1; }

# Build the HiGHS QP/LP subproblem solver (static libhighs.a) from source.
# This enables Uno's SQP presets (e.g. filtersqp). Skip with R_UNO_NO_HIGHS=1.
HIGHS_PKG_LIBS=""
HIGHS_CPPFLAGS=""
if test -z "${R_UNO_NO_HIGHS}"; then
    bash inst/build_highs.sh || { echo "HiGHS build failed!"; exit 1; }
    cd "${R_UNO_PKG_HOME}"
    R_HIGHS_LIB_DIR=${R_UNO_PKG_HOME}/src/highslib
    # Tell build_uno.sh to compile Uno with HAS_HIGHS + the HiGHSSolver sources.
    export HIGHS_LIB="${R_HIGHS_LIB_DIR}/lib/libhighs.a"
    HIGHS_PKG_LIBS="-L${R_HIGHS_LIB_DIR}/lib -lhighs"
    HIGHS_CPPFLAGS="-I${R_HIGHS_LIB_DIR}/include -I${R_HIGHS_LIB_DIR}/include/highs"
fi

# Build the Uno static library (src/unolib/{lib,include}).
bash inst/build_uno.sh || { echo "Uno build failed!"; exit 1; }
cd "${R_UNO_PKG_HOME}"

# The static libraries (src/highslib, src/unolib) are now built; the binding
# links the built libs+headers, not the bundled HiGHS/Uno SOURCE trees.  Those
# trees live under inst/ (not src/) so R CMD check's src-only pragma/line-ending
# scans never see the vendored third-party files.  They are kept OUT of the
# *installed* package via the top-level .Rinstignore (patterns /HiGHS, /uno, and
# /build_.*\.sh$), per CRAN's request -- NOT by deleting them from the extracted
# tarball here (which also avoids ever touching a developer's submodule checkout
# during an in-place `R CMD INSTALL .`).  See Writing R Extensions, ".Rinstignore".

# Remove the intermediate CMake build trees: the libraries are installed under
# src/highslib and src/unolib, so the build dirs are dead weight, and their
# CMake-generated Makefiles carry CRLF line endings on Windows -> R CMD check
# "line endings in Makefiles" WARNING.
rm -rf highs_build uno_build

# Normalize the installed HiGHS/Uno headers so R CMD check stays quiet:
#   * strip CRLF -> LF  (Windows CMake emits CRLF -> "line endings in sources" NOTE)
#   * ensure a trailing newline  (some upstream headers ship without one ->
#     "sources/headers not terminated with a newline" NOTE)
# The trailing-newline test: $(tail -c1 f) strips a final LF in command
# substitution, so it is non-empty exactly when the last byte is NOT a newline.
# Both passes are no-ops on already-clean files.
for incdir in src/highslib/include src/unolib/include; do
    test -d "${incdir}" || continue
    find "${incdir}" -type f -print | while read f; do
        tr -d '\r' < "$f" > "$f.tmp"
        if test -s "$f.tmp" && test -n "$(tail -c1 "$f.tmp")"; then
            printf '\n' >> "$f.tmp"
        fi
        mv "$f.tmp" "$f"
    done
done

R_UNO_LIB_DIR=${R_UNO_PKG_HOME}/src/unolib

# Link flags: the Uno static archive resolves its BLAS/LAPACK/Fortran-runtime
# externals (and HiGHS, if built) at the final package .so link.
RUNO_PKG_LIBS="-L${R_UNO_LIB_DIR}/lib -luno ${HIGHS_PKG_LIBS}"

sed -e "s|@RUNO_LIB_DIR@|${R_UNO_LIB_DIR}|g" \
    -e "s|@RUNO_PKG_LIBS@|${RUNO_PKG_LIBS}|g" \
    -e "s|@RUNO_MUMPS_CPPFLAGS@|${RUNO_MUMPS_CPPFLAGS}|g" \
    src/Makevars.in > src/Makevars

if [ -z "$(ls ${R_UNO_LIB_DIR} 2>/dev/null | grep 'include')" ]; then
    echo "Uno headers could not be found!"
    exit 1
fi
