#!/bin/sh
#
# pmlogconf setup - parse and process a group file to produce an
# initial configuration file control line
#
# Copyright (c) 2010 Ken McDonell.  All Rights Reserved.
# 
# 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 2 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, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

# Get standard environment
. $PCP_DIR/etc/pcp.env

prog=`basename $0`

_usage()
{
    echo "Usage: $prog [-v] [-h hostname] file"
    exit 1
}

HOST=localhost
verbose=false
while getopts h:v? c
do
    case $c
    in
	h)	# host to contact for "probe" tests
		HOST=$OPTARG
		;;

	v)	# verbose
		verbose=true
		;;

	?)	# eh?
		_usage
		# NOTREACHED
		;;
    esac
done
shift `expr $OPTIND - 1`

if [ $# -ne 1 ]
then
    _usage
    # NOTREACHED
fi

sts=1
tmp=/var/tmp/$$
trap "rm -f $tmp.*; exit \$sts" 0 1 2 3 15
#debug# tmp=`pwd`/tmp-setup
rm -f $tmp.*

# find "probe metric [condition] [state_rule]" line to determine action
# or
# find "force state" line
#
metric=''
options=''
force=''
eval `sed -n <"$1" \
    -e '/^#/d' \
    -e 's/?/\\\\?/g' \
    -e 's/\*/\\\\*/g' \
    -e 's/\[/\\\\[/g' \
    -e '/^probe[ 	]/{
s/^probe[ 	]*/metric='"'"'/
s/$/ /
s/ /'"'"' options='"'"'/
s/ *$/'"'"'/
p
q
}' \
    -e '/^force[ 	]/{
s/^force[ 	]*/force='"'"'/
s/ *$/'"'"'/
p
}'`
$verbose && $PCP_ECHO_PROG "$1: " >&2
if [ -n "$force" -a -n "$metric" ]
then
    $PCP_ECHO_PROG "$1: Warning: \"probe\" and \"force\" control lines ... ignoring \"force\"" >&2
    force=''
fi
if [ -z "$force" -a -z "$metric" ]
then
    $PCP_ECHO_PROG "$1: Warning: neither \"probe\" nor \"force\" control lines ... use \"force available\"" >&2
    force=available
fi

$verbose && [ -n "$metric" ] && $PCP_ECHO_PROG $PCP_ECHO_N "probe $metric $options""$PCP_ECHO_C" >&2
$verbose && [ -n "$force" ] && $PCP_ECHO_PROG $PCP_ECHO_N "force $force""$PCP_ECHO_C" >&2
rm -f $tmp.err
if [ -n "$metric" ]
then
    # probe
    echo "$options"
    echo "data `pmprobe -h $HOST -v $metric`"
    # need to handle these variants of pmprobe output
    # sample.string.hullo 1 "hullo world!"
    # sample.colour 3 101 202 303
    #
else
    # force
    $PCP_ECHO_PROG "force $force"
fi \
| sed \
    -e '/^data /!{
s/ //g
}' \
    -e '/^data [^"]*$/{
s/^data //
s/ //g
}' \
    -e '/^data .*"/{
s/^data //
s/ "//
s/" "//g
s/"$//
s/ //
}' \
| $PCP_AWK_PROG -F '
BEGIN		{ # conditions
	      i = 0
	      exists = ++i; condition[i] = "exists"
	      values = ++i; condition[i] = "values"
	      force = ++i; conditon[i] = "-"
	      regexp = ++i; condition[i] = "~" 
	      notregexp = ++i; condition[i] = "!~" 
	      gt = ++i; condition[i] = ">";
	      ge = ++i; condition[i] = ">=";
	      eq = ++i; condition[i] = "==";
	      neq = ++i; condition[i] = "!=";
	      le = ++i; condition[i] = "<=";
	      lt = ++i; condition[i] = "<";
	      # states
	      include = 100; state[include] = "include"
	      exclude = 101; state[exclude] = "exclude"
	      available = 102; state[available] = "available"
	    }
NR == 1 && $1 == "force" && NF == 2 {
	      # force variant
	      action = -1
	      for (i in state) {
		if ($2 == state[i]) {
		    action = i
		    break
		}
	      }
	      if (action == -1) {
		print "force state \"" $2 "\" not recognized" >"'$tmp.err'"
		exit
	      }
	      printf "probe=1 action=%d\n",action >>"'$tmp.out'"
	      exit
	    }
