#!/bin/bash
#
# A simple curl client to RHPAM.
#
# Requires:
# - jq
# - curl-client.conf to load the configuration from
#
# Variables in curl-client.conf:
#
#   API_ENDPOINT=   base URL to REST endpoints (http://.../services/rest/server)
#   API_USER=	    some username with rest-server role
#   API_PASS=	    the password for the above user
#   KIE_CONTAINER=  the name of the KIE container to work with
#   PROCESS_MODEL=  the ID of the process model to work with
#
#  All of the above can be overriden. Use with --help or -h to see the command line options and commands.
#
# NOTE: YOU MUST ALWAYS FIRST SPECIFY OPTIONS, THE COMMAND MUST BE LAST!
#
# Base variables:
MYNAME="$(basename $0 .sh)"
WORKDIR="$(cd $(dirname $0) && pwd)"
CONFIG="${WORKDIR}/${MYNAME}.conf"

# Version function.
version() {
    cat <<EOF
${MYNAME}, version 1.0, copyright 2021, Grega Bremec <gregab@p0f.net>

A simple curl client to RHPAM.

Requires:
- jq
- curl-client.conf to load the configuration from
EOF
}

# Usage function.
usage() {
    cat <<EOF
Usage: ${MYNAME}.sh [-h][-v][-c <cf>][-e <ep>][-u <usr>][-P <pw>][-k <kc>][-p <pm>][-i <id>][-x <id>][-s <sig>][-d <data>] <command>

Where:
 -h         displays this message and exits successfully
 -v         displays program version and exits successfully
 -c <cf>    is the location (and name) of the configuration file
 -e <ep>    is the API endpoint base URL (API_ENDPOINT cfg)
 -u <usr>   is an API user with rest-server role (API_USER cfg)
 -P <pw>    is the password for the above user (API_PASS cfg)
 -k <kc>    is the name of the KieContainer to work with (KIE_CONTAINER cfg)
 -p <pm>    is the process model ID to work with (PROCESS_MODEL cfg)
 -i <id>    is the process instance ID to work with
 -x <id>    is the process correlation ID (XID) to work with
 -s <sig>   is the name of the signal to work with
 -d <data>  is the request payload, if operation requires some data

NOTE: command line options override config file values.

And <command> is one of (required parameters in parentheses):

    listContainers     lists available KieContainer names
    listModels         lists process model definitions for a KieContainer (-k)
    listVariables      lists all variables defined in a process model (-k, -p)
    listInstances      lists running process instances for a model (-p)
    listCompleted      lists completed process instances for a model (-p)
    listAborted        lists aborted process instances for a model (-p)
    listXidMatches     lists process instances with a given correlation ID (-x)
    getInstanceInfo    displays basic information about a process instance (-k, -i)
    getInstanceSignals displays all signals available for a process instance (-k, -i)
    getInstanceVars    displays all variables currently set in an process instance (-k, -i)
    start              starts a process instance from a model (-k, -p, optionally -d)
    startWithXid       starts a process instance from a model (-k, -p, -x, optionally -d)
    sendSignal         sends a signal (with optional payload) to an instance (-k, -i, -s, optionally -d)
    sendSignalByXid    sends a signal (with optional payload) to an instance matching XID (-k, -x, -s, optionally -d)
    abort              aborts a specified process instance (-k, -i)

NOTE: you must always specify the command LAST on the line.

EOF
}

