#!/usr/bin/env sh

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

# Anticonf (tm) script by Jeroen Ooms, Jim Hester (2017)
# License: MIT
#
# This script will query 'pkg-config' for the required cflags and ldflags.
# If pkg-config is unavailable or does not find the library, try setting
# INCLUDE_DIR and LIB_DIR manually via e.g:
# R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib'

# Library settings
PKG_CONFIG_NAME="arrow"
PKG_DEB_NAME="(unsuppored)"
PKG_RPM_NAME="(unsuppored)"
PKG_BREW_NAME="apache-arrow"
PKG_TEST_HEADER="<arrow/api.h>"

# Make some env vars case-insensitive
ARROW_R_DEV=`echo $ARROW_R_DEV | tr '[:upper:]' '[:lower:]'`
FORCE_AUTOBREW=`echo $FORCE_AUTOBREW | tr '[:upper:]' '[:lower:]'`
FORCE_BUNDLED_BUILD=`echo $FORCE_BUNDLED_BUILD | tr '[:upper:]' '[:lower:]'`
ARROW_USE_PKG_CONFIG=`echo $ARROW_USE_PKG_CONFIG | tr '[:upper:]' '[:lower:]'`
LIBARROW_MINIMAL=`echo $LIBARROW_MINIMAL | tr '[:upper:]' '[:lower:]'`
TEST_OFFLINE_BUILD=`echo $TEST_OFFLINE_BUILD | tr '[:upper:]' '[:lower:]'`
NOT_CRAN=`echo $NOT_CRAN | tr '[:upper:]' '[:lower:]'`

VERSION=`grep '^Version' DESCRIPTION | sed s/Version:\ //`
UNAME=`uname -s`

# generate code
if [ "$ARROW_R_DEV" = "true" ] && [ -f "data-raw/codegen.R" ]; then
  echo "*** Generating code with data-raw/codegen.R"
  ${R_HOME}/bin/Rscript data-raw/codegen.R
fi

if [ ! "`${R_HOME}/bin/R CMD config CXX17`" ]; then
  echo "------------------------- NOTE ---------------------------"
  echo "Cannot install arrow: a C++17 compiler is required."
  echo "See https://arrow.apache.org/docs/r/articles/install.html"
  echo "---------------------------------------------------------"
  exit 1
fi

if [ -f "tools/apache-arrow.rb" ]; then
  # If you want to use a local apache-arrow.rb formula, do
  # $ cp ../dev/tasks/homebrew-formulae/autobrew/apache-arrow.rb tools/apache-arrow.rb
  # before R CMD build or INSTALL (assuming a local checkout of the apache/arrow repository)
  cp tools/autobrew .
  if [ "$FORCE_AUTOBREW" != "false" ]; then
    # It is possible to turn off forced autobrew if the formula is included,
    # but most likely you shouldn't because the included formula will reference
    # the C++ library at the version that matches the R package.
    FORCE_AUTOBREW="true"
  fi
fi

if [ "$FORCE_AUTOBREW" = "true" ] || [ "$FORCE_BUNDLED_BUILD" = "true" ]; then
  ARROW_USE_PKG_CONFIG="false"
fi

S3_LIBS=""
GCS_LIBS=""
# Note that cflags may be empty in case of success
if [ "$ARROW_HOME" ] && [ "$FORCE_BUNDLED_BUILD" != "true" ]; then
  echo "*** Using ARROW_HOME as the source of libarrow"
  PKG_CFLAGS="-I$ARROW_HOME/include $PKG_CFLAGS"
  PKG_LIBS="-larrow"
  LIB_DIR="$ARROW_HOME/lib"
  PKG_DIRS="-L$LIB_DIR"
elif [ "$INCLUDE_DIR" ] && [ "$LIB_DIR" ]; then
  echo "*** Using INCLUDE_DIR/LIB_DIR as the source of libarrow"
  PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS"
  PKG_LIBS="-larrow"
  PKG_DIRS="-L$LIB_DIR"
