# syntax=docker/dockerfile:1.4
# Dockerfile for base CORSIKA / sim_telarray build.
#
# Contains CORSIKA (possibly optimized; with and without curved atmosphere)
# and sim_telarray
# Requires CORSIKA and sim_telarray source code tarballs (plus tarball for
# CORSIKA optimized build) to be in the same directory as this Dockerfile.

# Shared build arguments
ARG CORSIKA_VERSION="77550"
ARG CORSIKA_OPT_PATCH_VERSION="v1.1.0"
ARG BUILD_OPT="prod6-sc"
ARG EXTRA_DEF="-DMAXIMUM_TELESCOPES=128"
ARG HADRONIC_MODEL="qgs2"
ARG AVX_FLAG="avx2"
ARG BERNLOHR_VERSION="1.68"
ARG AUTOCONF_VERSION="2.71"

#
# hadolint global ignore=DL3013,DL3033,DL3041,SC1091
# - DL3013, DL3033: ignore warnings about installing non-specific versions with microdnf or yum)
# - SC1091: ignore warning about not being able to source the bashrc

FROM almalinux:9.5 AS patches_stage
ARG CORSIKA_VERSION
ARG CORSIKA_OPT_PATCH_VERSION

RUN yum update -y && yum install -y git && \
    yum clean all && \
    rm -rf /var/cache/yum/* /tmp/* /var/tmp/*

RUN --mount=type=secret,id=gitlab_token \
    git config --global advice.detachedHead false && \
    git clone --depth 1 --branch "${CORSIKA_OPT_PATCH_VERSION}" "https://oauth2:$(cat /run/secrets/gitlab_token)@gitlab.cta-observatory.org/cta-computing/dpps/simpipe/corsika-opt-patches.git" && \
    cp -rL corsika-opt-patches/build_opt/corsikaOptPatch-$CORSIKA_VERSION/ ./corsika-patches/ && \
    rm -rf corsika-opt-patches

FROM almalinux:9.5 AS build_image
ARG BUILD_OPT
ARG EXTRA_DEF
ARG HADRONIC_MODEL
ARG AVX_FLAG
ARG CORSIKA_VERSION
ARG BERNLOHR_VERSION
ARG CORSIKA_OPT_PATCH_VERSION
ARG AUTOCONF_VERSION

ENV GCC_PATH="/usr/bin/"
ENV CORSIKA_DIR="corsika-${CORSIKA_VERSION}"

RUN yum update -y && yum install -y \
    gcc-fortran gsl-devel libgfortran \
    automake csh patch perl which bzip2 \
    wget make tar m4 && \
    yum clean all && \
    rm -rf /var/cache/yum/* /tmp/* /var/tmp/*

WORKDIR /tmp/
ADD autoconf.tar.gz /tmp/
# hadolint ignore=DL3003
RUN cd "autoconf-$AUTOCONF_VERSION" && \
    ./configure --prefix=/usr && \
    make && make install && \
    cd / && rm -rf /tmp/autoconf-*

WORKDIR /workdir/sim_telarray
COPY corsika_simtelarray.tar.gz .

RUN tar -zxf corsika_simtelarray.tar.gz && \
    tar -zxf ${CORSIKA_DIR}.tar.gz && \
    tar -zxf bernlohr-$BERNLOHR_VERSION.tar.gz -C ${CORSIKA_DIR}/bernlohr && \
    rm -f examples-with-data.tar.gz sim_telarray_config.tar.gz \
    corsika_simtelarray.tar.gz  ${CORSIKA_DIR}.tar.gz \
    bernlohr-$BERNLOHR_VERSION.tar.gz

COPY --from=patches_stage /corsika-patches ./${CORSIKA_DIR}/

# Apply patches for non-optimized / optimized CORSIKA
WORKDIR /workdir/sim_telarray/${CORSIKA_DIR}
RUN if [ "$CORSIKA_VERSION" = "77550" ]; then \
        patch -b -p0 src/corsika.F < "../corsika-77550.patch"; \
    fi && \
    if [ "$AVX_FLAG" != "generic" ]; then \
        ./corsika_opt_patching.sh && \
        autoreconf; \
    fi

# Build non-optimized / optimized CORSIKA
WORKDIR /workdir/sim_telarray
# hadolint ignore=DL3003
RUN for variant in curved ""; do \
        (cd ./${CORSIKA_DIR} && \
        if [ "$AVX_FLAG" = "generic" ] || [ "$variant" = "curved" ]; then \
            ../corsika_build_script "$HADRONIC_MODEL" generic $variant; \
        else \
            ../corsika_build_script "$HADRONIC_MODEL" generic cerenkopt vlibm $variant; \
        fi) && \
        make -C "${CORSIKA_DIR}" clean && rm -f ./*/*.a lib/*/*.a && \
        AVX_EXTRA_FLAG=$([ "$AVX_FLAG" = "avx512f" ] && echo "-ffp-contract=off" || echo "") && \
        C_SPECIFIC_FLAGS="-std=c99" && \
        FORTRAN_SPECIFIC_FLAGS="-ffixed-line-length-132 -fno-automatic -frecord-marker=4 -std=legacy" && \
        if [ "$AVX_FLAG" = "generic" ] || [ "$variant" = "curved" ]; then \
            BASE_FLAGS="-g -O3"; \
        else \
            BASE_FLAGS="-g -DCERENKOPT -DVLIBM -O3 ${AVX_FLAG:+-m$AVX_FLAG} ${AVX_EXTRA_FLAG} -DVECTOR_SIZE=8 -DVECTOR_LENGTH=8"; \
        fi && \
        CFLAGS="${BASE_FLAGS} ${C_SPECIFIC_FLAGS}" && \
        CXXFLAGS="${BASE_FLAGS} ${C_SPECIFIC_FLAGS}" && \
        FFLAGS="${BASE_FLAGS} ${FORTRAN_SPECIFIC_FLAGS}" && \
        make -C "${CORSIKA_DIR}" \
            CC="${GCC_PATH}/gcc -static" \
            CXX="${GCC_PATH}/g++ -static" \
            CPP="${GCC_PATH}/gcc -static -E" \
            F77="${GCC_PATH}/gfortran -L/lib64/" \
            CFLAGS="${CFLAGS}" \
            CXXFLAGS="${CXXFLAGS}" \
            FFLAGS="${FFLAGS}" \
            install && \
        echo "=== Listing ${CORSIKA_DIR}/run/ after install (variant: $variant) ===" && \
        ls -la "${CORSIKA_DIR}/run/" && \
        mkdir -p corsika-run && \
        if [ "$variant" = "curved" ]; then \
            mv -v -f "${CORSIKA_DIR}/run/corsika${CORSIKA_VERSION}Linux_"* "corsika-run/corsika-$variant" && \
            cp -v -f "${CORSIKA_DIR}/src/corsikacompilefile.f" "corsika-run/corsikacompilefile_$variant.f" && \
            echo "=== After curved variant copy, corsika-run contains: ===" && \
            ls -la corsika-run/; \
        else \
            mv -v -f "${CORSIKA_DIR}/run/corsika${CORSIKA_VERSION}Linux_"* "corsika-run/corsika" && \
            cp -v -f "${CORSIKA_DIR}/src/corsikacompilefile.f" "corsika-run/corsikacompilefile.f" && \
            echo "=== After non-curved variant copy, corsika-run contains: ===" && \
            ls -la corsika-run/; \
        fi && \
        if [ "$variant" = "" ]; then \
            if [ -d "${CORSIKA_DIR}/run/" ]; then \
                cp -r -v "${CORSIKA_DIR}/run/"* corsika-run/; \
            else \
                echo "Skipping copy: source directory ${CORSIKA_DIR}/run/ does not exist."; \
            fi; \
        fi; \
    done

# Build sim_telarray (with and without debug options)
RUN touch ${CORSIKA_DIR}.tar.gz && \
    # build with debug options; move binary to temporary location (to avoid being purged in next step)
    export NO_CORSIKA=1 EXTRA_DEFINES="${EXTRA_DEF} -DDEBUG_TRACE_99" && ./build_all $BUILD_OPT $HADRONIC_MODEL gsl && \
    mv /workdir/sim_telarray/sim_telarray/sim_telarray \
       /workdir/sim_telarray/sim_telarray/sim_telarray_debug_trace && \
    # build without debug options; move debug option binary back to sim_telarray/bin
    export NO_CORSIKA=1 EXTRA_DEFINES="${EXTRA_DEF}" && ./build_all $BUILD_OPT $HADRONIC_MODEL gsl && \
    mv /workdir/sim_telarray/sim_telarray/sim_telarray_debug_trace \
       /workdir/sim_telarray/sim_telarray/bin/sim_telarray_debug_trace

# Cleanup.
# CORSIKA source code is removed to follow
# the CORSIKA non-distribution policy.
RUN rm -rf ./${CORSIKA_DIR}* && \
    find . -name "*.tar.gz" -delete && \
    find . -name "doc*" -type d -exec rm -rf "{}" + 2>/dev/null && \
    find . -name "*.o" -delete && \
    rm -rf /var/cache/yum/* /tmp/* /var/tmp/* && \
    rm -f build_all clean_all corsika_build_script init_batch_job_SGE && \
    rm -f new_export test_build_all && \
    rm -rf ./sim_telarray/cfg ./lib ./include && \
    rm -f ./example_scripts/Prod6/'*'

# Use QGSJet tables downloaded externally (overwrite any existing copies)
WORKDIR /workdir/sim_telarray/corsika-run
COPY qgsdat-II-04.bz2 .
COPY qgsdat-III.bz2 .
RUN if [ "$HADRONIC_MODEL" = "qgs3" ]; then \
        if [ -f qgsdat-III.bz2 ]; then \
            bzip2 -dq qgsdat-III.bz2; \
        fi; \
        rm -f -v qgsdat-II-04.bz2; \
    fi && \
    if [ "$HADRONIC_MODEL" = "qgs2" ]; then \
        if [ -f qgsdat-II-04.bz2 ]; then \
            bzip2 -dq qgsdat-II-04.bz2; \
        fi; \
        rm -f -v qgsdat-III.bz2; \
    fi

# Add a yml file in workdir with the build options
WORKDIR /workdir/sim_telarray
RUN echo "build_opt: $BUILD_OPT" > ./build_opts.yml && \
    echo "extra_def: $EXTRA_DEF" >> ./build_opts.yml && \
    echo "hadronic_model: $HADRONIC_MODEL" >> ./build_opts.yml && \
    echo "avx_flag: $AVX_FLAG" >> ./build_opts.yml && \
    echo "corsika_version: $CORSIKA_VERSION" >> ./build_opts.yml && \
    echo "corsika_opt_patch_version: $CORSIKA_OPT_PATCH_VERSION" >> ./build_opts.yml && \
    echo "bernlohr_version: $BERNLOHR_VERSION" >> ./build_opts.yml

# Final stage - minimal base image with CORSIKA and sim_telarray
FROM almalinux:9.5-minimal
COPY --from=build_image /workdir/sim_telarray/ /workdir/sim_telarray/
WORKDIR /workdir

RUN microdnf update -y && microdnf install -y \
    bc \
    zstd \
    gsl-devel \
    gcc-fortran \
    procps \
    findutils \
    gcc-c++ \
    libgfortran && \
    microdnf clean all && \
    rm -rf /var/cache/dnf/* /tmp/* /var/tmp/*

ENV SIMTEL_PATH="/workdir/sim_telarray"