# Parse command-line options:
SHCNT=0
while getopts ":hve:u:P:c:k:p:i:x:s:d:" OPTION; do
    case ${OPTION} in
	h)
	    version
	    echo
	    usage
	    exit 0
	    ;;
	v)
	    version
	    exit 0
	    ;;
	e)
	    tEP="${OPTARG}"
	    SHCNT=$((SHCNT + 2))
	    ;;
	u)
	    tAU="${OPTARG}"
	    SHCNT=$((SHCNT + 2))
	    ;;
	P)
	    tAP="${OPTARG}"
	    SHCNT=$((SHCNT + 2))
	    ;;
	c)
	    CONFIG="${OPTARG}"
	    SHCNT=$((SHCNT + 2))
	    ;;
	k)
	    tKC="${OPTARG}"
	    SHCNT=$((SHCNT + 2))
	    ;;
	p)
	    tPM="${OPTARG}"
	    SHCNT=$((SHCNT + 2))
	    ;;
	i)
	    tII="${OPTARG}"
	    SHCNT=$((SHCNT + 2))
	    ;;
	x)
	    tXI="${OPTARG}"
	    SHCNT=$((SHCNT + 2))
	    ;;
	s)
	    tSG="${OPTARG}"
	    SHCNT=$((SHCNT + 2))
	    ;;
	d)
	    tDT="${OPTARG}"
	    SHCNT=$((SHCNT + 2))
	    ;;
	:)
	    echo "FATAL: Missing parameter to option -${OPTARG}" >&2
	    echo >&2
	    usage >&2
	    exit 1
	    ;;
	\?)
	    echo "FATAL: Unknown option: -${OPTARG}" >&2
	    echo >&2
	    usage >&2
	    exit 1
	    ;;
    esac
done

# Remove parameters from the command line:
shift ${SHCNT}
if [ -z "$*" ]; then
    echo "FATAL: Missing command." >&2
    echo >&2
    usage >&2
    exit 1
fi

# Try loading the config file:
if [ ! -e "${CONFIG}" ]; then
    echo "FATAL: Config file does not exist!" >&2
    exit 1
fi
if [ ! -r "${CONFIG}" ]; then
    echo "FATAL: Config file is not readable!" >&2
    exit 1
fi
if [ ! -f "${CONFIG}" ]; then
    echo "FATAL: Config file is not a regular file!" >&2
    exit 1
fi
#echo -n "Loading configuration from ${CONFIG}... "
. ${CONFIG}
#echo "done."

# Use the command-line overrides, if present:
[ -n "${tEP}" ] && API_ENDPOINT="${tEP}" && unset tEP
[ -n "${tAU}" ] && API_USER="${tAU}" && unset tAU
[ -n "${tAP}" ] && API_PASS="${tAP}" && unset tAP
[ -n "${tKC}" ] && KIE_CONTAINER="${tKC}" && unset tKC
[ -n "${tPM}" ] && PROCESS_MODEL="${tPM}" && unset tPM
[ -n "${tII}" ] && INSTANCE_ID="${tII}" && unset tII
[ -n "${tXI}" ] && CORRELATION_ID="${tXI}" && unset tXI
[ -n "${tSG}" ] && SIGNAL_NAME="${tSG}" && unset tSG
[ -n "${tDT}" ] && REQUEST_DATA="${tDT}" && unset tDT

