#!/usr/bin/env bash

# Manage the Nano configuration files in the '${HOME}/.config/nano/' folder.
#
# Copyright (c) 2017-2026 by Reto Kromer <https://reto.ch/>
#
# Released under a 3-Clause BSD License and provided "as is" without warranty
# or support of any kind.


# initialise constants
VERSION='2026-01-02'
SCRIPT_NAME="$(basename "$0")"
CONFIG_FILE="${HOME}/.config/AVpres/Bash_AVpres/${SCRIPT_NAME}.txt"
RED='\033[1;31m'
BLUE='\033[1;34m'
NC='\033[0m'

# load configuration file if any and initialise default values
[[ -f "${CONFIG_FILE}" ]] && . "${CONFIG_FILE}"
confirmation="${confirmation:-yes}"
cp_bin="${cp_bin:-$(which gcp) --preserve=mode,timestamps -r}"
folder="${folder:-${HOME}/.config/nano}"

# initialise variables
unset input_file
unset mode


# get date-and-time stamp
date_time() {
  TZ='UTC' date +'[%F %T %Z]'
}


# print an error message and exit with status 1
abort() {
  echo -e "${RED}${1-An unknown error occurred.\a}${NC}"
  echo "$(date_time) ${1:-An unknown error occurred.}" >> "${LOG_FILE}"
  echo "$(date_time) END" >> "${LOG_FILE}"
  exit 1
}


# print a minimal help message and exit with status 1
print_prompt() {
  echo "$(date_time) print prompt" >> "${LOG_FILE}"
  cat << EOF
Help:
  ${SCRIPT_NAME} -h
EOF
  echo "$(date_time) END" >> "${LOG_FILE}"
  exit 1
}


# print the help message and exit with status 0
print_help() {
  local tmp
  if [[ -f "${CONFIG_FILE}" ]]; then
    tmp="local configuration file found and loaded"
  else
    tmp="no local configuration file found on this computer"
  fi

  echo "$(date_time) print help" >> "${LOG_FILE}"
  cat << EOF

Usage:
  ${SCRIPT_NAME} -l
  ${SCRIPT_NAME} (-a|-d|-p) (nanorc|<syntax>.nanorc)
  ${SCRIPT_NAME} -i (nanorc|default.nanorc)
  ${SCRIPT_NAME} -h | -x
Options:
  -l  list the installed local configuration files
  -a  add a local configuration file
  -d  delete a local configuration file
  -p  print a local configuration file
  -i  initialise the 'nanorc' or 'default.nanorc' local configuration file
  -h  this help
  -x  advanced options with their default arguments
      (${tmp})
See also:
  man ${SCRIPT_NAME}
  https://avpres.net/Bash_AVpres/
About:
  Abstract: Manage the local Nano configuration files in the
  Folder:   ${folder}
  Version:  ${VERSION}

EOF
  echo "$(date_time) END" >> "${LOG_FILE}"
  exit 0
}


# print advanced options with their default arguments and exit with status 0
print_options() {
  local tmp
  local each

  echo "$(date_time) print options" >> "${LOG_FILE}"
  if [[ -f "${CONFIG_FILE}" ]]; then
    cat << EOF

Local configuration file
  '${CONFIG_FILE}'
found and loaded.
EOF
  else
    cat << EOF

No local configuration file for '${SCRIPT_NAME}' found on this computer.
EOF
  fi
  cat << EOF

Advanced options with their default arguments:
  --confirmation='${confirmation}'
  --cp='${cp_bin}'
  --folder='${folder}'

EOF
  echo "$(date_time) END" >> "${LOG_FILE}"
  exit 0
}


# list the local configuration files
list_config() {
  echo "$(date_time) list config" >> "${LOG_FILE}"
  cd "${folder}" || abort "Error: Could not change directory to '${folder}'."
  if [[ -z "$(ls -A "${folder}")" ]]; then
    echo -e "${BLUE}The folder '${folder}' is empty.${NC}"
  else
    echo -e "${BLUE}Installed Nano configuration files at '${folder}':${NC}"
    find . -type f | sort | sed 's/^.\//  /' | tee -a "${LOG_FILE}"
  fi
}


# add a configuration file
add_config() {
  echo "$(date_time) add config" >> "${LOG_FILE}"

  # check that external copy command is running
  if ! command -v ${cp_bin} &> /dev/null; then
    abort "Error: '${cp_bin}' is failing."
  fi

  # check if input is valid
  if [[ ! "$(basename "${input_file}")" =~ 'nanorc' ]]; then
    abort "Error: '$(basename "${input_file}")' is not a 'nanorc' file."
  fi

  # add the configuration file
  ${cp_bin} "${input_file}" "${folder}/$(basename "${input_file}")" || abort
  echo "$(date_time) '$(basename "${input_file}")' added" >> "${LOG_FILE}"
  echo -e "${BLUE}'$(basename "${input_file}")' has been successfully added.${NC}"
}


# delete a local configuration file
delete_config() {
  echo "$(date_time) delete config" >> "${LOG_FILE}"
  local kbd

  # check if input is valid
  if [[ ! -f "${folder}/${input_file}" ]]; then
    abort "Error: No '${input_file}' file is installed."
  fi

  # delete the configuration file
  if [[ "${confirmation}" != 'no' ]]; then
    echo -en "${BLUE}Delete the '${input_file}' file? (y|N) ${NC}"
    read -n 1 kbd
    echo
    if [[ "${kbd}" != [Yy] ]]; then
      echo "$(date_time) aborted by user" >> "${LOG_FILE}"
      echo "'${input_file}' has not been deleted."
      return 0
    fi
  fi
  rm "${folder}/${input_file}" || abort
  echo "$(date_time) '${input_file})' deleted" >> "${LOG_FILE}"
  echo -e "${BLUE}'${input_file}' has been successfully deleted.${NC}"
}


