#!/bin/bash
#
############################################################################
#
# MODULE:       v.flip
#
# AUTHOR(S):    Maciej Sieczka, sieczka@biol.uni.wroc.pl
#		Intitute of Plant Biology, Wroclaw University, Poland
#
# PURPOSE:      Flip direction of selected vector lines.
#
# VERSION:	1.6, developed over Grass 6.1 CVS 2006.05.19
#
# COPYRIGHT:    (c) 2006 Maciej Sieczka
#
#               This program is free software under the GNU General Public
#               License (>=v2). Read the file COPYING that comes with GRASS
#               for details.
#
#############################################################################

#%Module
#%  description: Flip direction of selected vector lines.
#%END
#%option
#% key: input
#% type: string
#% gisprompt: old,vector,vector
#% description: Input vector name
#% required : yes
#%END
#%option
#% key: layer
#% type: string
#% description: Input's layer containing lines to be flipped
#% required : yes
#%END
#%option
#% key: cat
#% type: string
#% description: Category ranges of lines to be flipped (e.g. 1,3-8,13)
#% required : yes
#%END
#%option
#% key: output
#% type: string
#% gisprompt: new,dig,vector
#% description: Output vector name
#% required : yes
#%END

# called from Grass?
if test "$GISBASE" = ""; then
 echo "ERROR: You must be in GRASS GIS to run this program." >&2
 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 "ERROR: awk required, please install awk or gawk first." 2>&1
    exit 1
fi

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

# set up temporary files
TMP="`g.tempfile pid=$$`"
if [ $? -ne 0 ] || [ -z "$TMP" ] ; then
    echo "ERROR: Unable to create temporary files." 1>&2
    exit 1
fi

cleanup()
{
 \rm -f $TMP $TMP.${PROG} $TMP.${PROG}.flip $TMP.${PROG}.meta $TMP.${PROG}.data $TMP.${PROG}.head $TMP.${PROG}.cat_toflip $TMP.${PROG}.cat_all $TMP.${PROG}.cat_asis $TMP.${PROG}.cat_asis_short $TMP.${PROG}.start_stop
}

# 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

INPUT="$GIS_OPT_INPUT"
OUTPUT="$GIS_OPT_OUTPUT"
CAT="$GIS_OPT_CAT"
LAYER="$GIS_OPT_LAYER"

for i in toflip leaveasis flipped patched; do
   g.findfile elem=vector file=${OUTPUT}_$i > /dev/null
   if [ $? -eq 0 ] ; then
      echo "ERROR: Intermediate vector <${OUTPUT}_$i> already exists." 1>&2
      exit 1
   fi
done



### DO IT ###

# is a table connected to the given layer?
v.db.connect -p layer=$LAYER map=$INPUT  >/dev/null 2>&1

CNCTSTAT=$?

if [ "$CNCTSTAT" -eq "0" ]; then
# extract the database connection settings of the input vector
cnct=`v.db.connect -g layer=$LAYER map=$INPUT`
tbl=`echo $cnct | cut -d " " -f2`
key=`echo $cnct | cut -d " " -f3`
dbs=`echo $cnct | cut -d " " -f4`
drv=`echo $cnct | cut -d " " -f5`
fi

# extract lines to be reverted into separate vector
v.extract -t layer=$LAYER input=$INPUT list=$CAT output="${OUTPUT}_toflip" > /dev/null

#transform it to ascii for reverting lines
v.out.ascii input="${OUTPUT}_toflip" format=standard  > $TMP.${PROG}.flip

# get categories of lines NOT to be reverted
v.category layer=$LAYER input="${OUTPUT}_toflip" option=print > $TMP.${PROG}.cat_toflip
v.category layer=$LAYER input=$INPUT option=print > $TMP.${PROG}.cat_all
cat $TMP.${PROG}.cat_toflip $TMP.${PROG}.cat_all | sort -n | uniq -u > $TMP.${PROG}.cat_asis

# translate long category list like "1,2,3,...,100" to "1-100"
# (to avoid hitting the 4096 chars Bash variable limit)

awk '
{if (NR==1) {prev=$1; print}

	    else {if ($1==prev+1) {foll="-"$1}

		  else {print foll; print ","$1; foll=""}
prev=$1}
}
END {print foll}
' $TMP.${PROG}.cat_asis | grep . > $TMP.${PROG}.cat_asis_short

asis=`cat $TMP.${PROG}.cat_asis_short`
asis=`echo $asis | sed 's/ //g'`

# extract lines NOT to be reverted into a separate vector

v.extract -t layer=$LAYER input=$INPUT list=$asis output="${OUTPUT}_leaveasis" > /dev/null

# extract header from to-be-reverted vector (for later patching)

awk '(NR<11)' $TMP.${PROG}.flip > $TMP.${PROG}.head

# extract vector type, number of lines and categories (for later patching)

awk '
{if ((NR>10) && ($1=="L") || ($1=='$LAYER')) {print} else if (NR>10) {print""}}
' $TMP.${PROG}.flip > $TMP.${PROG}.meta

# get starting and ending lines of each line feature

awk '
($1 == "L") {print FNR+1","$2+FNR}
' $TMP.${PROG}.flip > $TMP.${PROG}.start_stop

# pipe vertices into a file...

for a in `cat $TMP.${PROG}.start_stop`; do

	echo >> $TMP.${PROG}.data

	# ...reverting lines at the same time (tac)
	cat $TMP.${PROG}.flip | sed -n "$a p" | tac >> $TMP.${PROG}.data

	# empty echoes are to make empty lines where needed
	echo >> $TMP.${PROG}.data
done

# merge header, data and meta into final, reverted ascii vector

paste -d '' $TMP.${PROG}.data $TMP.${PROG}.meta >> $TMP.${PROG}.head
echo

v.in.ascii input=$TMP.${PROG}.head output="${OUTPUT}_flipped" format=standard > /dev/null

# patch reverted and left-as-is, clean to snap nodes
v.patch input="${OUTPUT}_leaveasis","${OUTPUT}_flipped" output="${OUTPUT}_patched" > /dev/null
echo
v.clean input="${OUTPUT}_patched" output=$OUTPUT type=line tool=snap thresh=0.0001 > /dev/null
echo

### ALL DONE ###

cleanup

g.remove vect="${OUTPUT}_toflip","${OUTPUT}_leaveasis","${OUTPUT}_flipped","${OUTPUT}_patched" > /dev/null

if [ "$CNCTSTAT" -eq "0" ]; then
# copy the original table using the OUTPUT vector name, and connect to the OUTPUT
db.copy from_driver=$drv from_database=$dbs from_table=$tbl to_driver=$drv to_database=$dbs to_table=$OUTPUT > /dev/null
v.db.connect map=$OUTPUT layer=$LAYER driver=$drv database=$dbs table=$OUTPUT key=$key > /dev/null
fi

echo
