#!/usr/bin/env bash
# ==========================================================================
#     _   _ _ ____            ____          _____
#    | | | (_)  _ \ ___ _ __ / ___|___  _ _|_   _| __ __ _  ___ ___ _ __
#    | |_| | | |_) / _ \ '__| |   / _ \| '_ \| || '__/ _` |/ __/ _ \ '__|
#    |  _  | |  __/  __/ |  | |__| (_) | | | | || | | (_| | (_|  __/ |
#    |_| |_|_|_|   \___|_|   \____\___/|_| |_|_||_|  \__,_|\___\___|_|
#
#       ---  High-Performance Connectivity Tracer (HiPerConTracer)  ---
#                 https://www.nntb.no/~dreibh/hipercontracer/
# ==========================================================================
#
# High-Performance Connectivity Tracer (HiPerConTracer)
# Copyright (C) 2015-2025 by Thomas Dreibholz
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Contact: dreibh@simula.no

# Bash options:
set -eu


# ###### Usage ##############################################################
usage () {
   echo >&2 "Usage: $0 configuration_file [-h|--help] [-d|--dry-run] [-q|--quiet] [-B|--write-dbeaver-config file_prefix]"
   exit 1
}


# ###### Main program #######################################################

# ====== Handle arguments ===================================================
GETOPT="$(PATH=/usr/local/bin:$PATH which getopt)"
options="$(${GETOPT} -o hdqB: --long help,dry-run,quiet,write-dbeaver-config: -a -- "$@")"
# shellcheck disable=SC2181
if [[ $? -ne 0 ]]; then
   usage
fi

DRY_RUN=0
QUIET=0
DBEAVER_CONFIG_PREFIX=""
eval set -- "${options}"
while [ $# -gt 0 ] ; do
   case "$1" in
      -B | --write-dbeaver-config)
         DBEAVER_CONFIG_PREFIX="$2"
         shift 2
         ;;
      -d | --dry-run)
         DRY_RUN=1
         shift
         ;;
      -q | --quiet)
         QUIET=1
         shift
         ;;
      --)
         shift
         break
         ;;
  esac
