#!/bin/sh
############################################################################
#
# MODULE:       d.zoom.keys
# AUTHOR(S):    Alexander Muriy
#               (Institute of Environmental Geoscience, Moscow, Russia)  
#               e-mail: amuriy AT gmail DOT com 
#
# PURPOSE:      Allows to change the current geographic region settings interactively, with a keyboard.
#
# COPYRIGHT:    (C) 02/2012 Alexander Muriy / GRASS Development Team
#
#  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.
#
############################################################################
#%Module 
#%  description: Allows to change the current geographic region settings interactively, with a keyboard. Use arrow keys to navigate, "-" to make futher, "+" (without "Shift") to make closer.
#%  keywords: display, zoom
#%End
#%Option
#%  key: mon
#%  type: string
#%  required: no
#%  key_desc: name
#%  description: Name of graphics monitor to select (default is currently selected monitor).
#%End
#%Option
#%  key: magn
#%  type: double
#%  required: no
#%  multiple: no
#%  key_desc: number
#%  description: Magnification: default is "1" (1/10 of current region). "magn" > 1 gives positive magnification, "magn" < 1 gives negative one. 
#%End
#%Flag
#% key: t
#% description: Use navigation from terminal
#%End
#%Flag
#% key: x
#% description: Use navigation in X-monitor (requires <xev> and <xdotool>)
#%End
#%Flag
#% key: r
#% description: Decrease region resolution during navigation 
#%End
############################################################

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

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

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


############################################################
cleanup()
{ 
    rm -f "$TMP*"
    if [ "$GIS_FLAG_T" -eq 1 ]; then
	stty "$tty_save"
    fi
    
    if [ "$GIS_FLAG_R" -eq 1 ]; then
	g.region nsres="$OLD_NSRES" ewres="$OLD_EWRES"
	d.redraw --q
    fi
}
############################################################
## what to do in case of user break:
exitprocedure()
{
    echo ""
    echo "User break!"
    cleanup
    exit 1
}

## shell check for user break (signal list: trap -l)
trap "exitprocedure" 2 3 15

############################################################
## check for <xev>
if [ "$GIS_FLAG_X" -eq 1 ] && [ ! -x "$(which xev)" ] ; then
    g.message -e "<xev> required, please install it first"
    exit 1
fi

## check for <xdotool>
if [ "$GIS_FLAG_X" -eq 1 ] && [ ! -x "$(which xdotool)" ] ; then
    g.message -e "<xdotool> required, please install it first"
    exit 1
fi

## check for <awk>
if [ ! -x "$(which awk)" ] ; then
    g.message -e "<awk> required, please install <awk> or <gawk> first"
    exit 1
fi

############################################################
## setup temporary files 
TMP="$(g.tempfile pid=$$)"
if [ "$?" -ne 0 ] || [ -z "$TMP" ] ; then
    g.message -e "ERROR: Unable to create temporary files."
    exit 1
fi

############################################################
## DO IT

if [ "$(d.mon -p | cut -f1 -d' ')" != "Currently" ] ; then
    g.message -e "No active monitors. Please start <d.mon ...> first"
    exit 1
fi

if [ "$GIS_FLAG_X" -eq 0 ] && [ "$GIS_FLAG_T" -eq 0 ]; then
    g.message -e "Please select method of navigation: flag \"-t\" from terminal or flag \"-x\" from X-monitor"
    exit 1
fi 

if [ "$GIS_FLAG_X" -eq 1 ] && [ "$GIS_FLAG_T" -eq 1 ]; then
    g.message -e "Please select one method of navigation: flag \"-t\" from terminal or flag \"-x\" from X-monitor"
    exit 1
fi 

MAGN_NEGAT=$(echo "$GIS_OPT_MAGN" | grep "-")
if [ "$MAGN_NEGAT" ]; then
    g.message -e "Magnification should be a positive number: default is "1" (1/10 of current region). "magn" > 1 gives positive magnification, "magn" < 1 gives negative one."
    exit 1
fi  


## region stuff 

if [ "$GIS_FLAG_R" -eq 1 ]; then
    eval $(g.region -g)
    OLD_NSRES="$nsres"
    OLD_EWRES="$ewres"
    
    curr_res=$(echo "$nsres" "$ewres" | awk '{x=($1+$2)/2; print x}')
    tmp_res=$(echo "$curr_res" | awk '{x=$1*3; print x}')

    g.region res="$tmp_res"
fi

eval $(g.region -eg)
ns_extent_round=$(printf "%.0f\n" $ns_extent)
ew_extent_round=$(printf "%.0f\n" $ew_extent)

if [ -z "$GIS_OPT_MAGN" ]; then
    MAGN=1
else
    MAGN="$GIS_OPT_MAGN"
fi

east_step=$(echo $ew_extent_round "$MAGN" | awk '{e=($1/10)*$2; print e}')
north_step=$(echo $ns_extent_round "$MAGN" | awk '{n=($1/10)*$2; print n}')


## monitors stuff 
curr_mon=$(d.mon -p | cut -d':' -f2 | sed 's/^ //g')

if [ -z "$GIS_OPT_MON" ]; then
    MON="$curr_mon"
else
    MON="$GIS_OPT_MON"
fi

NOT_RUN=$(d.mon -L | grep "$MON" | grep "not running")
if [ -z "$NOT_RUN" ]; then
    d.mon select="$MON"
