#!/usr/bin/bash
#
# Copyright: 2021 ZENETYS
# Author: Benoit DOLEZ <bdolez@zenetys.com>
# License: MIT License (http://opensource.org/licenses/MIT)
# Version: 0.1
#

[[ $XDEBUG == 1 ]] && set -x

export LC_ALL=C
shopt -s nullglob
set -o pipefail
set -f

PROGNAME=${0##*/}
USAGE="${PROGNAME} [OPTIONS] ACTION [...]"

function info() {
    local i;
    local d=$(date +%Y-%m-%dT%H:%M:%S.%3N%z);
    local l=info
    [[ ${1:0:2} == -- ]] && l=${1:2} && shift
    for i in "$@"; do
        printf '%s%s%s: %s\n' "${C[$l]}" "${l^^}" "${C[reset]}" "$i" >&2
    done
}

function fatal() {
    local usage=0
    [[ $1 == --usage ]] && usage=1 && shift
    info --${FUNCNAME[0]} "$@"
    (( $usage )) && usage
    trap "" EXIT
    exit 127
}

function error() {
    info --${FUNCNAME[0]} "$@"
}

function warning() {
    info --${FUNCNAME[0]} "$@"
}

function debug() {
    local debug=0

    [[ ${1:0:1} == - ]] && debug=${1:1} && shift
    (( DEBUG < $debug )) && return 0
    info --${FUNCNAME[0]} "$@"
}

function usage() {
  local IFS=$'\t'
  exec >&2
  if [[ $0 == "-bash" ]] ; then return 1 ; fi
  [[ $# -gt 0 ]] && echo "ERROR: $*"
  version
  echo "Usage: $USAGE"
  echo "Options:"
  sed -nr "s/^[[:space:]]*## ([^:]*): /\1\t/p" -- "$0" |
    while read OPT DESC ; do
      printf " %-20s %s\n" "$OPT" "$DESC"
    done
  echo

  echo "<ACTION> is one of :"
  sed -nr "s/^# X-ACTION ([^:]*): /\1\t/p" -- "$0" |
    while read OPT DESC ; do
      printf " %s\n     %s\n" "$OPT" "$DESC"
    done
  echo

  return 0
}

function version() {
  local PROGFILE=$0
  local VERSION=$(sed -n 's/^# Version: //p' $PROGFILE)
  local AUTHOR=$(sed -n 's/^# Author: //p' $PROGFILE)
  local LICENSE=$(sed -n 's/^# License: //p' $PROGFILE)

  echo "${PROGFILE##*/} $VERSION - $AUTHOR - $LICENSE"
}

function _naglive() {
    zservice status nagios >/dev/null || return 1
    naglive "$@"
}

CONFIG_HEADER='{
  "title": "%TITLE%",
  "menu": [
    {
      "name": "Bac à état",
      "to": "/panel",
      "icon": "mdi-table"
    },
    {
      "i18nName": "menuHistory",
      "to": "/history",
      "icon": "mdi-history"
    },
    {
      "i18nName": "menuAvailability",
      "to": "/availability",
      "icon": "mdi-percent"
    }'

IPSLA_HEADER='
    {
      "name": "IPSLA",
      "icon": "mdi-chart-bar",
      "subMenus": ['

CONFIG_CLOSE='  ],
  "apiType": "livestatus"
}'

# X-ACTION build: build config from operational monitoring
function do_build() {
  local cfgdir=$BASEDIR/$(date +%Y%m%d%H%M%S)
  local title first=1 ipsla_build

  mkdir -p $cfgdir
  debug "Create conf.d to '$cfgdir'"

  [[ -r $USERDIR/title.txt ]] && title=$(< "$USERDIR/title.txt")
  [[ -z $title ]] && title=${HOSTNAME%%.*}
  title=$(echo "$title" |sed -zre 's,[[:cntrl:]]+, ,g; s,\s+$,,; s,^\s+,,')
  { echo "$CONFIG_HEADER" |sed "s/%TITLE%/$title/"
    find "$USERDIR/" -mindepth 1 -maxdepth 1 -type f -name '*.json' |sort -V |
        while read -r; do
      printf ",\n"
      cat "$REPLY"
    done
  } > "$cfgdir/config.json"

  ipsla_build=$(HEADERS=host_name,service_description,__IPSLA_PEER _naglive |
       grep -E '\W+IPSLA-\w+\W+' | sort -k3 | while read hst svc site; do
    [[ $first == 1 ]] || printf ",\n"
    first=0
    echo -n "$hst/$svc: ${site#*;}" >&2
    printf '{'
    printf '"name": "%s","database": "%s:%s",' "${site#*;}" "$hst" "$svc"
    printf '"to": "/graph/",'
    printf '"datasources": ["RTTMin","AvgJitter","pktLoss"]'
    printf '}'
    echo ", ok" >&2
  done)

  if [[ -n $ipsla_build ]]; then
    echo "$IPSLA_HEADER"
    echo "$ipsla_build"
    printf '      ]\n    }\n'
  fi >> "$cfgdir/config.json"

  echo "$CONFIG_CLOSE" >> $cfgdir/config.json

  # validate link to new config
  ln -snf ${cfgdir##*/} ${CFGDIR}/new
}

# X-ACTION apply: apply new config
function do_apply() {
  debug "Apply new menu from ${CFGDIR}/new"

  [[ -L ${CFGDIR}/new ]] ||
    fatal "bad configuration: '${CFGDIR}/new' do not link to configuration"

  [[ -L ${CFGDIR}/previous ]] && rm ${CFGDIR}/previous
  [[ -L ${CFGDIR}/current ]] && mv ${CFGDIR}/current ${CFGDIR}/previous
  mv ${CFGDIR}/new ${CFGDIR}/current

  info "New configuration applied and linked to ${CFGDIR}/current"
}

# X-ACTION revert: revert to old config
function do_revert() {
  debug "Revert previous configuration (${CFGDIR}/previous)"

  [[ -L ${CFGDIR}/previous ]] ||
    fatal "can't revert to unknown configuration"

  if [[ -L ${CFGDIR}/current ]]; then
    debug "Disable current ${CFGDIR}/$(readlink ${CFGDIR}/current)"
    [[ -L ${CFGDIR}/old ]] && rm ${CFGDIR}/old
    mv ${CFGDIR}/current ${CFGDIR}/old
    info "Old configuration linked to ${CFGDIR}/old"
  fi

  info "Previous configuration applied and linked to ${CFGDIR}/current"

  mv ${CFGDIR}/previous ${CFGDIR}/current

  systemctl stop snmptrapd
  rm -f /var/lib/snmp/snmptrapd.conf
  systemctl start snmptrapd
  systemctl restart snmptrapd

}

declare VERBOSE=${VERBOSE:-1}
declare USERDIR=${USERDIR:-/etc/kompot/menus}
declare BASEDIR=${BASEDIR:-/var/lib/kompot/configs/menus}
declare CFGDIR=${BASEDIR}

export PATH=${PATH}:${0%/*}

(( ${#BASH_SOURCE[@]} > 1 )) && return

while (( $# > 0 )); do
  case "$1" in
    ## -h, --help: This help
    -h|--help) usage && exit 0 ;;
    ## -V, --version: Show version
    -V|--version) version && exit 0 ;;
    ## --x-debug: Enable bash debug mode
    --x-debug)    XDEBUG=1 ;;
    ## -v, --verbose: Define verbose level (must be repeat)
    -v|--verbose) ((VERBOSE++)) ;;
    ## -q, --quiet: Set verbose level to 0
    -q|--quiet) ((VERBOSE=0)) ;;
    ## -f, --source: Filename to source, or stdin if last argument
    -f|--source) SOURCE=$2; shift;;
    -*) usage "Unknown parameter '$1'" && exit 1 ;;
    *) ARGS+=( "$1" ) ;;
  esac
  shift
done

[[ $XDEBUG == 1 ]] && set -x

####################################################
## main program starts here
####################################################

ACTION=${ARGS[0]}

case $ACTION in
  # FIXME
  build) do_build "${ARGS[@]:1}" ;;
  apply) do_apply ;;
  revert) do_revert ;;
  *) usage "unknown command '$ACTION'" && exit 1 ;;
esac

exit $?

