#! /bin/bash
# Copyright 2019 Google LLC
#
# Licensed 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.

# A script that updates the bindgen library manually.
#
# Please refer to the file README.md
#
# Requirements:
# - bash
# - awk
# - tr
# - llvm-dev package (for llvm-config that bindgen needs)

set -eo pipefail

# Cargo needs to be in path as well.
PATH=$PATH:/usr/local/cargo/bin

# The directory into which the rust bindings file will be written.  If left
# unset, the current directory is the default.
OUTPUT_DIR=${OUTPUT_DIR:-.}

# The list of unicode source headers to generate bindings for. This list is
# intended to be kept in sync with the static variable by the same name in the
# build.rs file.
readonly BINDGEN_SOURCE_MODULES=(
)

# Types for which to generate the bindings.  Expand this list if you need more.
# The syntax is regex.  This list is intended to be kept in sync with the static
# variable by the same name in the build.rs file.
readonly BINDGEN_ALLOWLIST_TYPES=(
        "UCPTrie.*"
        "UCPTrieType"
        "UCPTRIE.*"
        "UPRV.*"
)

# Functions for which to generate the bindings.  Expand this list if you need
# more.  This list is intended to be kept in sync with the static variable by
# the same name in the build.rs file.
readonly BINDGEN_ALLOWLIST_FUNCTIONS=(
        "usrc_.*"
)

readonly TOOLS_DIR="/src/icu/icu4c/source/tools/toolutil"

# Modules that are only included if present.  This is for the ICU tools, for
# example. Relative to $TOOLS_DIR.
readonly BINDGEN_TOOLS_MODULES=(
  "writesrc.h"
)

function check_requirements() {
  icu-config --version &> /dev/null || \
    (echo "The generator requires icu-config to be in PATH; see README.md"; exit 1)

  bindgen --version &> /dev/null || \
    (echo "The generator requires bindgen to be in PATH; see README.md"; exit 1)

  awk --version &> /dev/null || \
    (echo "The generator requires awk to be installed; see README.md"; exit 1)

  llvm-config --version &> /dev/null || \
    (echo "The generator requires llvm-config (package llvm-dev) to be installed; see README.md"; exit 1)
}

# Generates a temporary header file to be supplied to bindgen for binding generation.
# The file is automatically removed upon exit, so if you are debugging you may want
# to remove that part.
function generate_header_file() {
  MAIN_HEADER_FILE="$(mktemp --suffix=.h)"
  echo "MAIN_HEADER_FILE=${MAIN_HEADER_FILE}"
  trap "rm ${MAIN_HEADER_FILE}" EXIT

  readonly ICU_INCLUDE_DIR="$(icu-config --prefix)/include/unicode"

  echo "// Automatically generated by run_bindgen.sh, DO NOT EDIT. " > ${MAIN_HEADER_FILE}
  for module in ${BINDGEN_SOURCE_MODULES[@]}; do
    echo "#include \"${ICU_INCLUDE_DIR}/${module}.h\"" >> "${MAIN_HEADER_FILE}"
  done

  ls -d /src/icu

  # Optionally include the files from other headers.
  if [[ -e "${TOOLS_DIR}" ]]; then
    for module in ${BINDGEN_TOOLS_MODULES[@]}; do
      modulepath="${TOOLS_DIR}/${module}"
      if [[ -f "${modulepath}" ]]; then 
        echo "#include \"${modulepath}\"" >> "${MAIN_HEADER_FILE}"
      fi
    done
  fi
}

function main() {
  check_requirements

  generate_header_file

  # Joins all with a |, so ("a" "b") become "a|b"
  local _allowlist_types_concat="$(\
    echo ${BINDGEN_ALLOWLIST_TYPES[@]} | tr ' ' '|')"
  local _functions_concat="$(\
    echo ${BINDGEN_ALLOWLIST_FUNCTIONS[@]} | tr ' ' '|')"

  set -x 

  # Example: "67.1", "66.0.1"
  local _icu_version="$(icu-config --version)"
  # Example: "67"
  local _icu_version_major="${_icu_version%.*}"
  local _icu_version_major="${_icu_version_major%.*}"

  # Respectful code hack.
  local _allowlist="allowlist"


  local _output_file="${OUTPUT_DIR}/lib_${_icu_version_major}.rs"
  bindgen \
    --default-enum-style=rust \
    --no-doc-comments \
    --with-derive-default \
    --with-derive-hash \
    --with-derive-partialord \
    --with-derive-partialeq \
    --"${_allowlist}"-type="${_allowlist_types_concat}" \
    --"${_allowlist}"-function="${_functions_concat}" \
    --opaque-type="" \
    --output="${_output_file}" \
    "${MAIN_HEADER_FILE}" \
    -- \
    $(icu-config --cppflags) \
    -I ${TOOLS_DIR} \
    -I "/src/icu/icu4c/source/common"

  # This can fail for weird reasons, ignore.
  rustfmt --force "${_output_file}" || true
}

main