else
  # Use pkg-config to find libarrow if available and allowed
  pkg-config --version >/dev/null 2>&1
  if [ $? -eq 0 ]; then
    PKG_CONFIG_AVAILABLE=true
  else
    PKG_CONFIG_AVAILABLE=false
  fi
  if [ "$PKG_CONFIG_AVAILABLE" = "true" ] && [ "$ARROW_USE_PKG_CONFIG" != "false" ]; then
    # Set the search paths and compile flags
    PKGCONFIG_CFLAGS=`pkg-config --cflags --silence-errors ${PKG_CONFIG_NAME}`
    PKGCONFIG_LIBS=`pkg-config --libs-only-l --libs-only-other --silence-errors ${PKG_CONFIG_NAME}`
    PKGCONFIG_DIRS=`pkg-config --libs-only-L --silence-errors ${PKG_CONFIG_NAME}`
  fi

  if [ "$PKGCONFIG_LIBS" != "" ]; then
    FOUND_LIB_DIR=`echo $PKGCONFIG_DIRS | sed -e 's/^-L//'`
    echo "*** Arrow C++ libraries found via pkg-config at $FOUND_LIB_DIR"
    PKG_CFLAGS="$PKGCONFIG_CFLAGS $PKG_CFLAGS"
    PKG_LIBS="${PKGCONFIG_LIBS}"
    PKG_DIRS="${PKGCONFIG_DIRS}"

    # Check for version mismatch
    PC_LIB_VERSION=`pkg-config --modversion arrow`
    echo $PC_LIB_VERSION | grep -e 'SNAPSHOT$' >/dev/null 2>&1
    # If on a release (i.e. not SNAPSHOT) and version != R package version, warn
    if [ $? -eq 1 ] && [ "$PC_LIB_VERSION" != "$VERSION" ]; then
      echo "**** Warning: library version mismatch"
      echo "**** C++ is $PC_LIB_VERSION but R is $VERSION"
      echo "**** If installation fails, upgrade the C++ library to match"
      echo "**** or retry with ARROW_USE_PKG_CONFIG=false"
    fi
  else
    if [ "$UNAME" = "Darwin" ] && [ "$FORCE_BUNDLED_BUILD" != "true" ]; then
      if [ "$FORCE_AUTOBREW" != "true" ] && [ "`command -v brew`" ] && [ "`brew ls --versions ${PKG_BREW_NAME}`" != "" ]; then
        echo "*** Using Homebrew ${PKG_BREW_NAME}"
        BREWDIR=`brew --prefix`
        PKG_LIBS="-larrow -larrow_bundled_dependencies"
        PKG_DIRS="-L$BREWDIR/opt/$PKG_BREW_NAME/lib $PKG_DIRS"
        PKG_CFLAGS="-I$BREWDIR/opt/$PKG_BREW_NAME/include $PKG_CFLAGS"
      else
        echo "*** Downloading ${PKG_BREW_NAME}"
        if [ -f "autobrew" ]; then
          echo "**** Using local manifest for ${PKG_BREW_NAME}"
        else
          curl -sfL "https://autobrew.github.io/scripts/$PKG_BREW_NAME" > autobrew
          if [ $? -ne 0 ]; then
            echo "Failed to download manifest for ${PKG_BREW_NAME}"
          fi
        fi
        . autobrew
        if [ $? -ne 0 ]; then
          echo "Failed to retrieve binary for ${PKG_BREW_NAME}"
        fi
        # autobrew sets `PKG_LIBS`, `PKG_DIRS`, and `PKG_CFLAGS`
      fi
    else
      if [ "${NOT_CRAN}" = "true" ]; then
        # Set some default values
        if [ "${LIBARROW_BINARY}" = "" ]; then
          export LIBARROW_BINARY=true
        fi
        if [ "${LIBARROW_MINIMAL}" = "" ]; then
          export LIBARROW_MINIMAL=false
        fi
      fi

      # find openssl on macos. macOS ships with libressl. openssl is installable
      # with brew, but it is generally not linked. We can over-ride this and find
      # openssl but setting OPENSSL_ROOT_DIR (which cmake will pick up later in
      # the installation process). FWIW, arrow's cmake process uses this
      # same process to find openssl, but doing it now allows us to catch it in
      # nixlibs.R and throw a nicer error.
      if [ "$UNAME" = "Darwin" ] && [ "${OPENSSL_ROOT_DIR}" = "" ]; then
        brew --prefix openssl >/dev/null 2>&1
        if [ $? -eq 0 ]; then
          export OPENSSL_ROOT_DIR="`brew --prefix openssl`"
          export PKG_CONFIG_PATH="`brew --prefix openssl`/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}"
        fi
      fi

      if [ "${ARROW_DEPENDENCY_SOURCE}" = "" ]; then
        export ARROW_DEPENDENCY_SOURCE=AUTO
      fi
      if [ "${ARROW_DEPENDENCY_SOURCE}" = "AUTO" ] && \
           [ "${PKG_CONFIG_AVAILABLE}" = "false" ]; then
        export ARROW_DEPENDENCY_SOURCE=BUNDLED
        echo "**** pkg-config not installed, setting ARROW_DEPENDENCY_SOURCE=BUNDLED"
      fi

      ${R_HOME}/bin/Rscript tools/nixlibs.R $VERSION

      LIB_DIR="`pwd`/libarrow/arrow-${VERSION}/lib"
      if [ -d "$LIB_DIR" ]; then
        if [ "${PKG_CONFIG_AVAILABLE}" = "true" ]; then
          # Use pkg-config to do static linking of libarrow's dependencies
          export PKG_CONFIG_PATH="${LIB_DIR}/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}"
          PKG_CONFIG="pkg-config"
          # pkg-config on CentOS 7 doesn't have --define-prefix option.
          if ${PKG_CONFIG} --help | grep -- --define-prefix >/dev/null 2>&1; then
            # --define-prefix is for binary packages. Binary packages
            # uses "/arrow/r/libarrow/dist" as prefix but it doesn't
            # match the extracted path. --define-prefix uses a directory
            # that arrow.pc exists as its prefix instead of
            # "/arrow/r/libarrow/dist".
            PKG_CONFIG="${PKG_CONFIG} --define-prefix"
          else
            # Rewrite prefix= in arrow.pc on CentOS 7.
            sed \
              -i.bak \
              -e "s,prefix=/arrow/r/libarrow/dist,prefix=${LIB_DIR}/..,g" \
              ${LIB_DIR}/pkgconfig/*.pc
            rm -f ${LIB_DIR}/pkgconfig/*.pc.bak
          fi
          PKG_CONFIG="${PKG_CONFIG} --silence-errors"
          PKG_CFLAGS="`${PKG_CONFIG} --cflags ${PKG_CONFIG_NAME}` $PKG_CFLAGS"
          PKG_DIRS="`${PKG_CONFIG} --libs-only-L ${PKG_CONFIG_NAME}`"
          PKG_LIBS="`${PKG_CONFIG} --libs-only-l --libs-only-other ${PKG_CONFIG_NAME}`"
        else
          # This case must be ARROW_DEPENDENCY_SOURCE=BUNDLED.
          PKG_CFLAGS="-I${LIB_DIR}/../include $PKG_CFLAGS"
          PKG_DIRS="-L${LIB_DIR}"
          if [ "${OPENSSL_ROOT_DIR}" != "" ]; then
            PKG_DIRS="${PKG_DIRS} -L${OPENSSL_ROOT_DIR}/lib"
          fi
          PKG_LIBS="-larrow"
          if [ -n "$(find "$LIB_DIR" -name 'libarrow_bundled_dependencies.*')" ]; then
            PKG_LIBS="$PKG_LIBS -larrow_bundled_dependencies"
          fi
          S3_LIBS="-lcurl -lssl -lcrypto"
          GCS_LIBS="-lcurl -lssl -lcrypto"
        fi
      fi
    fi
  fi
fi

# If on Raspberry Pi, need to manually link against latomic
# See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81358 for similar example
if grep raspbian /etc/os-release >/dev/null 2>&1; then
  PKG_CFLAGS="$PKG_CFLAGS -DARROW_CXXFLAGS=-latomic"
  PKG_LIBS="-latomic $PKG_LIBS"
fi

# Set any user-defined CXXFLAGS
if [ "$ARROW_R_CXXFLAGS" ]; then
  PKG_CFLAGS="$PKG_CFLAGS $ARROW_R_CXXFLAGS"
fi

# Test that we can find libarrow
CXX17="`${R_HOME}/bin/R CMD config CXX17` -E"
CXX17FLAGS=`"${R_HOME}"/bin/R CMD config CXX17FLAGS`
CXX17STD=`"${R_HOME}"/bin/R CMD config CXX17STD`
CPPFLAGS=`"${R_HOME}"/bin/R CMD config CPPFLAGS`
TEST_CMD="${CXX17} ${CPPFLAGS} ${PKG_CFLAGS} ${CXX17FLAGS} ${CXX17STD} -xc++ -"
echo "#include $PKG_TEST_HEADER" | ${TEST_CMD} >/dev/null 2>&1

if [ $? -eq 0 ]; then
  # Check for features
  ARROW_OPTS_CMAKE="$LIB_DIR/cmake/Arrow/ArrowOptions.cmake"

  arrow_built_with() {
    # Function to check cmake options for features
    grep -i 'set('"$1"' "ON")' $ARROW_OPTS_CMAKE >/dev/null 2>&1
  }

  if arrow_built_with ARROW_PARQUET; then
    PKG_CFLAGS="$PKG_CFLAGS -DARROW_R_WITH_PARQUET"
    PKG_LIBS="-lparquet $PKG_LIBS"
    # NOTE: parquet is assumed to have the same -L flag as arrow
    # so there is no need to add its location to PKG_DIRS
  fi
  if arrow_built_with ARROW_DATASET; then
    PKG_CFLAGS="$PKG_CFLAGS -DARROW_R_WITH_DATASET"
    PKG_LIBS="-larrow_dataset $PKG_LIBS"
    # NOTE: arrow-dataset is assumed to have the same -L flag as arrow
    # so there is no need to add its location to PKG_DIRS
  fi
  if arrow_built_with ARROW_SUBSTRAIT; then
    PKG_CFLAGS="$PKG_CFLAGS -DARROW_R_WITH_SUBSTRAIT"
    PKG_LIBS="-larrow_substrait $PKG_LIBS"
    # NOTE: arrow-substrait is assumed to have the same -L flag as arrow
    # so there is no need to add its location to PKG_DIRS
  fi
  if arrow_built_with ARROW_JSON; then
    PKG_CFLAGS="$PKG_CFLAGS -DARROW_R_WITH_JSON"
  fi
  if arrow_built_with ARROW_S3; then
    PKG_CFLAGS="$PKG_CFLAGS -DARROW_R_WITH_S3"
    PKG_LIBS="$PKG_LIBS $S3_LIBS"
  fi
  if arrow_built_with ARROW_GCS; then
    PKG_CFLAGS="$PKG_CFLAGS -DARROW_R_WITH_GCS"
    PKG_LIBS="$PKG_LIBS $GCS_LIBS"
  fi

  # prepend PKG_DIRS to PKG_LIBS
  PKG_LIBS="$PKG_DIRS $PKG_LIBS"
  echo "PKG_CFLAGS=$PKG_CFLAGS"
  echo "PKG_LIBS=$PKG_LIBS"
else
  echo "------------------------- NOTE ---------------------------"
  echo "There was an issue preparing the Arrow C++ libraries."
  echo "See https://arrow.apache.org/docs/r/articles/install.html"
  echo "---------------------------------------------------------"
  PKG_LIBS=""
  PKG_CFLAGS=""
  exit 1

fi

# Write to Makevars
sed -e "s|@cflags@|$PKG_CFLAGS|" -e "s|@libs@|$PKG_LIBS|" src/Makevars.in > src/Makevars

# This is removed because a (bad?) CRAN check fails when arrow.so is stripped
# # Add stripping
# if [ "$R_STRIP_SHARED_LIB" != "" ]; then
#   # R_STRIP_SHARED_LIB is set in the global Renviron and should be available here
#   echo "
# strip: \$(SHLIB)
# 	$R_STRIP_SHARED_LIB \$(SHLIB) >/dev/null 2>&1 || true
#
# .phony: strip
# " >> src/Makevars
# fi

# Success
exit 0
