# Filename:      /usr/share/ngcp-ngcpcfg/functions/main
# Purpose:       helper functions for ngcpcfg
################################################################################

# console output including timestamps {{{
timestamp_replacementchars='' # unset by default

console_output() {
  if [ -z "${TIME_FORMAT:-}" ] ; then
    printf -- "$*"
    return 0
  fi

  local timestamp="$(date "$TIME_FORMAT")"

  # indent depending on number of characters in date output
  timestamp_replacementchars="$(printf -- "%s: " "$timestamp" | sed 's/./ /g')"
  printf -- "$timestamp: $*"
}
# }}}

## logging functions {{{
log_info() {
  logger -t ngcpcfg -- "$*"
  console_output "$*\n"
}

# info without ending newline
log_info_n() {
  logger -t ngcpcfg -- "$*"
  console_output "$*"
}

log_warn() {
  logger -t ngcpcfg -- "Warning: $*"
  console_output "Warning: $*\n"
}

log_error() {
  logger -t ngcpcfg -- "Error: $*"
  console_output "Error: $*\n" >&2
}

log_debug() {
  if [ -n "${DEBUG:-}" ] ; then
    logger -t ngcpcfg -- "Debug: $*"
    console_output "DEBUG: $*\n" >&2
  fi
}
## }}}

