#!/bin/sh

############################################################################
#
# MODULE:	v.rast.stats
# AUTHOR(S):	Markus Neteler
# PURPOSE:	Calculates univariate statistics from a GRASS raster map
#		only for areas covered by vector objects on a per-category base
# COPYRIGHT:	(C) 2005 by the GRASS Development Team
#
#		This program is free software under the GNU General Public
#		License (>=v2). Read the file COPYING that comes with GRASS
#		for details.
#
# TODO: do we need layer= management?
#############################################################################

#%Module
#%  description: Calculates univariate statistics from a GRASS raster map based on vector polygons and uploads statistics to new attribute columns
#%  keywords: vector, raster, statistics
#%End
#%flag
#%  key: c
#%  description: continue if upload column(s) already exist
#%END
#%option
#% key: vector
#% type: string
#% key_desc: name
#% gisprompt: old,vector,vector
#% description: Name of vector polygon map
#% required : yes
#%End
#%option
#% key: raster
#% type: string
#% key_desc: name
#% gisprompt: old,cell,raster
#% description: Name of raster map to calculate statistics from
#% required : yes
#%END
#%option
#% key: colprefix
#% type: string
#% description: Column prefix for new attribute columns
#% required : yes
#%end

if  [ -z "$GISBASE" ] ; then
    echo "You must be in GRASS GIS to run this program."
 exit 1
fi

if [ "$1" != "@ARGS_PARSED@" ] ; then
  exec g.parser "$0" "$@"
fi

PROG=`basename $0`

#### check if we have awk
if [ ! -x "`which awk`" ] ; then
    echo "$PROG: awk required, please install awk or gawk first" 2>&1
    exit 1
fi

# setting environment, so that awk works properly in all languages
unset LC_ALL
LC_NUMERIC=C
export LC_NUMERIC

#### setup temporary file
TMP="`g.tempfile pid=$$`"
if [ $? -ne 0 ] || [ -z "$TMP" ] ; then
    echo "ERROR: unable to create temporary files" 1>&2
    exit 1
fi
SQLTMP=$TMP.sql
# we need a random name
TMPNAME=`basename $TMP`

cleanup()
{
 #restore settings:
 g.region region=${TMPNAME}
 g.remove region=${TMPNAME} 2> /dev/null
 g.remove rast=${VECTOR}_${TMPNAME} 2> /dev/null
 g.remove MASK > /dev/null 2> /dev/null
 if [ $MASKFOUND -eq 1 ] ; then
   echo "Restoring previous MASK..."
   g.rename ${TMPNAME}_origmask,MASK > /dev/null
 fi
 rm -f $TMP $TMPNAME $TMP.cats $SQLTMP
}

# what to do in case of user break:
exitprocedure()
{
 echo "User break!"
 cleanup
 exit 1
}
# shell check for user break (signal list: trap -l)
trap "exitprocedure" 2 3 15


VECTOR="$GIS_OPT_VECTOR"
RASTER="$GIS_OPT_RASTER"
COLPREFIX="$GIS_OPT_COLPREFIX"

#check the input vector map
eval `g.findfile element=vector file=$VECTOR`
if [ ! "$file" ] ; then
  echo "Input vector map $VECTOR not found"
  exit 1
fi
#check the input raster map
eval `g.findfile element=cell file=$RASTER`
if [ ! "$file" ] ; then
  echo "Input raster map $RASTER not found"
  exit 1
fi

#check presence of raster MASK, put it aside
MASKFOUND=0
eval `g.findfile element=cell file=MASK`
if [ "$file" ] ; then
  echo "Raster MASK found, temporarily disabled"
  g.rename MASK,${TMPNAME}_origmask > /dev/null
  MASKFOUND=1
fi

#get RASTER resolution of map which we want to query:
#fetch separated to permit for non-square cells (latlong etc)
NSRES=`r.info -s $RASTER | grep nsres | cut -d'=' -f2`
if [ $? -ne 0 ] ; then
 echo "An error occurred reading the input raster map resolution."
 exit 1
fi
EWRES=`r.info -s $RASTER | grep ewres | cut -d'=' -f2`

#save current settings:
g.region save=${TMPNAME} > /dev/null

#Temporarily setting raster resolution to $RASTER resolution
#keep boundary settings
g.region nsres=$NSRES ewres=$EWRES -a

#prepare raster MASK
v.to.rast in=$VECTOR out=${VECTOR}_${TMPNAME} use=cat > /dev/null 2> /dev/null
if [ $? -ne 0 ] ; then
 echo "An error occurred."
 exit 1
fi