# See to it that we recognise the command and all parameters are there:
COMMAND="$*"
case ${COMMAND} in
    listContainers)
	true
	;;
    listModels)
	if [ -z "${KIE_CONTAINER}" ]; then
	    echo "FATAL: ${COMMAND} requires -k option to be set." >&2
	    echo >&2
	    usage >&2
	    exit 1
	fi
	;;
    listInstances|listCompleted|listAborted)
	if [ -z "${PROCESS_MODEL}" ]; then
	    echo "FATAL: ${COMMAND} requires -p option to be set." >&2
	    echo >&2
	    usage >&2
	    exit 1
	fi
	;;
    listXidMatches)
	if [ -z "${CORRELATION_ID}" ]; then
	    echo "FATAL: ${COMMAND} requires -x option to be set." >&2
	    echo >&2
	    usage >&2
	    exit 1
	fi
	;;
    listVariables|start)
	ERRORS=0
	if [ -z "${KIE_CONTAINER}" ]; then
	    echo "FATAL: ${COMMAND} requires -k option to be set." >&2
	    ERRORS=1
	fi
	if [ -z "${PROCESS_MODEL}" ]; then
	    echo "FATAL: ${COMMAND} requires -p option to be set." >&2
	    ERRORS=1
	fi
	if [ ${ERRORS} -gt 0 ]; then
	    echo >&2
	    usage >&2
	    exit 1
	fi
	;;
    getInstanceInfo|getInstanceSignals|getInstanceVars|abort)
	ERRORS=0
	if [ -z "${KIE_CONTAINER}" ]; then
	    echo "FATAL: ${COMMAND} requires -k option to be set." >&2
	    ERRORS=1
	fi
	if [ -z "${INSTANCE_ID}" ]; then
	    echo "FATAL: ${COMMAND} requires -i option to be set." >&2
	    ERRORS=1
	fi
	if [ ${ERRORS} -gt 0 ]; then
	    echo >&2
	    usage >&2
	    exit 1
	fi
	;;
    sendSignal)
	ERRORS=0
	if [ -z "${KIE_CONTAINER}" ]; then
	    echo "FATAL: ${COMMAND} requires -k option to be set." >&2
	    ERRORS=1
	fi
	if [ -z "${INSTANCE_ID}" ]; then
	    echo "FATAL: ${COMMAND} requires -i option to be set." >&2
	    ERRORS=1
	fi
	if [ -z "${SIGNAL_NAME}" ]; then
	    echo "FATAL: ${COMMAND} requires -s option to be set." >&2
	    ERRORS=1
	fi
	if [ ${ERRORS} -gt 0 ]; then
	    echo >&2
	    usage >&2
	    exit 1
	fi
	;;
    sendSignalByXid)
	ERRORS=0
	if [ -z "${KIE_CONTAINER}" ]; then
	    echo "FATAL: ${COMMAND} requires -k option to be set." >&2
	    ERRORS=1
	fi
	if [ -z "${CORRELATION_ID}" ]; then
	    echo "FATAL: ${COMMAND} requires -x option to be set." >&2
	    ERRORS=1
	fi
	if [ -z "${SIGNAL_NAME}" ]; then
	    echo "FATAL: ${COMMAND} requires -s option to be set." >&2
	    ERRORS=1
	fi
	if [ ${ERRORS} -gt 0 ]; then
	    echo >&2
	    usage >&2
	    exit 1
	fi
	;;
    startWithXid)
	ERRORS=0
	if [ -z "${KIE_CONTAINER}" ]; then
	    echo "FATAL: ${COMMAND} requires -k option to be set." >&2
	    ERRORS=1
	fi
	if [ -z "${PROCESS_MODEL}" ]; then
	    echo "FATAL: ${COMMAND} requires -p option to be set." >&2
	    ERRORS=1
	fi
	if [ -z "${CORRELATION_ID}" ]; then
	    echo "FATAL: ${COMMAND} requires -x option to be set." >&2
	    ERRORS=1
	fi
	if [ ${ERRORS} -gt 0 ]; then
	    echo >&2
	    usage >&2
	    exit 1
	fi
	;;
    *)
	echo "FATAL: Unrecognised command: \"$*\"" >&2
	echo >&2
	usage >&2
	exit 1
	;;
esac

# Show what would have happened:
echo
echo "Executing the following operation: ${COMMAND}"
echo
echo "    API_ENDPOINT   = ${API_ENDPOINT}"
echo "    API_USER       = ${API_USER}"
echo "    API_PASS       = ${API_PASS//?/*}"

CURL_CMD="curl -s -u'${API_USER}:${API_PASS}' -H 'Accept: application/json' -H 'Content-Type: application/json'"

