name: CMake

on:
  push:
  
  pull_request:
    branches:
      - master

    paths-ignore:
      - 'doc/**'
      - '!doc/CMakeLists.txt'
      - '!doc/Makefile.am'
      - 'README.md'

  schedule:
    - cron:  '15 14 4,11,18,25 * *'
  
  workflow_dispatch:

env:
  # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
  BUILD_TYPE: Release
  NAME: IPhreeqc

jobs:

  init:
    runs-on: ubuntu-latest
    # Map step outputs to job outputs
    outputs:
      VER: ${{ steps.vars.outputs.VER }}
      REL: ${{ steps.vars.outputs.REL }}
      DATE: ${{ steps.vars.outputs.DATE }}
      DATE_RFC_3339: ${{ steps.vars.outputs.DATE_RFC_3339 }}
    steps:
      - name: Setup vars
        id: vars
        run: |
          echo VER=$(curl -sS https://raw.githubusercontent.com/usgs-coupled/phreeqc-version/main/next_ver.sh | sh) >> $GITHUB_OUTPUT
          echo REL=$(curl -sS https://raw.githubusercontent.com/usgs-coupled/phreeqc-version/main/rel.py | python3) >> $GITHUB_OUTPUT
          echo DATE=$(date "+%x")                                                                                   >> $GITHUB_OUTPUT
          echo DATE_RFC_3339=$(date --rfc-3339=date)                                                                >> $GITHUB_OUTPUT


  test:
    strategy:
      fail-fast: false
      matrix:
        os: [macos-latest, ubuntu-latest, windows-latest]

    runs-on: ${{ matrix.os }}
    env:
      BUILD_DIR: _ctest  # set in ctest.cmake

    steps:
    - uses: actions/checkout@v4

    - name: Install ninja valgrind (Linux)
      if: runner.os == 'Linux'
      run: sudo apt-get update && sudo apt-get install -y ninja-build valgrind

    - name: Install ninja (macOS)
      if: runner.os == 'macOS'
      run: brew install ninja

    - name: Set up Visual Studio shell (Windows)
      if: runner.os == 'Windows'
      uses: egor-tensin/vs-shell@v2
      with:
        arch: x64

    - name: CTest
      run: ctest -S ctest.cmake -V --output-on-failure --timeout 900

    - name: Upload results
      uses: actions/upload-artifact@v4
      with:
        name: ${{ matrix.os }}-${{ github.job }}-results
        path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/Testing/

  test-shared:
    strategy:
      fail-fast: false
      matrix:
        os: [macos-latest, ubuntu-latest, windows-latest]

    runs-on: ${{ matrix.os }}
    env:
      BUILD_DIR: _ctest_shared  # set in ctest-shared.cmake

    steps:
    - uses: actions/checkout@v4

    - name: Install ninja valgrind (Linux)
      if: runner.os == 'Linux'
      run: sudo apt-get update && sudo apt-get install -y ninja-build valgrind

    - name: Install ninja (macOS)
      if: runner.os == 'macOS'
      run: brew install ninja

    - name: Set up Visual Studio shell (Windows)
      if: runner.os == 'Windows'
      uses: egor-tensin/vs-shell@v2
      with:
        arch: x64

    - name: CTest
      run: ctest -S ctest-shared.cmake -V --output-on-failure --timeout 900

    - name: Upload results
      uses: actions/upload-artifact@v4
      with:
        name: ${{ matrix.os }}-${{ github.job }}-results
        path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/Testing/

  test-clang:
    strategy:
      fail-fast: false
      matrix:
        os: [macos-latest, ubuntu-latest, windows-latest]
        shared_libs: [OFF, ON]
        enable_module: [OFF, ON]

    runs-on: ${{ matrix.os }}
    env:
      BUILD_DIR: _build

    steps:
    - uses: actions/checkout@v4

    - name: Install ninja valgrind (Linux)
      if: runner.os == 'Linux'
      run: sudo apt-get update && sudo apt-get install -y ninja-build clang valgrind

    - name: Install ninja (macOS)
      if: runner.os == 'macOS'
      run: brew install ninja

    - name: Set up Visual Studio shell (Windows)
      if: runner.os == 'Windows'
      uses: egor-tensin/vs-shell@v2
      with:
        arch: x64

    - name: CMake configure
      if: runner.os == 'Linux'
      run: CC=clang CXX=clang++ cmake -B ${{ env.BUILD_DIR }} -DBUILD_SHARED_LIBS=${{ matrix.shared_libs }} -DIPHREEQC_ENABLE_MODULE=${{ matrix.enable_module }} -DCMAKE_CXX_STANDARD=20 -DCMAKE_CXX_STANDARD_REQUIRED=ON

    - name: CMake configure
      if: runner.os == 'macOS'
      run: CC=$(brew --prefix llvm@15)/bin/clang CXX=$(brew --prefix llvm@15)/bin/clang++ cmake -B ${{ env.BUILD_DIR }} -DBUILD_SHARED_LIBS=${{ matrix.shared_libs }} -DIPHREEQC_ENABLE_MODULE=${{ matrix.enable_module }} -DCMAKE_CXX_STANDARD=20 -DCMAKE_CXX_STANDARD_REQUIRED=ON

    - name: CMake configure
      if: runner.os == 'Windows'
      run: cmake -B ${{ env.BUILD_DIR }} -A x64 -T "ClangCL" -DBUILD_SHARED_LIBS=${{ matrix.shared_libs }} -DIPHREEQC_ENABLE_MODULE=${{ matrix.enable_module }} -DCMAKE_CXX_STANDARD=20 -DCMAKE_CXX_STANDARD_REQUIRED=ON

    - name: CMake build
      run: cmake --build ${{ env.BUILD_DIR }}

    - name: CTest
      run: ctest --test-dir ${{ env.BUILD_DIR }}
  
    - name: Upload results
      uses: actions/upload-artifact@v4
      with:
        name: ${{ matrix.os }}-${{ github.job }}-SHARED=${{ matrix.shared_libs }}-MODULE=${{ matrix.enable_module }}-results
        path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/Testing/

  chm:
    runs-on: windows-latest

    steps:
      - name: Checkout phreeqc3-HTMLversion
        uses: actions/checkout@v4
        with:
          repository: usgs-coupled-subtrees/phreeqc3-HTMLversion
          ref: master

      - name: cache htmlhelp
        id: cache-htmlhelp
        uses: actions/cache@v4
        with:
          path: "C:/Program Files (x86)/HTML Help Workshop"
          key: ${{ runner.os }}-htmlhelp

      - name: install htmlhelp
        if: steps.cache-htmlhelp.outputs.cache-hit != 'true'
        timeout-minutes: 5
        run: |
          curl -L -O --max-time 120 http://web.archive.org/web/20160201063255/http://download.microsoft.com/download/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe
          cmd /c start /wait .\htmlhelp.exe /q /c /t:$(Get-Location)\tmp
          $file = "$(Get-Location)\tmp\htmlhelp.inf"
          (Get-Content $file) | Foreach-Object { $_ `
            -replace '^BeginPrompt',                                               ';;BeginPrompt' `
            -replace '^EndPrompt',                                                 ';;EndPrompt' `
            -replace '^49000=CustomLDID49000, 1',                                  '49000=CustomLDID49000, 5' `
            -replace '^"hhupd.exe',                                                ';;hhupd.exe' `
            -replace '^DefaultInstallDir="C:\\Program Files\\HTML Help Workshop"', 'DefaultInstallDir="%ProgramFiles%\\HTML Help Workshop"'
          } | Set-Content $file
          cmd /c start /wait .\tmp\setup.exe
          Remove-Item -Recurse -Force .\tmp
          Remove-Item -Recurse -Force .\htmlhelp.exe
          # the next line doesn't seem to work (supposed to set the path)
          # echo 'C:\Program Files (x86)\HTML Help Workshop' >> $GITHUB_PATH

      - name: compile chm
        shell: bash
        run: |
          pushd HTML
          bash fixup_html.bash
          popd
          # hhc returns 1 on success
          set +e
          'C:\Program Files (x86)\HTML Help Workshop\hhc' phreeqc3.hhp | tee hhc.out
          status=${PIPESTATUS[0]}
          set -e
          if [ "$status" -eq 1 ]; then
            echo "[OK]"
            exit 0
          else
            echo "[FAILED]"
            exit 1
          fi

      - uses: actions/upload-artifact@v4
        with:
          name: chm
          path: ${{github.workspace}}/phreeqc3.chm


  R-CMD-check:
    needs: [init]
    runs-on: ${{ matrix.config.os }}

    name: ${{ matrix.config.os }} (${{ matrix.config.r }})

    strategy:
      fail-fast: false
      matrix:
        config:
          - {os: macos-latest,    r: 'devel'}
          - {os: macos-latest,    r: 'release'}
          - {os: windows-latest,  r: 'devel'}
          - {os: windows-latest,  r: 'release'}
          - {os: ubuntu-latest,   r: 'devel'}
          - {os: ubuntu-latest,   r: 'release'}
          - {os: ubuntu-latest,   r: 'oldrel-1'}

    steps:
      - uses: actions/checkout@v4

      - name: versioning
        run: ./jenkins-dist.sh -v ${{ needs.init.outputs.VER }} -r ${{ needs.init.outputs.REL }} -d ${{ needs.init.outputs.DATE }}

      - name: Setup R
        uses: r-lib/actions/setup-r@v2
        with:
          r-version: ${{ matrix.config.r }}
          http-user-agent: ${{ matrix.config.http-user-agent }}
          use-public-rspm: true

      - name: create source
        working-directory: R
        run: make VERSION=${{ needs.init.outputs.VER }} RELEASE_DATE=${{ needs.init.outputs.DATE_RFC_3339 }} source

      - name: Install dependencies
        uses: r-lib/actions/setup-r-dependencies@v2
        with:
          extra-packages: any::roxygen2, any::pkgbuild, any::rcmdcheck
          needs: roxygen2, pkgbuild, check
          working-directory: R/phreeqc

      - name: Display sessionInfo()
        run: sessionInfo()
        working-directory: R/phreeqc
        shell: Rscript {0}

      - name: roxygen2::roxygenise()
        run: roxygen2::roxygenise()
        working-directory: R/phreeqc
        shell: Rscript {0}

      - name: Check
        uses: r-lib/actions/check-r-package@v2
        with:
          working-directory: R/phreeqc

      - name: List files
        if: matrix.config.os == 'ubuntu-latest' && matrix.config.r == 'release'
        run: |
          pwd
          ls -lR
          find -name "*.tar.gz"

      - uses: actions/upload-artifact@v4
        if: matrix.config.os == 'ubuntu-latest' && matrix.config.r == 'release'
        with:
          name: cran-${{ github.run_number }}
          path: |
            R/phreeqc/check/phreeqc_*.tar.gz
            R/phreeqc/check/phreeqc.Rcheck/00check.log


  # r-build:
  #   needs: [init]
  #   runs-on: ubuntu-latest
  #   steps:
  #     - uses: actions/checkout@v4

  #     - uses: r-lib/actions/setup-r@v2
  #       with:
  #         use-public-rspm: true

  #     - name: install devtools
  #       run: Rscript -e 'install.packages("devtools")'

  #     - name: install curl
  #       run: Rscript -e 'install.packages("curl")'

  #     - name: versioning
  #       run: ./jenkins-dist.sh -v ${{ needs.init.outputs.VER }} -r ${{ needs.init.outputs.REL }} -d ${{ needs.init.outputs.DATE }}

  #     - name: setup clang
  #       run: |
  #         mkdir -p ~/.R
  #         echo CC=clang -Qunused-arguments > ~/.R/Makevars
  #         echo CXX=clang++ -Qunused-arguments >> ~/.R/Makevars

  #     - name: check
  #       run: cd R && make VERSION=${{ needs.init.outputs.VER }} check_built

  #     - uses: actions/upload-artifact@v4
  #       with:
  #         name: cran
  #         path: ${{github.workspace}}/R/phreeqc_*.tar.gz


  # r-valgrind:
  #   needs: [r-build]
  #   runs-on: ubuntu-latest
  #   steps:
  #     - uses: actions/checkout@v4

  #     - uses: actions/download-artifact@v4
  #       with:
  #         name: cran
  #         path: R
    
  #     - name: Display structure of downloaded files
  #       working-directory: R
  #       run: ls -lR
      
  #     - uses: r-lib/actions/setup-r@v2
  #       with:
  #         use-public-rspm: true

  #     - name: install devtools
  #       run: Rscript -e 'install.packages("devtools")'

  #     - name: install curl
  #       run: Rscript -e 'install.packages("curl")'

  #     - name: install valgrind
  #       run: sudo apt-get install -y valgrind

  #     - name: setup clang
  #       run: |
  #         mkdir -p ~/.R
  #         echo CC=clang -Qunused-arguments > ~/.R/Makevars
  #         echo CXX=clang++ -Qunused-arguments >> ~/.R/Makevars

  #     - name: install
  #       run: cd R && R CMD INSTALL --build phreeqc_*.tar.gz

  #     - name: run
  #       run: cd R && R -d "valgrind --tool=memcheck --leak-check=full" --vanilla < valgrind.R 2>&1 | tee valgrind.full.out

  #     - uses: actions/upload-artifact@v4
  #       with:
  #         name: valgrind
  #         path: ${{github.workspace}}/R/valgrind.full.out


  distcheck:
    needs: [init, chm]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/download-artifact@v4
        with:
          name: chm

      - name: mv chm
        run: mv phreeqc3.chm doc/.

      - name: versioning
        run: ./jenkins-dist.sh -v ${{ needs.init.outputs.VER }} -r ${{ needs.init.outputs.REL }} -d ${{ needs.init.outputs.DATE }}

      - name: doxygen
        run: sudo apt-get install -y doxygen && cd doc && doxygen

      - name: autoreconf
        run: autoreconf -fvi

      - name: mkdir
        run: mkdir _build

      - name: configure
        working-directory: ${{github.workspace}}/_build
        run: ../configure --prefix=$(pwd)/INSTALL

      - name: make
        working-directory: ${{github.workspace}}/_build
        run: make -j2 distcheck

      - name: convert
        run: |
          sudo apt install -y dos2unix
          native="
          doc/Makefile \
          doc/examples/AccumulateLine.c \
          doc/examples/CreateIPhreeqc.c \
          doc/examples/F90ClearAccumulatedLines.f90 \
          doc/examples/F90CreateIPhreeqc.f90 \
          doc/examples/F90DestroyIPhreeqc.f90 \
          doc/examples/F90GetComponent.f90 \
          doc/examples/F90GetDumpStringLine.f90 \
          doc/examples/F90GetSelectedOutputValue.f90 \
          doc/examples/F90GetVersionString.f90 \
          doc/examples/GetComponent.c \
          doc/examples/GetDumpString.c \
          doc/examples/GetSelectedOutputValue.c \
          doc/examples/GetVersionString.c \
          doc/examples/IPhreeqc.cpp \
          doc/examples/Makefile \
          doc/examples/phreeqc.dat \
          src/CSelectedOutput.cpp \
          src/CSelectedOutput.hxx \
          src/CVar.hxx \
          src/Debug.h \
          src/ErrorReporter.hxx \
          src/IPhreeqc.cpp \
          src/IPhreeqc.f.inc \
          src/IPhreeqc.f90.inc \
          src/IPhreeqc.h \
          src/IPhreeqc.hpp \
          src/IPhreeqcCallbacks.h \
          src/IPhreeqcF.f \
          src/IPhreeqcLib.cpp \
          src/IPhreeqc_interface.F90 \
          src/IPhreeqc_interface_F.cpp \
          src/IPhreeqc_interface_F.h \
          src/Var.c \
          src/Var.h \
          src/Version.h \
          src/fimpl.h \
          src/fwrap.cpp \
          src/fwrap.h \
          src/fwrap1.cpp \
          src/fwrap2.cpp \
          src/fwrap3.cpp \
          src/fwrap4.cpp \
          src/fwrap5.cpp \
          src/fwrap6.cpp \
          src/fwrap7.cpp \
          src/fwrap8.cpp \
          src/pp_sys.cpp \
          src/thread.h \
          test/llnl.dat \
          test/phreeqc.dat \
          test2/Makefile \
          test2/wateq4f.dat \
          test5/Makefile \
          test5/phreeqc.dat \
          test5/test5.c \
          tests/main_fortran.cxx \
          tests/test_c.c \
          tests/test_cxx.cxx \
          tests/test_f90.F90 \
          unit/TestCVar.cpp \
          unit/TestCVar.h \
          unit/TestInterface.cpp \
          unit/TestInterface.h \
          unit/TestSelectedOutput.cpp \
          unit/TestSelectedOutput.h \
          unit/TestVar.cpp \
          unit/TestVar.h \
          unit/llnl.dat.old \
          unit/missing_e.dat \
          unit/phreeqc.dat.old \
          unit/unit.cpp"
          for f in ${native}; do
            unix2dos "${f}"
          done

      - name: dist-zip
        working-directory: ${{github.workspace}}/_build
        run: make dist-zip

      - name: copy
        run: cp doc/README IPhreeqc_ReadMe.txt

      - uses: actions/upload-artifact@v4
        with:
          name: readme
          path: ${{github.workspace}}/IPhreeqc_ReadMe.txt

      - uses: actions/upload-artifact@v4
        with:
          name: tarball
          path: ${{github.workspace}}/_build/*.tar.gz

      - uses: actions/upload-artifact@v4
        with:
          name: zipball
          path: ${{github.workspace}}/_build/*.zip

  # build:
  #   needs: [init]
  #   # The CMake configure and build commands are platform agnostic and should work equally
  #   # well on Windows or Mac.  You can convert this to a matrix build if you need
  #   # cross-platform coverage.
  #   # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
  #   runs-on: windows-2019

  #   # Check all combinations of BUILD_SHARED_LIBS and BUILD_CLR_LIBS
  #   strategy:
  #     matrix:
  #       BUILD_SHARED_LIBS: [ON, OFF]
  #       BUILD_CLR_LIBS: [ON, OFF]
  #       exclude:
  #         - BUILD_SHARED_LIBS: OFF
  #           BUILD_CLR_LIBS: ON

  #   steps:
  #   - uses: actions/checkout@v4

  #   - name: Configure CMake
  #     # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
  #     # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
  #     run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_SHARED_LIBS=${{matrix.BUILD_SHARED_LIBS}} -DBUILD_CLR_LIBS=${{matrix.BUILD_CLR_LIBS}}

  #   - name: Build
  #     # Build your program with the given configuration
  #     run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}

  #   - name: Test
  #     working-directory: ${{github.workspace}}/build
  #     # Execute tests defined by the CMake configuration.  
  #     # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
  #     run: ctest -C ${{env.BUILD_TYPE}}
