#!/bin/bash

BASE_TEMPLATE_DIR=/usr/share/xivo-config/templates
CUSTOM_TEMPLATE_DIR=/etc/xivo/custom-templates

is_mds() {
    [ -f /var/lib/xivo/mds_enabled ]
}

if ! is_mds; then
  set -o allexport
    # shellcheck disable=SC1091
  . /usr/sbin/xivo-read-config
  set +o allexport
fi

# list all variables with the good prefix
TEMPLATE_VARS="$(compgen -v XIVO_) $(compgen -v _XIVO_)"


#### helper functions used for templating ####

generate_file()
{
  local FILE=$1

  for VAR in ${TEMPLATE_VARS}; do
    VALUE="${!VAR}"
    if ! sed -ri "s#\#${VAR}\##${VALUE}#g" "${FILE}"; then
      echo sed -ri "s#\#${VAR}\##${VALUE}#g" "${FILE}"
      cat "${FILE}"
    fi
  done
}

apply_template_to_module()
{
  local BUILD_DIR=$1
  local CONFIG_NAME=$2

  mkdir -p "${BUILD_DIR}"

  if [ -e "${BASE_TEMPLATE_DIR}/${CONFIG_NAME}" ]; then
    cp -a "${BASE_TEMPLATE_DIR}/${CONFIG_NAME}" "${BUILD_DIR}"
  fi
  if [ -e "${CUSTOM_TEMPLATE_DIR}/${CONFIG_NAME}" ]; then
    cp -a "${CUSTOM_TEMPLATE_DIR}/${CONFIG_NAME}" "${BUILD_DIR}"
  fi

  FILE_LIST=$(find "${BUILD_DIR}/${CONFIG_NAME}" -type f -print)
  for FILE in ${FILE_LIST}; do
    generate_file "${FILE}"
  done
}

check_diff()
{
  local BUILD_DIR=$1
  local CONFIG_NAME=$2
  local CONFIG_PATH_PREFIX=$3

  local FILE_LIST
  FILE_LIST=$(cd "${BUILD_DIR}/${CONFIG_NAME}" || exit; find . -type f -printf "%P\n")

  for FILE in ${FILE_LIST}; do
    if [ -n "${CONFIG_PATH_PREFIX}" ] && [ ! -e "${CONFIG_PATH_PREFIX}/${FILE}" ]; then
      return 1
    fi
    if ! diff "${BUILD_DIR}/${CONFIG_NAME}/${FILE}" "${CONFIG_PATH_PREFIX}/${FILE}" >/dev/null; then
      return 1
    fi
  done

  return 0
}