hook_setup() {
  log_debug "hook_setup ${1:-}"

  if ! [ -d /usr/share/ngcp-ngcpcfg/hooks ] ; then
    log_debug "Directory /usr/share/ngcp-ngcpcfg/hooks doesn't exist."
    return 0
  fi

  local target_directory="$1"

  if [ -z "${1:-}" ] ; then
    log_error "Missing argument for target directory in hook_setup. Exiting."
    exit 1
  fi

  if ! [ -d "$target_directory" ] ; then
    log_error "Hook target directory $target_directory not a directory. Exiting."
    exit 1
  fi

  for hook in /usr/share/ngcp-ngcpcfg/hooks/* ; do
    [ -r "$hook" ] || continue
    log_debug "Creating symlink for $hook in $target_directory"
    ln -sf "$hook" "$target_directory"/
  done
}

compare_active_branch() {
  log_debug "get_active_branch ${1:-}"

  log_debug "cd $NGCPCTL_MAIN"
  cd "$NGCPCTL_MAIN"

  local current_branch
  current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
  log_debug "current_branch = $current_branch"
  echo "$current_branch"
}

get_branch_status() {
  log_debug "cd $NGCPCTL_MAIN"
  cd "$NGCPCTL_MAIN"

  log_debug "git rev-parse HEAD"
  local LOCAL=$(git rev-parse HEAD)

  log_debug "git rev-parse @{u}"
  local REMOTE=$(git rev-parse @{u})

  log_debug "git merge-base HEAD @{u}"
  local BASE=$(git merge-base HEAD @{u})

  if [ "$LOCAL" = "$REMOTE" ]; then
    # Up-to-date
    return 0
  elif [ "$LOCAL" = "$BASE" ]; then
    # Need to pull
    return 1
  elif [ "$REMOTE" = "$BASE" ]; then
    # Need to push
    return 2
  else
    # Diverged
    return 3
  fi
}

## important variables we depend on to operate successfully {{{
# support test suite which requires system independent configuration
if [ -r "${NGCPCFG:-}" ] ; then
  log_debug "sourcing configuration file ${NGCPCFG:-}"
  . "${NGCPCFG:-}"
else
  if [ -r /etc/ngcp-config/ngcpcfg.cfg ] ; then
    . /etc/ngcp-config/ngcpcfg.cfg
    log_debug "sourced configuration file /etc/ngcp-config/ngcpcfg.cfg"

    if [ -d /etc/ngcp-config/ngcpcfg.d ] ; then
      for file in /etc/ngcp-config/ngcpcfg.d/*.cfg ; do
        if test -r $file ; then
          . $file
	  log_debug "sourced configuration file $file"
        fi
      done
    fi
  elif [ -r /etc/ngcp-config-crypted.tgz.gpg ] ; then
    log_error "Configuration pool locked. Please contact your distributor. Exiting."
    exit 1
  else
    log_error "Could not read configuration file /etc/ngcp-config/ngcpcfg.cfg. Exiting."
    exit 1
  fi
fi

if ! [ -r "$NGCPCTL_CONFIG" ] ; then
  log_error "Configuration file ${NGCPCTL_CONFIG} does not exist (unconfigured?) - exiting."
  exit 1
fi

if ! [ -r "$CONSTANTS_CONFIG" ] ; then
  log_error "Constants file ${CONSTANTS_CONFIG} does not exist (unconfigured?) - exiting."
  exit 1
fi

if ! [ -n "${NETWORK_CONFIG:-}" ] ; then
  log_warn "NETWORK_CONFIG is not configured in $NGCPCTL_CONFIG - continuing anyway."
elif ! [ -r "$NETWORK_CONFIG" ] ; then
  log_error "Constants file ${NETWORK_CONFIG} does not exist (unconfigured?) - exiting."
  exit 1
fi

if ! [ -d "$TEMPLATE_POOL_BASE" ] ; then
  log_error "No template directory (${TEMPLATE_POOL_BASE}) found - exiting."
  exit 1
fi

if [ -d "${EXTRA_CONFIG_DIR:-}" ] && ls ${EXTRA_CONFIG_DIR}/*.yml &>/dev/null ; then
  log_debug "EXTRA_CONFIG_DIR is configured and *.yml files are present, setting EXTRA_CONFIG_FILES"
  EXTRA_CONFIG_FILES=${EXTRA_CONFIG_DIR}/*.yml
fi

## }}}

## environment variables {{{
export PN="ngcpcfg"
export HNAME="$(hostname)"
export NNAME="$(ngcp-nodename)"

# avoid warnings by perl script complaining about locales
export LANG=C
export LC_ALL=C

# make sure it's available in all helper scripts
[ -n "${DEBUG:-}" ] && export DEBUG
[ -n "${NO_DB_SYNC:-}" ] && export NO_DB_SYNC

# export for access via build_config etc
export CONFIG_POOL
export HOST_CONFIG
export LOCAL_CONFIG
export NGCPCTL_CONFIG
export CONSTANTS_CONFIG
export NETWORK_CONFIG
export EXTRA_CONFIG_DIR
export EXTRA_CONFIG_FILES
## }}}

## HA / carrier features {{{
if [ -r /usr/share/ngcp-ngcpcfg/functions/ha_features ] ; then
  . /usr/share/ngcp-ngcpcfg/functions/ha_features
  set_ha_file # set $HA_FILE for usage in generate_template_list
fi

if [ -r /usr/share/ngcp-ngcpcfg/functions/carrier_features ] ; then
  . /usr/share/ngcp-ngcpcfg/functions/carrier_features
  set_host_and_pair_files # set $HOST_FILE + $PAIR_FILE for usage in generate_template_list
fi
## }}}

## functions {{{
generate_template_list() {
  [ -n "$TEMPLATE_POOL_BASE" ] || return 1

  local filelist_prepared=$(mktemp)
  local filelist_final=$(mktemp)

  for dir in ${CONFIG_POOL} ; do
    [ -n "${dir}" ] || ( echo "${dir} doesn't exist" >&2 ; continue )
    # iterate over all files
    for file in $(find "$TEMPLATE_POOL_BASE/${dir}" -name \*.tt2 -o -name \*.tt2"${HA_FILE:-}" -o -name \*.tt2"${HOST_FILE:-}" -o -name \*.tt2"${PAIR_FILE:-}") ; do
      # *NO* arguments provided via cmdline
      if [ -z "${1:-}" ] ; then
        echo "$file" >> "${filelist_prepared}"
      else
        # arguments (file list/pattern) provided via cmdline
        for arg in "$@"; do
          if echo $file | grep -q -- "${arg}" ; then
            echo "$file" >> "${filelist_prepared}"
          fi
        done
      fi
    done
  done

  # remove all filenames where a preferred filename exists
  # foo.customtt.tt2.hostname > foo.customtt.tt2.pairname > foo.customtt.tt2.spX > foo.customtt.tt2 > foo.tt2.hostname > foo.tt2.pairname > foo.tt2.spX > foo.tt2
  for line in $(cat ${filelist_prepared}); do

    # ignoring foo.patchtt.tt2.* completely (it is not a tt2 template to be built)
    if [[ "${line}" =~ .*\.patchtt\.tt2(.*)?$ ]]; then
      log_debug "Ignored patchtt file '${line}'"
      continue
    fi

    normalized_filename="$line"

    if [ -n "${HA_FILE:-}" ] ; then
      normalized_filename="${normalized_filename%${HA_FILE}}"
    fi

    if [ -n "${HOST_FILE:-}" ] ; then
      normalized_filename="${normalized_filename%${HOST_FILE}}"
    fi

    if [ -n "${PAIR_FILE:-}" ] ; then
      normalized_filename="${normalized_filename%${PAIR_FILE}}"
    fi

    normalized_filename="${normalized_filename%.customtt.tt2}"
    normalized_filename="${normalized_filename%.tt2}"

    # foo.custom.tt2.hostname
    if [ -n "${HOST_FILE:-}" ] ; then
      if grep -q -- "^${normalized_filename}.customtt.tt2${HOST_FILE}$" "${filelist_prepared}" ; then
        echo "${normalized_filename}.customtt.tt2${HOST_FILE}" >> "${filelist_final}"
        continue
      fi
    fi

    # foo.custom.tt2.pairname
    if [ -n "${PAIR_FILE:-}" ] ; then
      if grep -q -- "^${normalized_filename}.customtt.tt2${PAIR_FILE}$" "${filelist_prepared}" ; then
        echo "${normalized_filename}.customtt.tt2${PAIR_FILE}" >> "${filelist_final}"
        continue
      fi
    fi

    # foo.customtt.tt2.sp{1,2}
    if [ -n "${HA_FILE:-}" ] ; then
      if grep -q -- "^${normalized_filename}.customtt.tt2${HA_FILE:-}" "${filelist_prepared}" ; then
        echo "${normalized_filename}.customtt.tt2${HA_FILE:-}" >> "${filelist_final}"
        continue
      fi
    fi

    # foo.customtt.tt2
    if grep -q -- "^${normalized_filename}.customtt.tt2$" "${filelist_prepared}" ; then
      echo "${normalized_filename}.customtt.tt2" >> "${filelist_final}"
      continue
    fi

    # foo.tt2.hostname
    if [ -n "${HOST_FILE:-}" ] ; then
      if grep -q -- "^${normalized_filename}.tt2${HOST_FILE}" "${filelist_prepared}" ; then
        echo "${normalized_filename}.tt2${HOST_FILE}" >> "${filelist_final}"
        continue
      fi
    fi

    # foo.tt2.pairname
    if [ -n "${HOST_FILE:-}" ] ; then
      if grep -q -- "^${normalized_filename}.tt2${PAIR_FILE}" "${filelist_prepared}" ; then
        echo "${normalized_filename}.tt2${PAIR_FILE}" >> "${filelist_final}"
        continue
      fi
    fi

    # foo.tt2.sp{1,2}
    if [ -n "${HA_FILE:-}" ] ; then
      if grep -q -- "^${normalized_filename}.tt2${HA_FILE}" "${filelist_prepared}" ; then
        echo "${normalized_filename}.tt2${HA_FILE}" >> "${filelist_final}"
        continue
      fi
    fi

    # another file not matching any previous checks
    echo "$line" >> "${filelist_final}"
  done

  # output file list, make sure we provide the file names just once
  sort -u ${filelist_final}

  if [ -n "${DEBUG:-}" ] ; then
    # send to stderr since stdout is used from outside
    log_debug "Not removing temporary filelist files since we are in debug mode:" >&2
    log_debug "  filelist_prepared = ${filelist_prepared}" >&2
    log_debug "  filelist_final    = ${filelist_final}" >&2
  else
    rm -f "${filelist_prepared}" "${filelist_final}"
  fi

  unset filelist_prepared filelist_final
}

record_commit_id() {
  log_debug "cd $NGCPCTL_MAIN"
  cd "$NGCPCTL_MAIN"

  log_debug "mkdir -p ${STATE_FILES_DIR}"
  mkdir -p "${STATE_FILES_DIR}"

  # if there are uncommitted changes then record it as such
  if git status --porcelain | grep -q . ; then
    echo "dirty" > "${STATE_FILES_DIR}/build"
  else
    local latest_commit=$(git log -1 --format="%H")
    log_debug "echo $latest_commit > ${STATE_FILES_DIR}/build"
    echo "$latest_commit" > "${STATE_FILES_DIR}/build"
  fi
}
## }}}

## END OF FILE #################################################################