# print a local configuration file
print_config() {
  echo "$(date_time) print config" >> "${LOG_FILE}"

  # check if input is valid
  if [[ ! -f "${folder}/${input_file}" ]]; then
    abort "Error: No '${input_file}' file is installed."
  fi
  echo -e "${BLUE}The local configuration file '${input_file}' is:${NC}"
  cat "${folder}/${input_file}" || abort
}


# initialise the local configuration files
init_config() {
  echo "$(date_time) init config" >> "${LOG_FILE}"

  if [[ "${input_file}" == 'nanorc' ]]; then
    if [[ -f "${folder}/nanorc" ]]; then
      abort "Error: There is already a 'nanorc' configuration file."
    fi
    echo -e "${BLUE}Installing 'nanorc' configuration file...${NC}"
    cat << EOF >> "${folder}/nanorc"
# Generated on $(TZ='UTC' date +'%F %T %Z') by ${SCRIPT_NAME} ${VERSION}
#
# Copyright (c) 2017-2026 by Reto Kromer <https://reto.ch/>
#
# This Nano configuration file is released under a 3-Clause BSD Licence and is
# provided "as is" without warranty or support of any kind.

set autoindent
#set linenumbers
#set nohelp
set softwrap

include ${folder}/*.nanorc
#include /usr/share/nano/*.nanorc
#include /usr/local/share/nano/*.nanorc
#include /opt/homebrew/share/nano/*.nanorc
EOF
  elif  [[ "${input_file}" == 'default.nanorc' ]]; then
    if [[ -f "${folder}/default.nanorc" ]]; then
      abort "Error: There is already a 'default.nanorc' configuration file."
    fi
    echo -e "${BLUE}Installing 'default.nanorc' configuration file...${NC}"
    cat << EOF >> "${folder}/default.nanorc"
# Generated on $(TZ='UTC' date +'%F %T %Z') by ${SCRIPT_NAME} ${VERSION}
#
# Copyright (c) 2017-2026 by Reto Kromer <https://reto.ch/>
#
# This Nano configuration file is released under a 3-Clause BSD Licence and is
# provided "as is" without warranty or support of any kind.

# This default syntax is used for files that do not match any other syntax.

syntax default
comment "#"

# comments
color cyan "^[[:space:]]*#.*"
color cyan "[[:space:]]#.*"

# tabs
color ,cyan "	+"

# trailing whitespace
color ,cyan "[[:space:]]+$"
EOF
  else
    abort "Error: '${input_file}' cannot be initialised."
  fi
}


# start log file
[[ -d '/tmp/AVpres' ]] || mkdir -p '/tmp/AVpres'
LOG_FILE="$(mktemp "/tmp/AVpres/${SCRIPT_NAME}.XXXXXXXXXX")"
echo "$(date_time) ${SCRIPT_NAME} ${VERSION}" > "${LOG_FILE}"
echo "$(date_time) $0 $*" >> "${LOG_FILE}"
echo "$(date_time) START" >> "${LOG_FILE}"

# check that Bash 3.2 or later is running
bash_version="$(bash -c 'echo ${BASH_VERSION}')"
echo "$(date_time) running bash version = '${bash_version}'" >> "${LOG_FILE}"
if ! printf '%s\n%s\n' "${bash_version}" "3.2" | sort -rVC; then
  echo -e "${BLUE}Warning: This 'bash' binary is very old."
  echo -e "We strongly recommend that you use the current version 5.3.${NC}"
fi

# parse and process provided input
(( $# == 0 )) && print_prompt
while getopts ":la:d:p:i:-:hx" opt; do
  case "${opt}" in
    l) mode='list' ;;
    a) if [[ "${OPTARG:0:1}" == '-' ]]; then
         abort "Error: The parameter '-a' requires an argument."
       else
         input_file="${OPTARG}"
         mode='add'
       fi ;;
    d) if [[ "${OPTARG:0:1}" == '-' ]]; then
         abort "Error: The parameter '-d' requires an argument."
       else
         input_file="${OPTARG}"
         mode='delete'
       fi ;;
    p) if [[ "${OPTARG:0:1}" == '-' ]]; then
         abort "Error: The parameter '-p' requires an argument."
       else
         input_file="${OPTARG}"
         mode='print'
       fi ;;
    i) if [[ "${OPTARG:0:1}" == '-' ]]; then
         abort "Error: The parameter '-i' requires an argument."
       else
         input_file="${OPTARG}"
         mode='init'
       fi ;;
    -) case "${OPTARG}" in
         list) mode='list' ;;
         add=?*) input_file="${OPTARG#*=}"; mode='add' ;;
         delete=?*) input_file="${OPTARG#*=}"; mode='delete' ;;
         print=?*) input_file="${OPTARG#*=}"; mode='print' ;;
         init=?*) input_file="${OPTARG#*=}"; mode='init' ;;
         confirmation=?*) confirmation="${OPTARG#*=}" ;;
         cp=?*) cp_bin="${OPTARG#*=}" ;;
         folder=?*) folder="${OPTARG#*=}" ;;
         help) print_help ;;
         options) print_options ;;
         *) abort "Error: The option '--${OPTARG}' is not valid or requires an argument." ;;
       esac ;;
    h) print_help ;;
    x) print_options ;;
    :) abort "Error: The option '-${OPTARG}' requires an argument." ;;
    *) abort "Error: The option '-${OPTARG}' is not valid." ;;
  esac
done

input_file="${input_file%%/}"
folder="${folder%%/}"
[[ -d "${folder}" ]] || mkdir -p "${folder}"
${mode}_config
echo "$(date_time) END" >> "${LOG_FILE}"