else
    g.message -e "Monitor <"$MON"> is not running. Please run or select it first"
    exit 1
fi     


####  navigation in X-monitor

if [ "$GIS_FLAG_X" -eq 1 ]; then
    
### make actions scripts for AWK
    
    for ACTIONS in up down left right closer futher; do
	SCRIPT="${TMP}_"$ACTIONS".sh"
	echo '#!/bin/sh' > $SCRIPT
	
	case "$ACTIONS" in
	    up)
		echo "g.region n=n-"$north_step" s=s-"$north_step"" >> $SCRIPT
		echo "d.redraw --q" >> $SCRIPT
		;;
	    down)
		echo "g.region n=n+"$north_step" s=s+"$north_step"" >> $SCRIPT
		echo "d.redraw --q" >> $SCRIPT
		;;
	    left)
		echo "g.region w=w+"$east_step" e=e+"$east_step"" >> $SCRIPT
		echo "d.redraw --q" >> $SCRIPT
		;;
	    right)
		echo "g.region w=w-"$east_step" e=e-"$east_step"" >> $SCRIPT
		echo "d.redraw --q" >> $SCRIPT
		;;
	    closer)
		echo "g.region w=w+"$east_step" e=e-"$east_step" n=n-"$north_step" s=s+"$north_step"" >> $SCRIPT
		echo "d.redraw --q" >> $SCRIPT
		;;
	    futher)
		echo "g.region w=w-"$east_step" e=e+"$east_step" n=n+"$north_step" s=s-"$north_step"" >> $SCRIPT
		echo "d.redraw --q" >> $SCRIPT
		;;
	esac
	
    done
    
    
    eval $(g.gisenv)
    
    GRASS_version=$(g.version -g | grep "version" | cut -d'=' -f2)
    
    window_search="GRASS "${GRASS_version}" - Monitor: "${MON}" - Location: "${LOCATION_NAME}""
    GRASS_wid=$(xdotool search --title "${window_search}")

    xdotool windowactivate "${GRASS_wid}"
    
    xev -id "${GRASS_wid}" | awk '/keycode/ {print $4; fflush()}' | while read -r xev_code; do
	awk -v TMP="$TMP" -v xev="${xev_code}" 'NR % 2 { next } 
    {
          if ($0 == 111)
          system ("sh "TMP"_up.sh")
          else if ($0 == 116) 
          system ("sh "TMP"_down.sh")
          else if ($0 == 113) 
          system ("sh "TMP"_left.sh")
          else if ($0 == 114) 
          system ("sh "TMP"_right.sh")
          else if ($0 == 20) 
          system ("sh "TMP"_futher.sh")
          else if ($0 == 21) 
          system ("sh "TMP"_closer.sh")
    }'          
	
    done
fi


#### navigation in terminal

if [ "$GIS_FLAG_T" -eq 1 ]; then
    
    tty_save=$(stty -g)
    
    get_odx()
    {
	od -t o1 | awk '{ for (i=2; i<=NF; i++)
                        printf("%s%s", i==2 ? "" : " ", $i)
                        exit }'
    }
    
# Grab terminal capabilities
    tty_cuu1=$(tput cuu1 2>&1 | get_odx)            # up arrow
    tty_kcuu1=$(tput kcuu1 2>&1 | get_odx)
    tty_cud1=$(tput cud1 2>&1 | get_odx)            # down arrow
    tty_kcud1=$(tput kcud1 2>&1 | get_odx)
    tty_cub1=$(tput cub1 2>&1 | get_odx)            # left arrow
    tty_kcub1=$(tput kcud1 2>&1 | get_odx)
    tty_cuf1=$(tput cuf1 2>&1 | get_odx)            # right arrow
    tty_kcuf1=$(tput kcud1 2>&1 | get_odx)

# Some terminals send the wrong code for certain arrow keys
    if [ "$tty_cuu1" = "033 133 101" -o "$tty_kcuu1" = "033 133 101" ]; then
	tty_cudx="033 133 102"
	tty_cufx="033 133 103"
	tty_cubx="033 133 104"
    fi
    
    stty cs8 -icanon -echo min 10 time 1
    stty intr '' susp ''
    
    while true; do
	keypress=$(dd bs=10 count=1 2> /dev/null | get_odx)
	
	case "$keypress" in
	    "$tty_cuu1"|"$tty_kcuu1") 
		g.region n=n-"$north_step" s=s-"$north_step"
		d.redraw --q
		;;
	    "$tty_cud1"|"$tty_kcud1"|"$tty_cudx") 
		g.region n=n+"$north_step" s=s+"$north_step"
		d.redraw --q
		;;
	    "$tty_cub1"|"$tty_kcub1"|"$tty_cubx") 
		g.region w=w+"$east_step" e=e+"$east_step"
		d.redraw --q
		;;
	    "$tty_cuf1"|"$tty_kcuf1"|"$tty_cufx") 
		g.region w=w-"$east_step" e=e-"$east_step"
		d.redraw --q
		;;
	    055)
		g.region w=w-"$east_step" e=e+"$east_step" n=n+"$north_step" s=s-"$north_step"
		d.redraw --q
		;; 
	    075)
		g.region w=w+"$east_step" e=e-"$east_step" n=n-"$north_step" s=s+"$north_step"
		d.redraw --q
		;; 
	    003) 
		echo "User break!"
		stty $tty_save; 
		break 
		;;
	esac

    done

fi

cleanup

exit 0