done
if [ $# -lt 1 ] ; then
   usage
fi
CONFIGURATION_FILE="$1"
if [ ! -e "${CONFIGURATION_FILE}" ] ; then
   echo >&2 "ERROR: Use configuration ${CONFIGURATION_FILE} does not exist!"
fi


# ====== Read configuration file ============================================
dbbackend=""
dbserver=""
dbport=""
dbcafile=""
dbcrlfile=""
dbkeyfile=""
dbcertfile=""
dbcertkeyfile=""
dbconnectionflags=""
dbuser=""
dbpassword=""
database=""
configContent=$(sed -r '/[^=#]+=[^=]+/!d' <"${CONFIGURATION_FILE}" | sed -r "s/[[:space:]]*=[[:space:]]*(.*)[[:space:]]*/='\1'/g")
eval "${configContent}"
if [ "${dbcafile}" == "NONE" ] ; then
   dbcafile=""
fi
if [ "${dbcrlfile}" == "NONE" ] ; then
   dbcrlfile=""
fi
if [ "${dbkeyfile}" == "NONE" ] ; then
   dbkeyfile=""
fi
if [ "${dbcertfile}" == "NONE" ] ; then
   dbcertfile=""
fi
if [ "${dbcertkeyfile}" == "NONE" ] ; then
   dbcertkeyfile=""
fi
if [ "${dbcertfile}" == "NONE" ] ; then
   dbcertfile=""
fi
tls_enabled=1
tls_check_certificate=1
tls_check_hostname=1
for dbconnectionflag in ${dbconnectionflags} ; do
   if [ "${dbconnectionflag}" == "DisableTLS" ] ; then
      tls_enabled=0
      tls_check_certificate=0
      tls_check_hostname=0
   elif [ "${dbconnectionflag}" == "AllowInvalidCertificate" ] ; then
      tls_check_certificate=0
      tls_check_hostname=0
   elif [ "${dbconnectionflag}" == "AllowInvalidHostname" ] ; then
      tls_check_certificate=1
      tls_check_hostname=0
   elif [ "${dbconnectionflag}" != "NONE" ] ; then
      echo >&2 "ERROR: Invalid connection flag ${dbconnectionflag}!"
      exit 1
   fi
done


# ====== Build the parameters line =============================================
oldCommand=0
command=""
parameters=""
if [ "${dbbackend}" == "MariaDB" ] || [ "${dbbackend}" == "MySQL" ] ; then

   if [ "${dbbackend}" == "MariaDB" ] ; then
      command="$(which mariadb || true)"
      if [ "${DRY_RUN}" -eq 0 ] && [ "${command}" == "" ] ; then
         echo >&2 "ERROR: MariaDB client (mariadb) not found. Is it installed?"
         exit 1
      fi
   else
      command="$(which mysql || true)"
      if [ "${DRY_RUN}" -eq 0 ] && [ "${command}" == "" ] ; then
         echo >&2 "ERROR: MySQL client (mysql) not found. Is it installed?"
         exit 1
      fi
   fi
   if [ "${dbport}" == "0" ] ; then
      dbport="3306"
   fi
   parameters="${parameters} --silent --host=\"${dbserver}\" --port=${dbport} --protocol=tcp --user=\"${dbuser}\" --password=\"${dbpassword}\" --database=\"${database}\""
   if [ ${tls_enabled} -eq 1 ] && [ "${dbcafile}" != "" ] ; then
      if [ ${tls_check_certificate} -eq 1 ] || [ ${tls_check_hostname} -eq 1 ] ; then
         parameters="${parameters} --ssl-verify-server-cert"
      fi
      parameters="${parameters} --ssl-ca=\"${dbcafile}\""
      if [ "${dbcrlfile}" != "" ] ; then
         parameters="${parameters} --ssl-crl \"${dbcrlfile}\""
      fi
   fi

elif [ "${dbbackend}" == "PostgreSQL" ] ; then

   command="$(which psql || true)"
   if [ "${DRY_RUN}" -eq 0 ] && [ "${command}" == "" ] ; then
      echo >&2 "ERROR: PostgreSQL client (psql) not found. Is it installed?"
      exit 1
   fi
   if [ "${dbport}" == "0" ] ; then
      dbport="5432"
   fi
   parameters="--quiet --host=\"${dbserver}\" --port=${dbport} --username=\"${dbuser}\" --dbname=\"${database}\""
   export PGPASSWORD="${dbpassword}"
   if [ ${tls_enabled} -eq 1 ] && [ "${dbcafile}" != "" ] ; then
      if [ ${tls_check_certificate} -eq 1 ] ; then
         if [ ${tls_check_hostname} -eq 1 ] ; then
            export PGSSLMODE="verify-full"
         else
            export PGSSLMODE="verify-ca"
         fi
      else
         export PGSSLMODE="require"
      fi
      export PGSSLROOTCERT="${dbcafile}"
      if [ "${dbcrlfile}" != "" ] ; then
         export PGSSLCRL="${dbcrlfile}"
      fi
   else
      export PGSSLMODE="prefer"
   fi

elif [ "${dbbackend}" == "MongoDB" ] ; then

   command="$(which mongosh || true)"
   if [ "${DRY_RUN}" -eq 0 ] && [ "${command}" == "" ] ; then
      command="$(which mongo || true)"
      if [ "${DRY_RUN}" -eq 0 ] && [ "${command}" == "" ] ; then
         echo >&2 "ERROR: MongoDB client (mongosh or mongo) not found. Is it installed?"
         exit 1
      else
         oldCommand=1
      fi
   fi
   if [ "${dbport}" == "0" ] ; then
      dbport="27017"
   fi
   parameters="\"mongodb://${dbserver}:${dbport}/${database}\" --username \"${dbuser}\" --password \"${dbpassword}\""
   if [ ${tls_enabled} -eq 1 ] && [ "${dbcafile}" != "" ] ; then
      if [ ${oldCommand} -eq 0 ] ; then
         parameters="${parameters} --tls --tlsDisabledProtocols TLS1_0,TLS1_1,TLS1_2 --tlsCAFile \"${dbcafile}\""
         if [ ${tls_check_certificate} -eq 0 ] ; then
            parameters="${parameters} --tlsAllowInvalidCertificates"
         elif [ ${tls_check_hostname} -eq 0 ] ; then
            parameters="${parameters} --tlsAllowInvalidHostnames"
         fi
         if [ "${dbcrlfile}" != "" ] ; then
            # FIXME: --tlsCRLFile \"${dbcrlfile}\" does not work!
            # parameters="${parameters} --tlsCRLFile \"${dbcrlfile}\""
            true
         fi
      else
         parameters="${parameters} --ssl --sslDisabledProtocols TLS1_0,TLS1_1,TLS1_2 --sslCAFile \"${dbcafile}\""
         if [ "${dbcrlfile}" != "" ] ; then
            parameters="${parameters} --sslCRLFile \"${dbcrlfile}\""
         fi
      fi
   fi
   if [ ${oldCommand} -eq 0 ] ; then
      parameters="${parameters} --quiet"
   fi

else

   echo >&2 "ERROR: Invalid dbbackend setting \"${dbbackend}!\""
   exit 1

fi


# ====== Generate DBeaver configuration file ================================
if [ "${DBEAVER_CONFIG_PREFIX}" ] ; then
   driver=""
   provider=""
   jdbc=""
   custom=""
   handler=""
   dbusername="${dbuser}"

   # ====== MariaDB/MySQL ===================================================
   if [ "${dbbackend}" == "MariaDB" ] || [ "${dbbackend}" == "MySQL" ] ; then
      provider="mysql"
      handler="mysql_ssl"
      # FIXME!
      # Currently, the MariaDB driver is not working. Using MySQL driver instead
      # => https://github.com/dbeaver/dbeaver/issues/35242
#       if [ "${dbbackend}" == "MariaDB" ] ; then
#          driver="mariaDB"
#          jdbc="mariadb"
#       else
         driver="mysql8"
         jdbc="mysql"
#       fi
      if [ ${tls_enabled} -eq 1 ] && [ "${dbcafile}" != "" ] ; then
         ssl_require="true"
         if [ ${tls_check_certificate} -eq 1 ] || [ ${tls_check_hostname} -eq 1 ] ; then
            ssl_verify_server="true"
         else
            ssl_verify_server="false"
         fi
      else
         ssl_require="false"
         ssl_verify_server="false"
      fi
      custom=",
							\"ssl_require\": \"${ssl_require}\",
							\"ssl_verify.server\": \"${ssl_verify_server}\",
							\"ssl.public.key.retrieve\": \"false\""

   # ====== PostgreSQL ======================================================
   elif [ "${dbbackend}" == "PostgreSQL" ] ; then
      driver="postgres-jdbc"
      provider="postgresql"
      jdbc="postgresql"
      handler="postgre_ssl"
      if [ ${tls_check_certificate} -eq 1 ] ; then
         if [ ${tls_check_hostname} -eq 1 ] ; then
            ssl_mode="verify-full"
         else
            ssl_mode="verify-ca"
         fi
      else
         ssl_mode="require"
      fi
      custom=",
							\"sslMode\": \"${ssl_mode}\",
							\"sslFactory\": \"\""
      if [ "${dbuser}" == "postgres" ] ; then
         dbusername="root"
      fi

   # ====== Unsupported =====================================================
   else
      if [ ${QUIET} -eq 0 ] ; then
         echo >&2 "WARNING: DBeaver does not support ${dbbackend} backend!"
      fi
      echo "" >"${DBEAVER_CONFIG_PREFIX}-data-source.json"
      echo "" >"${DBEAVER_CONFIG_PREFIX}-credentials-config.json"
   fi

   if [ "${driver}" != "" ] ; then
      identifier="$(echo "${provider}://${dbusername}@${dbserver}:${dbport}/${database}" | md5sum --tag |  cut -d' ' -f4)"

      color="211,215,207"
      if [ "${dbusername}" == "importer" ] ; then
         color="237,212,0"
      elif [ "${dbusername}" == "researcher" ] ; then
         color="0,127,253"
      elif [ "${dbusername}" == "maintainer" ] ; then
         color="114,159,207"
      elif [ "${dbusername}" == "root" ] ; then
         color="239,41,41"
      fi
      # ansiColor="${color//,/;}"
      # echo >&2 -e "\x1b[38;2;${ansiColor}mdbusername=${dbusername} database=${database} color=${color}\x1b[0m"

      # ====== Generate DBeaver configuration ==================================
      if [ ${QUIET} -eq 0 ] ; then
         echo -e "\x1b[34m$(date +"%F %H:%M:%S"): Writing DBeaver configuration to ${DBEAVER_CONFIG_PREFIX} ...\x1b[0m"
      fi
      (
         cat << EOF
{
	"folders": {},
	"connection-types": {
		"${dbusername}": {
			"name": "${dbusername}",
			"color": "${color}",
			"description": "Regular database access for ${dbusername}",
			"auto-commit": true,
			"confirm-execute": false,
			"confirm-data-change": false,
			"smart-commit": false,
			"smart-commit-recover": true,
			"auto-close-transactions": true,
			"close-transactions-period": 1800,
			"auto-close-connections": true,
			"close-connections-period": 14400
		}
	},
	"connections": {
		"${driver}-${identifier}": {
			"provider": "${provider}",
			"driver": "${driver}",
			"name": "${dbusername}@${dbserver}:${dbport}/${database} ${dbbackend}",
			"save-password": true,
			"configuration": {
				"host": "${dbserver}",
				"port": "${dbport}",
				"database": "${database}",
				"url": "jdbc:${jdbc}://${dbserver}:${dbport}/${database}",
				"configurationType": "MANUAL",
				"type": "${dbusername}",
				"closeIdleConnection": true,
				"auth-model": "native",
				"handlers": {
					"${handler}": {
						"type": "CONFIG",
						"enabled": true,
						"save-password": true,
						"properties": {
							"ssl.ca.cert": "${dbcafile}",
							"ssl.client.cert": "${dbcertfile}",
							"ssl.client.key": "${dbkeyfile}",
							"ssl.method": "CERTIFICATES",
							"ssl.public.key.retrieve": "false",
							"ssl.cipher.suites": ""${custom}
						}
					}
				}
			}
		}
	}
}
EOF
      ) >"${DBEAVER_CONFIG_PREFIX}-data-source.json"

      (
         cat << EOF
{
	"${driver}-${identifier}": {
		"#connection": {
			"user": "${dbuser}",
			"password": "${dbpassword}"
		}
	}
}
EOF
      ) >"${DBEAVER_CONFIG_PREFIX}-credentials-config.json"
   fi
fi


# ====== Run the parameters line ============================================
if [ ${QUIET} -eq 0 ] ; then
   if [ ${DRY_RUN} -eq 0 ] ; then
      echo -e "\x1b[34m$(date +"%F %H:%M:%S"): Connecting to database ...\x1b[0m"
      echo -en "\x1b[37m"
   fi

   if [ "${dbbackend}" == "PostgreSQL" ] ; then
      export | grep "PGPASSWORD=\|PGSSL[A-Z]*=" | sort || true
   fi
   echo "${command} ${parameters}"
   fi

if [ ${DRY_RUN} -eq 0 ] ; then
   if [ ${QUIET} -eq 0 ] ; then
      echo -en "\x1b[0m"
   fi
   sh -c "${command} ${parameters}"
fi
