#!/bin/sh
set -e

ZLIB_VER="1.3.1"
HDF5_VER="2.0.0"

echo "--- [hdf5lib] Starting Configuration (Static) ---"

# 1. Environment Setup ---------------------------------------------------------

# Locate R and ensure it exists
R_EXE="${R_HOME}/bin${R_ARCH_BIN}/R"
if [ ! -f "$R_EXE" ]; then
  R_EXE="${R_HOME}/bin/R"
  if [ ! -f "$R_EXE" ]; then
    R_EXE=$(which R 2>/dev/null || true)
    if [ -z "$R_EXE" ]; then
      echo "Error: R not found. Please ensure R is installed and in your PATH."
      exit 1
    fi
  fi
fi

# Detect OS (Windows vs Unix) for logic branching
case "$(uname -s)" in
  CYGWIN*|MINGW*|MSYS*) WIN=1; EXE=".exe" ;;
  *)                    WIN=0; EXE=""     ;;
esac


# 2. R Configuration Inspection ------------------------------------------------
# Fetch compilation flags from R to ensure binary compatibility
R_CC=$("$R_EXE" CMD config CC)
R_CFLAGS=$("$R_EXE" CMD config CFLAGS)
R_CPICFLAGS=$("$R_EXE" CMD config CPICFLAGS)
R_CPPFLAGS=$("$R_EXE" CMD config CPPFLAGS)
R_LDFLAGS=$("$R_EXE" CMD config LDFLAGS)
R_AR=$("$R_EXE" CMD config AR)
R_MAKE=$("$R_EXE" CMD config MAKE)

# Set defaults if R config returns empty
: "${R_AR:=ar}"
: "${R_MAKE:=make}"

# Construct final flags
# Add optimization flag if not already present
export CC="$R_CC"
case " $R_CFLAGS " in
  *" -O"*) export CFLAGS="$R_CFLAGS $R_CPICFLAGS" ;;
  *)       export CFLAGS="$R_CFLAGS $R_CPICFLAGS -O2" ;;
esac


# --- 2b. Capture Runtime/Linker Flags (e.g. Sanitizers) ---
# We need to propagate flags like -fsanitize=address to consumer packages
# so they can successfully link against our static library.

mkdir -p inst
for flag in $R_CFLAGS $R_LDFLAGS; do
  case "$flag" in
    -fsanitize=*) echo "$flag" >> inst/exported_flags.txt ;;
  esac
done

# 3. Build ZLIB ----------------------------------------------------------------
echo "--- [hdf5lib] Decompressing sources..."
mkdir build
cd build

tar -xf "../src/zlib-$ZLIB_VER.tar.gz"
tar -xf "../src/hdf5-$HDF5_VER.tar.gz"
cp ../src/H5pubconf.h        "hdf5-$HDF5_VER/src/"
cp ../src/find_byte_widths.c "hdf5-$HDF5_VER/"

echo "--- [hdf5lib] Building ZLIB..."
cd "zlib-$ZLIB_VER"
export CPPFLAGS="-I. $R_CPPFLAGS"
export LDFLAGS="$R_LDFLAGS"
export AR="$R_AR"
echo "  CC:       $CC"
echo "  CFLAGS:   $CFLAGS"
echo "  LDFLAGS:  $LDFLAGS"
echo "  AR:       $AR"

if [ "$WIN" -eq 1 ]; then
  "$R_MAKE" -f win32/Makefile.gcc libz.a >/dev/null
else
  chmod +x ./configure
  ./configure --static >/dev/null
  "$R_MAKE" libz.a >/dev/null
fi

# Extract ZLIB objects to merge them into the final library
rm *.o
"$R_AR" -x libz.a

cd ..


# 4. Build HDF5 ----------------------------------------------------------------
echo "--- [hdf5lib] Building HDF5..."
cd "hdf5-$HDF5_VER"

# A. Generators
# Compile and run generator to detect system type sizes (creates src/H5_byte_widths.h)
# Use unquoted $CC to allow arguments like -std=gnu11
$CC $CPPFLAGS $CFLAGS -o find_byte_widths$EXE ./find_byte_widths.c
./find_byte_widths$EXE | tr -d '\r' > src/H5_byte_widths.h

# B. Compilation
# Use the pre-generated Makefile (from prep_hdf5.r) to build all objects
# Explicitly passing CC/CFLAGS overrides the defaults in the Makefile
"$R_EXE" -s -e "invisible(file.copy(R.home('include'), '.', recursive = TRUE))"

# Define base flags
CPPFLAGS="-Isrc -Ihl/src -I../zlib-$ZLIB_VER -Iinclude $R_CPPFLAGS"
CPPFLAGS="$CPPFLAGS -DH5_BUILT_AS_STATIC_LIB -DH5_DLL= -DH5HL_DLL="

echo "  CC:       $CC"
echo "  CFLAGS:   $CFLAGS"
echo "  CPPFLAGS: $CPPFLAGS"

for src in src/*.c hl/src/*.c; do
  obj=$(basename "$src" .c).o
  echo "  \$CC \$CFLAGS \$CPPFLAGS -c $src -o $obj"
  $CC $CFLAGS $CPPFLAGS -c "$src" -o "$obj"
done

cd ..


# 5. Link and Archive ----------------------------------------------------------
echo "--- [hdf5lib] Linking static library..."

# Detect LTO and rchk/wllvm
# The MINIFY variable is a flag indicating the absence of both Link Time
# Optimization (LTO) and the wllvm compiler (used by rchk). LTO objects
# contain bytecode that standard 'strip' and 'ld -r' often corrupt, so we
# skip size-reduction steps if -flto or wllvm is detected.
MINIFY=1
case "$CFLAGS" in
  *-flto*) MINIFY=0 ;;
esac
case "$CC" in
  *wllvm*) MINIFY=0 ;;
esac

# Create the final static library
# Logic: Use partial linking (ld -r) on non-Windows systems to reduce size.
if [ "$WIN" -eq 0 ] && [ "$MINIFY" -eq 1 ] && command -v ld >/dev/null 2>&1; then
  echo "  Performing partial linking (ld -r)..."
  # Merge all .o files into one big object (deduplicates symbols/sections)
  ld -r -o libhdf5z.o "hdf5-$HDF5_VER/"*.o "zlib-$ZLIB_VER/"*.o
  "$R_AR" -crs libhdf5z.a libhdf5z.o
else
  "$R_AR" -crs libhdf5z.a "hdf5-$HDF5_VER/"*.o "zlib-$ZLIB_VER/"*.o
fi

# Strip debug symbols to reduce installed package size
if [ "$MINIFY" -eq 1 ] && command -v strip >/dev/null 2>&1; then
  echo "  Stripping debug symbols..."
  strip -S libhdf5z.a || true
fi


# 6. Installation --------------------------------------------------------------
echo "--- [hdf5lib] Installing..."
cd ..

# Install headers and library
mkdir -p inst/lib inst/include
cp build/"hdf5-$HDF5_VER"/src/*.h    inst/include/
cp build/"hdf5-$HDF5_VER"/hl/src/*.h inst/include/
cp build/libhdf5z.a                  inst/lib/

# Cleanup
rm -rf src build

echo "  Final install size: $(du -sh inst/ | cut -f1)"

echo "--- [hdf5lib] Done. ---"
exit 0