do_apply()
{
  local BUILD_DIR=$1
  local CONFIG_NAME=$2
  local CONFIG_PATH_PREFIX=$3

  local RESULT_SUBDIR=${BUILD_DIR}/${CONFIG_NAME}
  # if CONFIG_PATH_PREFIX is empty, install into /

  NOT_EXPANDED=$(grep -Er "#[A-Z0-9_]+#" "${RESULT_SUBDIR}")
  if [ -n "${NOT_EXPANDED}" ]; then
    echo "ERROR: generation from CONFIG_NAME '${CONFIG_NAME}' failed because all variables could not be expanded:" >&2
    echo "${NOT_EXPANDED}" | cut -d: -f2-
    return 1
  fi

  if [ -z "${DEBUG}" ]; then
    cp -a "${RESULT_SUBDIR}"/* "${CONFIG_PATH_PREFIX}"/
    echo "'${CONFIG_NAME}' configuration UPDATED."
  else
    echo "DEBUG: would copy ${RESULT_SUBDIR}/* into ${CONFIG_PATH_PREFIX}/"
  fi
}

do_restart()
{
  local CONFIG_NAME=$1

  local SCRIPT
  if [ -f "${CUSTOM_TEMPLATE_DIR}/${CONFIG_NAME}.restart" ]; then
    SCRIPT="${CUSTOM_TEMPLATE_DIR}/${CONFIG_NAME}.restart"
  elif [ -f "${BASE_TEMPLATE_DIR}/${CONFIG_NAME}.restart" ]; then
    SCRIPT="${BASE_TEMPLATE_DIR}/${CONFIG_NAME}.restart"
  fi

  if [ -z "${DEBUG}" ]; then
    ${SCRIPT}
  else
    echo "DEBUG: would run: ${SCRIPT}"
  fi
}

place_templated_module() {
  local BUILD_DIR=$1
  local CONFIG_NAME=$2
  local CONFIG_PATH_PREFIX=$3

  if check_diff "${BUILD_DIR}" "${CONFIG_NAME}" "${CONFIG_PATH_PREFIX}"; then
    echo "'${CONFIG_NAME}' configuration OK, skipping."
  else
    if do_apply "${BUILD_DIR}" "${CONFIG_NAME}" "${CONFIG_PATH_PREFIX}"; then
      do_restart "${CONFIG_NAME}"
    fi
  fi
}

contains() {
    [[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]]
}

### main functions for templating

apply_templating() {
  echo "(Re)templating"

  LIST_BASE_TEMPLATE=$(cd "${BASE_TEMPLATE_DIR}" || exit; find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n")
  LIST_CUSTOM_TEMPLATE=$(cd "${CUSTOM_TEMPLATE_DIR}" || exit; find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n")
  LIST_TEMPLATE=$(echo "${LIST_BASE_TEMPLATE} ${LIST_CUSTOM_TEMPLATE}" | tr ' ' '\n' | sort -u)

  ### just template dialplan for mds
  if is_mds; then
    if contains "${LIST_TEMPLATE}" "dialplan"; then
      LIST_TEMPLATE="dialplan"
    else
      return
    fi
  fi

  for TEMPLATE in ${LIST_TEMPLATE}; do
    if [ -f "${BASE_TEMPLATE_DIR}/${TEMPLATE}.skip" ] || [ -f "${CUSTOM_TEMPLATE_DIR}/${TEMPLATE}.skip" ]; then
      continue
    fi

    if [[ ${XIVO_HANDLE_SYSTEM_CONF} == "0" ]] && [[ ${TEMPLATE} == "mail" || ${TEMPLATE} == "system" ]]; then
      echo "'${TEMPLATE}' externally handled configuration, skipping."
    else
      apply_template_to_module "${BASE_BUILD_DIR}" "${TEMPLATE}"
      if [[ ${TEMPLATE} == "dialplan" ]]; then
        DIALPLAN_PATH_PREFIX="/usr/share/xivo-config/dialplan"
        place_templated_module "${BASE_BUILD_DIR}" "${TEMPLATE}" "${DIALPLAN_PATH_PREFIX}"
        warn_uncleaned_config "${BASE_BUILD_DIR}" "${TEMPLATE}" "${DIALPLAN_PATH_PREFIX}"
      else
        #the full config path is defined in the templates folder
        place_templated_module "${BASE_BUILD_DIR}" "${TEMPLATE}"
      fi
    fi
  done
}

dahdi_configuration() {
  if [ -x /usr/sbin/xivo-check-dahdi-ports ]; then
    if [ -n "${DEBUG}" ]; then
      echo "DEBUG: create monit DAHDI ports configuration"
    fi
    /usr/sbin/xivo-check-dahdi-ports configure
  fi
  }

dhcp_configuration() {
  if [ "${XIVO_DHCP_ACTIVE}" = "1" ]; then
    update-rc.d isc-dhcp-server defaults > /dev/null
  else
    update-rc.d isc-dhcp-server remove > /dev/null
  fi
}

warn_uncleaned_config() {
  #Usage for dialplan only right now
  local BUILD_DIR=$1
  local CONFIG_NAME=$2
  local CONFIG_PATH_PREFIX=$3

  if [ -z "${CONFIG_PATH_PREFIX}" ];then
    return
  fi

  BUILD_DIR_FILE_LIST=$(find "${BUILD_DIR}/${CONFIG_NAME}" -type f -printf "%P\n")
  DESTINATION_FILE_LIST=$(find "${CONFIG_PATH_PREFIX}" -type f -printf "%P\n")
  for FILE in ${DESTINATION_FILE_LIST}; do
    if ! contains "${BUILD_DIR_FILE_LIST}" "${FILE}";then
      echo "File ${FILE} lives outside the templated ${CONFIG_NAME} configuration"
    fi
  done
}

#### Apply template for each "configuration module" ####

BASE_BUILD_DIR=$(mktemp -d)

apply_templating
if ! is_mds; then
  dahdi_configuration
  dhcp_configuration
fi

#### cleanup ####

if [ -z "${DEBUG}" ]; then
  rm -rf "${BASE_BUILD_DIR}"
else
  echo "DEBUG: generated files can be found here: ${BASE_BUILD_DIR}"
fi

echo "DONE"