NR == 1		{ if (NF == 0) {
		op = exists	# default predicate
		yes = available	# default success action
		no = exclude	# default failure action
	      }
	      else {
		op = -1
		for (i in condition) {
		    if ($1 == condition[i]) {
			op = i
			yes = available	# default success action
			no = exclude	# default failure action
			break
		    }
		}
		if (op == -1) {
		    print "condition operator \"" $1 "\" not recognized" >"'$tmp.err'"
		    exit
		}
		if (op == exists || op == values) {
		    actarg = 2
		}
		else {
		    if (NF < 2) {
			print "missing condition operand after " condition[op] " operator" >"'$tmp.err'"
			exit
		    }
		    oprnd = $2
		    actarg = 3
		}
		if (NF < actarg) next
		str = $actarg
		for (i = actarg+1; i <= NF; i++) {
		    str = str " " $i
		}
		if (NF >= actarg && $actarg != "?") {
		    print "expected \"?\" after condition, found \"" str "\"" >"'$tmp.err'"
		    exit
		}
		if (NF >= actarg && NF < actarg+3) {
		    print "missing state rule components: \"" str "\"" >"'$tmp.err'"
		    exit
		}
		if (NF >= actarg && NF > actarg+3) {
		    print "extra state rule components: \"" str "\"" >"'$tmp.err'"
		    exit
		}
		actarg++
		yes = -1
		for (i in state) {
		    if ($actarg == state[i]) {
			yes = i
			break
		    }
		}
		if (yes == -1) {
		    print "sucess state \"" $actarg "\" not recognized" >"'$tmp.err'"
		    exit
		}
		actarg++
		if ($actarg != ":") {
		    print "expected \":\" in state rule, found \"" $actarg "\"" >"'$tmp.err'"
		    exit
		}
		actarg++
		no = -1
		for (i in state) {
		    if ($actarg == state[i]) {
			no = i
			break
		    }
		}
		if (no == -1) {
		    print "failure state \"" $actarg "\" not recognized" >"'$tmp.err'"
		    exit
		}
	      } 
	    }
NR == 2		{ #debug# printf "op: %d %s pmprobe: %s",op, condition[op],$0
	      probe = 0
	      if ($2 < 0) {
		# error from pmprobe
		;
	      }
	      else {
		if (op == exists) {
		    probe = 1
		}
		else if (op == values) {
		    if ($2 > 0) probe = 1
		}
		else if (op == regexp) {
		    for (i = 3; i <= NF; i++) {
			if ($i ~ oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == notregexp) {
		    for (i = 3; i <= NF; i++) {
			if ($i !~ oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == gt) {
		    for (i = 3; i <= NF; i++) {
			if ($i > oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == ge) {
		    for (i = 3; i <= NF; i++) {
			if ($i >= oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == eq) {
		    for (i = 3; i <= NF; i++) {
			if ($i == oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == neq) {
		    for (i = 3; i <= NF; i++) {
			if ($i != oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == le) {
		    for (i = 3; i <= NF; i++) {
			if ($i <= oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == lt) {
		    for (i = 3; i <= NF; i++) {
			if ($i < oprnd) {
			    probe = 1
			    break
			}
		    }
		}
	      }
	      if (probe == 1) 
		action = yes
	      else
		action = no
	      printf "probe=%d action=%d\n",probe,action >>"'$tmp.out'"
	    }'

if [ -f $tmp.err ]
then
    $verbose && $PCP_ECHO_PROG >&2
    $PCP_ECHO_PROG "$1: Error: `cat $tmp.err`" >&2
elif [ -f $tmp.out ]
then
    probe=''
    action=''
    eval `cat $tmp.out`
    if $verbose
    then
	case $probe
	in
	    0)
		probe_s="failure"
		;;
	    1)
		probe_s="success"
		;;
	    *)
		probe_s="unknown ($probe)"
		;;
	esac
	case $action
	in
	    100)
		action_s="include"
		;;
	    101)
		action_s="exclude"
		;;
	    102)
		action_s="available"
		;;
	    *)
		action_s="unknown ($action)"
		;;
	esac
	$PCP_ECHO_PROG " -> probe=$probe_s action=$action_s" >&2
    fi
    if [ $action = 100 -o $action = 102 ]
    then
	mode='n'
	[ $action = 100 ] && mode='y'
	delta=`sed -n <"$1" -e /'^delta[ 	]/s/delta[ 	]*//p'`
	[ -z "$delta" ] && delta='default'
	echo "#+ $1:$mode:$delta:"
    else
	echo "#+ $1:x::"
    fi
    sts=0
else
    $verbose && $PCP_ECHO_PROG >&2
    $PCP_ECHO_PROG "$1: Botch: no errors and no probe results ... try -v" >&2
fi

exit
