#!/bin/sh
VERSION=1.1.2
PROGNAME=`basename $0`
DESC="$PROGNAME $VERSION: find minimum and maximum value in a data set"
LICENSE="Copyright (C) 2009 Dimitar Ivanov

License: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."

################################################################################
#
# mmval - find minimum and maximum value in a data set
#
# 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/>.
#
################################################################################

show_usage ()
{
cat << EOU

Usage: $PROGNAME [OPTION]... [FILE]
Options:
   -m       - find the maximum value
   -M       - find the minimum value
   -n       - prefix the output with the line number within its input
   -c <int> - consider the data in the specified column of the input
   -v       - print program version and copyright message, then exit
   -h       - display this help and exit

EOU
}

show_version()
{
     cat << !ver
$PROGNAME $VERSION
$LICENSE
!ver
}


[ x$1 = x--help ] && set -- '-h' \
  && DESC="$PROGNAME determines minimum and maximum values of data"
[ x$1 = x--version ] && set -- '-v'
opts="mMnc:vh"
opts=`getopt $opts $*` && RC=0 || { opts="-h"; RC=1; }
set -- $opts

while [ 1 ]
do
case $1 in
     -v) show_version; exit
      ;;
     -n) line_numbers=yes
      ;;
     -m) mode=${mode}min
      ;;
     -M) mode=${mode}max
      ;;
     -c) col=$2
         shift
      ;;
     -[a-zA-Z])
         echo $DESC
         show_usage
         exit
      ;;
      *) file=$2
         [ -z "$file" ] && file=-
         break
      ;;
esac
shift
done

   # File sanity check
if [ "$file" != "-" ]; then
   [ -f "$file" ] || \
     { echo "Error: no such file '$file'"; exit 1; }
   [ -r "$file" ] || \
     { echo "Error: no read permission for '$file'"; exit 2; }
fi

[ x$col = x ] && col=1

case $mode in
     min) comp='<'
     ;;
     max) comp='>'
     ;;
     maxmin|minmax)
     ;;
     *) show_usage && exit
     ;;
esac

   # Code for finding out minum or maximum values only
awk_script_min="
{
  v_i=\$$col
  if( ! i ) v_m = v_i;
  if( v_i $comp v_m ) { v_m = v_i; lines = \"\"; }
  i++
  if( v_i == v_m ) {
      if( lines != \"\" )
          lines = sprintf( \"%s\\n%d:%s\", lines, i, \$0 );
      else
          lines = sprintf( \"%d:%s\", i, \$0 )
  }
}
END \
{
  if( \"$line_numbers\" == \"yes\"  ) print lines;
  else                                print v_m;
}
"
   # The same like the minimum script
awk_script_max="$awk_script_min"

   # Code for finding out concurrently minum and maximum values
awk_script_minmax="
{
  v_i=\$$col
  if( ! i ) { v_max = v_min = v_i; }
  if( v_i < v_min ) { v_min = v_i; lines_min = \"\"; }
  if( v_i > v_max ) { v_max = v_i; lines_max = \"\"; }
  i++
  if( v_i == v_max ) {
      if( lines_max != \"\" )
          lines_max = sprintf( \"%s\\n%d:%s\", lines_max, i, \$0 );
      else
          lines_max = sprintf( \"%d:%s\", i, \$0 );
  }
  if( v_i == v_min ) {
      if( lines_min != \"\" )
          lines_min = sprintf( \"%s\\n%d:%s\", lines_min, i, \$0 );
      else
          lines_min = sprintf( \"%d:%s\", i, \$0 );
  }
}
END \
{
  if( \"$line_numbers\" == \"yes\"  ) {
      if( \"$mode\" == \"maxmin\" ) { print lines_max; print lines_min; }
      else                          { print lines_min; print lines_max; }
  } else {
      if( \"$mode\" == \"maxmin\" ) printf( \"%s\n%s\n\", v_max, v_min );
      else                          printf( \"%s\n%s\n\", v_min, v_max );
  }
}
"
   # The same like the minmax script
awk_script_maxmin="$awk_script_minmax"

   # Evaluate the variable to get the actual script name
eval awk_script="\${awk_script_$mode}"

cat $file |awk "$awk_script"