#dump cats to file to avoid "too many argument" problem:
r.cats ${VECTOR}_${TMPNAME} fs=';' 2> /dev/null | cut -d';' -f1 > $TMP.cats
#echo "List of categories found: $CATSLIST"
NUMBER=`cat $TMP.cats | wc -l | awk '{print $1}'`
if [ $NUMBER -lt 1 ] ; then
   echo "ERROR: No categories found in raster map"
   exit 1
fi

#check if DBF driver used, in this case cut to 10 chars col names:
DBFDRIVER=0
v.db.connect -g $VECTOR | cut -d' ' -f5 | grep -i dbf > /dev/null
if [ $? -eq 0 ] ; then
  DBFDRIVER=1
else
  # in case a table is missing, we'll trap a crash later...
  DBFDRIVER=0
fi
# we need this for non-DBF driver:
DB_SQLDRIVER=`v.db.connect -g $VECTOR | cut -d' ' -f5`
DB_DATABASE="`v.db.connect -g $VECTOR | cut -d' ' -f4`"

for i in n min max range mean stddev variance cf_var sum ; do
  #check if column already present
  if [ $DBFDRIVER -eq 1 ] ; then
     CURRCOLUMN="`echo ${COLPREFIX}_${i} | cut -b1-10`"
  else
     CURRCOLUMN="${COLPREFIX}_${i}"
  fi
  v.info -c $VECTOR 2> /dev/null | sed 's+^+|+g' |sed 's+$+|+g' | grep "|$CURRCOLUMN|" > /dev/null
  if [ $? -eq 0 ] ; then
    if [ $GIS_FLAG_C -ne 1 ] ; then
       echo "ERROR: Cannot create column <$CURRCOLUMN> (already present). Use -c flag to update values in this column."
       exit 1
    fi
  else
    echo "Adding column <$CURRCOLUMN>"
    v.db.addcol map=$VECTOR columns="$CURRCOLUMN double precision"
    if [ $? -eq 1 ] ; then
      echo "ERROR: Cannot continue (problem to add column)."
      exit 1
    fi
  fi
done

#loop over cats and calculate statistics:
CURRNUM=1
for i in `cat $TMP.cats` ; do
 echo "Processing category $i ($CURRNUM/$NUMBER)"
 g.remove MASK > /dev/null 2> /dev/null
 r.mapcalc "MASK=if(${VECTOR}_${TMPNAME} == $i, 1, null())" 2> /dev/null

 #n, min, max, range, mean, stddev, variance, coeff_var, sum
 eval `r.univar -g $RASTER | sed 's+nan+NULL+g'`

 if [ $DBFDRIVER -eq 1 ] ; then
  echo "UPDATE $VECTOR SET `echo ${COLPREFIX}_n| cut -b1-10`=$n     WHERE cat=$i;" > $SQLTMP
  echo "UPDATE $VECTOR SET `echo ${COLPREFIX}_min| cut -b1-10`=$min WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET `echo ${COLPREFIX}_max| cut -b1-10`=$max WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET `echo ${COLPREFIX}_range| cut -b1-10`=$range WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET `echo ${COLPREFIX}_mean| cut -b1-10`=$mean   WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET `echo ${COLPREFIX}_stddev| cut -b1-10`=$stddev     WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET `echo ${COLPREFIX}_variance| cut -b1-10`=$variance WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET `echo ${COLPREFIX}_cf_var| cut -b1-10`=$coeff_var  WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET `echo ${COLPREFIX}_sum| cut -b1-10`=$sum     WHERE cat=$i;" >> $SQLTMP
 else
  echo "UPDATE $VECTOR SET ${COLPREFIX}_n=$n     WHERE cat=$i;" > $SQLTMP
  echo "UPDATE $VECTOR SET ${COLPREFIX}_min=$min WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET ${COLPREFIX}_max=$max WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET ${COLPREFIX}_range=$range WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET ${COLPREFIX}_mean=$mean   WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET ${COLPREFIX}_stddev=$stddev     WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET ${COLPREFIX}_variance=$variance WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET ${COLPREFIX}_cf_var=$coeff_var  WHERE cat=$i;" >> $SQLTMP
  echo "UPDATE $VECTOR SET ${COLPREFIX}_sum=$sum     WHERE cat=$i;" >> $SQLTMP
 fi

 cat $SQLTMP | db.execute database=$DB_DATABASE driver=$DB_SQLDRIVER

 CURRNUM=`expr $CURRNUM + 1`
done

g.remove MASK > /dev/null 2> /dev/null

cleanup

echo "Statistics calculated from raster map <$RASTER> and uploaded to attribute table of vector map <$VECTOR>."
echo "Done."

exit 0
