#!/bin/bash
# Purpose: set config value
################################################################################

set -e
set -u

# support testsuite
FUNCTIONS="${FUNCTIONS:-/usr/share/ngcp-ngcpcfg/functions/}"
HELPER="${HELPER:-/usr/share/ngcp-ngcpcfg/helper/}"
SCRIPTS="${SCRIPTS:-/usr/share/ngcp-ngcpcfg/scripts/}"

if ! [ -r "${FUNCTIONS}"/main ] ; then
  printf "Error: %s/main could not be read. Exiting.\n" "${FUNCTIONS}">&2
  exit 1
fi

. "${FUNCTIONS}"/main

## functions {{{
help() {
  echo "Usage: ngcpcfg set <file> <key>"
  echo "Example: ngcpcfg set /etc/ngcp-config/config.yml general.maintenance=yes"
}

## }}}

[ "${#:-}" -ne 2 ] && (help >&2 ; exit 1)

file="$1"
data="$2"
RC=0

[ -f "${file}" ] || (log_error "missing ${file}. Exiting." ; exit 1)
[ -z "${data}" ] && ( log_error "missing data to set. Exiting." ; exit 1)

log_debug "Received data: ${data}"
option="${data/=*/}"
value="${data/*=/}"

[ -z "${option}" ] && ( log_error "missing option to set. Exiting." ; exit 1)
[ -z "${value}" ] && ( log_error "missing value to set. Exiting." ; exit 1)
log_debug "Saving option '${option}' value '${value}' into '${file}'"

if [[ ${value} =~ ^\'.*\'$ ]] ; then
  log_debug "\$value is already quoted."
elif [[ ${value} =~ ^[0-9]*$ ]] ; then
  log_debug "Not quoting \$value for integers."
elif [[ ${value} =~ ^\[.*\]$ ]] ; then
  log_debug "Not quoting \$value for arrays."
elif [[ ${value} =~ ^\{.*\}$ ]] ; then
  log_debug "Not quoting \$value for hashes."
else
  log_debug "Quoting \$value to prevent further Perl errors."
  value="\"${value}\""
fi

tmp=$(mktemp)
log_debug "Temporary perl file: ${tmp}"

cat > "${tmp}" << EOF
use strict;
use warnings;
use YAML::XS;
my \$file="${file}";
my \$yaml = YAML::XS::LoadFile("\$file");
my \$valref = \\\$yaml;

for my \$component (split(/\\./, "${option}")) {
  if (ref(\$valref) eq 'SCALAR' && defined(\$\$valref)) {
    print STDERR ("Key resolved to a SCALAR at '\$component'; cannot continue.\n");
    exit(1);
  }
  elsif (\$component =~ /^\\d+\$/ && (!defined(\$\$valref) || ref(\$\$valref) eq 'ARRAY')) {
    \$valref = \\\$\$valref->[\$component];
  }
  elsif (\$component eq 'APPEND' && ref(\$\$valref) eq 'ARRAY') {
    \$valref = \\\$\$valref->[\$#{\$\$valref}+1];
  }
  elsif (!defined(\$\$valref) || ref(\$\$valref) eq 'HASH') {
    \$valref = \\\$\$valref->{\$component};
  }
  else {
    print STDERR ("Key resolved to a " . ref(\$\$valref) . " reference; refusing to overwrite.\n");
    exit(1);
  }
}
if (!defined(\$\$valref) || ref(\$valref) eq 'SCALAR') {
  \$\$valref = ${value};
}
elsif (ref(\$\$valref) eq 'ARRAY' && ref(${value}) eq 'ARRAY') {
  \$\$valref = ${value};
}
elsif (ref(\$\$valref) eq 'HASH' && ref(${value}) eq 'HASH') {
  \$\$valref = ${value};
}
else {
  print STDERR ("Key resolved to a " . ref(\$\$valref) . " reference; refusing to overwrite.\n");
  exit(1);
}

YAML::XS::DumpFile(\$file, \$yaml);
EOF

log_debug "perl -wCSD \"${tmp}\" || RC=$?"
perl -wCSD "${tmp}" || RC=$?

if [ "${RC}" = "0" ]; then
  log_debug "ngcpcfg diff | tail -n +5 || true"
  ngcpcfg diff | tail -n +5 || true
fi

if [ -n "${DEBUG:-}" ] ; then
  log_debug "Not removing temporary file ${tmp}"
else
  rm -f "${tmp}"
fi

exit ${RC}

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