# Do the job
case ${COMMAND} in
    listContainers)
	echo
	echo "Available containers:"
	echo
	eval ${CURL_CMD} -XGET ${API_ENDPOINT}/containers | \
	    jq -r '.result."kie-containers"."kie-container"[]."container-id"' | \
	    sed 's/^/ - /'
	echo
	;;
    listModels)
	echo "    KIE_CONTAINER  = ${KIE_CONTAINER}"
	echo
	echo "Available process model definitions:"
	echo
	eval ${CURL_CMD} -XGET ${API_ENDPOINT}/containers/${KIE_CONTAINER}/processes | \
	    jq -r '.processes[]."process-id"' | \
	    sed 's/^/ - /'
	echo
	;;
    listVariables)
	echo "    KIE_CONTAINER  = ${KIE_CONTAINER}"
	echo "    PROCESS_MODEL  = ${PROCESS_MODEL}"
	echo
	echo "Available variables in process model definition of ${PROCESS_MODEL}:"
	echo
	eval ${CURL_CMD} -XGET ${API_ENDPOINT}/containers/${KIE_CONTAINER}/processes/definitions/${PROCESS_MODEL}/variables | \
	    jq -r '.variables' | \
	    grep -v '^[\{\}]' | \
	    sed 's/^[[:space:]]*//; s/^/ - /; s/"//g'
	echo
	;;
    listInstances|listCompleted|listAborted)
	case ${COMMAND} in
	    listInstances)
		STATE=1
		WORD=active
		;;
	    listCompleted)
		STATE=2
		WORD=completed
		;;
	    listAborted)
		STATE=3
		WORD=aborted
		;;
	esac
	echo "    PROCESS_MODEL  = ${PROCESS_MODEL}"
	echo
	echo "Available ${WORD} process instances of ${PROCESS_MODEL}:"
	echo
	eval ${CURL_CMD} -XGET ${API_ENDPOINT}/queries/processes/${PROCESS_MODEL}/instances?status=${STATE} | \
	    jq -r '."process-instance"[]."process-instance-id"' | \
	    sed 's/^/ - /'
	echo
	;;
    listXidMatches)
	echo "    CORRELATION_ID = ${CORRELATION_ID}"
	echo
	echo "Available process instances with XID of ${CORRELATION_ID}:"
	echo
	eval ${CURL_CMD} -XGET ${API_ENDPOINT}/queries/processes/instance/correlation/${CORRELATION_ID} | \
	    jq -r '"ID \(."process-instance-id"), model \(."process-id"), version \(."process-version"), state \(."process-instance-state"), XID \(."correlation-key")"' | \
	    sed 's/^/ - /'
	echo
	;;
    getInstanceInfo)
	echo "    KIE_CONTAINER  = ${KIE_CONTAINER}"
	echo "    INSTANCE_ID    = ${INSTANCE_ID}"
	echo
	echo -n "Process instance ID ${INSTANCE_ID} details: "
	eval ${CURL_CMD} -XGET ${API_ENDPOINT}/containers/${KIE_CONTAINER}/processes/instances/${INSTANCE_ID} | \
	    jq -r '"model \(."process-id"), version \(."process-version"), state \(."process-instance-state"), XID \(."correlation-key")"'
	echo
	;;
    getInstanceSignals)
	echo "    KIE_CONTAINER  = ${KIE_CONTAINER}"
	echo "    INSTANCE_ID    = ${INSTANCE_ID}"
	echo
	echo "Process instance ID ${INSTANCE_ID} signals:"
	echo
	eval ${CURL_CMD} -XGET ${API_ENDPOINT}/containers/${KIE_CONTAINER}/processes/instances/${INSTANCE_ID}/signals | \
	    jq -r '.[]' | \
	    sed 's/^/ - /'
	echo
	;;
    getInstanceVars)
	echo "    KIE_CONTAINER  = ${KIE_CONTAINER}"
	echo "    INSTANCE_ID    = ${INSTANCE_ID}"
	echo
	echo "Process instance ID ${INSTANCE_ID} variables:"
	echo
	eval ${CURL_CMD} -XGET ${API_ENDPOINT}/containers/${KIE_CONTAINER}/processes/instances/${INSTANCE_ID}/variables | \
	    jq -r '.' | \
	    grep -v '^[\{\}]' | \
	    sed 's/^[[:space:]]*//; s/^/ - /; s/"//g'
	echo
	;;
    start)
	echo "    KIE_CONTAINER  = ${KIE_CONTAINER}"
	echo "    PROCESS_MODEL  = ${PROCESS_MODEL}"
	echo "    REQUEST_DATA   = \"${REQUEST_DATA}\""
	echo
	echo -n "Starting a new instance of process model ${PROCESS_MODEL}... "
	if [ -n "${REQUEST_DATA}" ]; then
	    CURL_CMD="${CURL_CMD} -d '${REQUEST_DATA}'"
	fi
	NEW_ID=$(eval ${CURL_CMD} -XPOST ${API_ENDPOINT}/containers/${KIE_CONTAINER}/processes/${PROCESS_MODEL}/instances)
	echo "done."
	echo "New instance ID is ${NEW_ID}."
	echo
	;;
    startWithXid)
	echo "    KIE_CONTAINER  = ${KIE_CONTAINER}"
	echo "    PROCESS_MODEL  = ${PROCESS_MODEL}"
	echo "    CORRELATION_ID  = ${CORRELATION_ID}"
	echo "    REQUEST_DATA   = \"${REQUEST_DATA}\""
	echo
	echo -n "Starting a new instance of process model ${PROCESS_MODEL} with XID ${CORRELATION_ID}... "
	if [ -n "${REQUEST_DATA}" ]; then
	    CURL_CMD="${CURL_CMD} -d '${REQUEST_DATA}'"
	fi
	NEW_ID=$(eval ${CURL_CMD} -XPOST ${API_ENDPOINT}/containers/${KIE_CONTAINER}/processes/${PROCESS_MODEL}/instances/correlation/${CORRELATION_ID})
	echo "done."
	echo "New instance ID is ${NEW_ID}."
	echo
	;;
    sendSignal)
	echo "    KIE_CONTAINER  = ${KIE_CONTAINER}"
	echo "    INSTANCE_ID    = ${INSTANCE_ID}"
	echo "    SIGNAL_NAME    = ${SIGNAL_NAME}"
	echo "    REQUEST_DATA   = \"${REQUEST_DATA}\""
	echo
	echo -n "Sending signal ${SIGNAL_NAME} to process instance ID ${INSTANCE_ID}... "
	if [ -n "${REQUEST_DATA}" ]; then
	    CURL_CMD="${CURL_CMD} -d '${REQUEST_DATA}'"
	fi
	eval ${CURL_CMD} -w \''HTTP response %{http_code}... '\' -XPOST ${API_ENDPOINT}/containers/${KIE_CONTAINER}/processes/instances/${INSTANCE_ID}/signal/${SIGNAL_NAME}
	echo "done."
	echo
	;;
    sendSignalByXid)
	echo "    KIE_CONTAINER  = ${KIE_CONTAINER}"
	echo "    CORRELATION_ID = ${CORRELATION_ID}"
	echo "    SIGNAL_NAME    = ${SIGNAL_NAME}"
	echo "    REQUEST_DATA   = \"${REQUEST_DATA}\""
	echo
	echo -n "Sending signal ${SIGNAL_NAME} to process instance with XID of ${CORRELATION_ID}... "
	if [ -n "${REQUEST_DATA}" ]; then
	    CURL_CMD="${CURL_CMD} -d '${REQUEST_DATA}'"
	fi
	eval ${CURL_CMD} -w \''HTTP response %{http_code}... '\' -XPOST ${API_ENDPOINT}/containers/${KIE_CONTAINER}/processes/instances/correlation/${CORRELATION_ID}/signal/${SIGNAL_NAME}
	echo "done."
	echo
	;;
    abort)
	echo "    KIE_CONTAINER  = ${KIE_CONTAINER}"
	echo "    INSTANCE_ID    = ${INSTANCE_ID}"
	echo
	echo -n "Aborting instance ID ${INSTANCE_ID}... "
	eval ${CURL_CMD} -w \''HTTP response %{http_code}... '\' -XDELETE ${API_ENDPOINT}/containers/${KIE_CONTAINER}/processes/instances/${INSTANCE_ID}
	echo "done."
	echo
	;;
esac

# End of curl-client.sh