#!/bin/sh
#
############################################################################
#
# MODULE:       v.in.garmin
#
# AUTHOR(S):    Based on v.in.garmin.sh for GRASS 5.0 by Andreas Lange
#                  with bug fixes by Glynn Clements and Markus Neteler
#               Updated for GRASS 5.3 and 5.7 by Hamish Bowman
#
# PURPOSE:      Import GPS data from Garmin receiver into a GRASS vector map
#
# COPYRIGHT:    Original version (c) Andreas Lange
#               Updates by Hamish Bowman (c) the GRASS Development Team
#
#############################################################################
#
# REQUIREMENTS:
#      -  gpstrans from Carsten Tschach et al.
#         At the time of writing, gpstrans is at version 0.39.
#           get gpstrans from:
#             http://gpstrans.sourceforge.net
#           older versions might be found at:
#             http://www.metalab.unc.edu/pub/Linux/science/cartography/
#             ftp://www.mayko.com/pub/gpstrans
#      OR
#      - garmin-utils:  http://www.snafu.org
#        At the time of writing, garmin-utils is at version 2.5.
#
#      -  unix tools: grep, cat, tac, cut, paste, awk/nawk or gawk, sed
#      -  cs2cs from PROJ.4    http://proj.maptools.org
# NOTES:
#      - output may be slightly different  (millimeters) than v.in.gpsbabel
#        due to different number of downloaded decimal places.

#%Module
#% description: Download waypoints, routes, and tracks from a Garmin GPS receiver into a vector map.
#% keywords: vector, import, GPS
#%End
#%flag
#%  key: v
#%  description: Verbose mode
#%end
#%flag
#%  key: w
#%  description: Download Waypoints from GPS
#%end
#%flag
#%  key: r
#%  description: Download Routes from GPS
#%end
#%flag
#%  key: t
#%  description: Download Track from GPS
#%end
#%flag
#%  key: p
#%  description: Force import of track or route data as points
#%end
#%flag
#%  key: u
#%  description: Use gardump instead of gpstrans as the download program
#%end
#%flag
#%  key: z
#%  description: Import track in 3D (gardump only)
#%end
#%flag
#%  key: k
#%  description: Do not attempt projection transform from WGS84
#%end
#%option
#% key: output
#% type: string
#% gisprompt: new,vector,vector
#% description: Name for output vector map (omit for display to stdout)
#% required : no
#%end
#%option
#% key: port
#% type: string
#% description: Port Garmin receiver is connected to
#% answer: /dev/gps
#% required : no
#%end

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

if [ "$1" != "@ARGS_PARSED@" ] ; then
    # save command line
    CMDLINE=`basename "$0"`
    for arg in "$@" ; do
	CMDLINE="$CMDLINE \"$arg\""
    done
    export CMDLINE
    exec g.parser "$0" "$@"
fi


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

### setup enviro vars ###
MAPSET=`g.gisenv get=MAPSET`
LOCATION_NAME=`g.gisenv get=LOCATION_NAME`
GISDBASE=`g.gisenv get=GISDBASE`
LOCATION="$GISDBASE/$LOCATION_NAME/$MAPSET"

PROG=`basename "$0"`

if [ $GIS_FLAG_U -eq 0 ] ; then
    #### check for gpstrans
    if [ ! -x "`which gpstrans`" ] ; then
	g.message -e "gpstrans program not found, install it first\
	  http://gpstrans.sourceforge.net"
	exit 1
    fi
else
    #### check for gardump from garmin-utils
    if [ ! -x "`which gardump`" ] ; then
	g.message -e "gardump program not found (from garmin-utils), install it first\
	  http://www.snafu.org"
	exit 1
    fi
fi

#### check for cs2cs
if [ ! -x "`which cs2cs`" ] ; then
    g.message -e "cs2cs program not found, install it first\
      http://proj.maptools.org"
    exit 1
fi

#### check if we have awk
if [ ! -x "`which awk`" ] ; then
    g.message -e  "awk required, please install awk or gawk first"
    exit 1
fi

#### check if we have tac
# perhaps try `type -t` instead of `which`, as it is more POSIXy
if [ -x "`which tac`" ] ; then
   TAC=tac
else
   TAC=awk_tac
fi

awk_tac()
{
   awk '1 { last = NR; line[last] = $0; }
          END { for (i = last; i > 0; i--) { print line[i]; } }'
}

#### setup temporary file
TEMPFILE="`g.tempfile pid=$$`"
if [ $? -ne 0 ] || [ -z "$TEMPFILE" ] ; then
    g.message -e "Unable to create temporary files"
    exit 1
fi

#### trap ctrl-c so that we can clean up tmp
trap 'rm -f "${TEMPFILE}"*' 2 3 15


#### process command line arguments
WPT=0 ; RTE=0 ; TRK=0 ; KEEP_WGS84=0; VERBOSE=0

# some backwards compat verbosity
if [ $GIS_FLAG_V -eq 1 ] ; then
    VERBOSE=1
    GRASS_VERBOSE=3
    export GRASS_VERBOSE
elif [ -n "$GRASS_VERBOSE" ] && [ "$GRASS_VERBOSE" -eq 3 ] ; then
    VERBOSE=1
fi

if [ -n "$GIS_OPT_OUTPUT" ] ; then
    NAME="$GIS_OPT_OUTPUT"
    if [ $VERBOSE -eq 1 ] ; then
	g.message message="output=$NAME"
    fi
fi
if [ -n "$GIS_OPT_PORT" ] ; then
    GPSPORT="-p$GIS_OPT_PORT"
    if [ $VERBOSE -eq 1 ] ; then
	g.message message="port=$GIS_OPT_PORT"
    fi
fi


if [ "`expr $GIS_FLAG_W + $GIS_FLAG_R + $GIS_FLAG_T`" -gt 1 ] ; then
    g.message -e "One feature at a time please. Use v.patch if you need to combine them."
    rm -f "$TEMPFILE"
    exit 1
fi


if [ $GIS_FLAG_W -eq 1 ] ; then
    WPT=1
    CREATE_POINTS=1
fi
if [ $GIS_FLAG_R -eq 1 ] ; then
    RTE=1
    CREATE_POINTS=0
fi
if [ $GIS_FLAG_T -eq 1 ] ; then
    TRK=1
    CREATE_POINTS=0
fi

if [ $GIS_FLAG_P -eq 1 ] ; then
    CREATE_POINTS=1
fi
if [ $GIS_FLAG_K -eq 1 ] ; then
    KEEP_WGS84=1
fi

if [ "`expr $WPT + $TRK + $RTE`" -eq 0 ] ; then
    g.message -e "Must request either waypoints, route, or track."
    rm -f "$TEMPFILE"
    exit 1
fi

if [ $GIS_FLAG_Z -eq 1 ] &&  [ $TRK -ne 1 ] ; then
    g.message -e "3D import is only supported for tracks so far"
    rm -f "$TEMPFILE"
    exit 1
fi


#### check that receiver is responding on $GPSPORT
if [ $GIS_FLAG_U -eq 0 ] ; then
    # sadly gpstrans 0.39 returns 0 after timeout.. hopefully fixed someday.
    gpstrans "$GPSPORT" -i 1> /dev/null
    if [ $? -ne 0 ] ; then
	g.message -e message="Receiver on $GIS_OPT_PORT not responding, exiting"
	rm -f "$TEMPFILE"
	exit 1
    fi
elif [ $VERBOSE -eq 1 ] ; then
    # not really needed for gardump as exit code is meaningful?
    g.message "Testing GPS connection..."
    gardump -u -p "$GIS_OPT_PORT" 1>&2
    if [ $? -ne 0 ] ; then
	g.message -e message="Receiver on $GIS_OPT_PORT not responding, exiting"
	rm -f "$TEMPFILE"
	exit 1
    fi
    g.message "GPS connection ok"
fi

#### set up projection info
IN_PROJ="+proj=longlat +datum=WGS84"
OUT_PROJ="`g.proj -jf`"
PROJ_TYPE=`g.region -p | grep 'projection' | cut -f2 -d" "`
if [ $PROJ_TYPE -eq 0 ] && [ $KEEP_WGS84 -ne 1 ] ; then
    g.message -e "Cannot project to a XY location."
    rm -f "$TEMPFILE"
    exit 1
fi


#### receive data
if [ $WPT -eq 1 ] ; then
    g.message "Receiving Waypoints..."
    if [ $GIS_FLAG_U -eq 0 ] ; then
	gpstrans "$GPSPORT" -dw > "$TEMPFILE".gpst 2>/dev/null
	EXITCODE=$?
    else
	gardump -w -p "$GIS_OPT_PORT" > "$TEMPFILE".gard
	EXITCODE=$?
    fi
fi
if [ $RTE -eq 1 ] ; then
    g.message "Receiving Routes..."
    if [ $GIS_FLAG_U -eq 0 ] ; then
	gpstrans "$GPSPORT" -dr > "$TEMPFILE".gpst 2>/dev/null
	EXITCODE=$?
    else
	gardump -r -p "$GIS_OPT_PORT" > "$TEMPFILE".gard
	EXITCODE=$?
    fi
fi
if [ $TRK -eq 1 ] ; then
    g.message "Receiving Tracks..."
    if [ $GIS_FLAG_U -eq 0 ] ; then
	gpstrans "$GPSPORT" -dt > "$TEMPFILE".gpst 2>/dev/null
	EXITCODE=$?
    else
	gardump -t -p "$GIS_OPT_PORT" > "$TEMPFILE".gard
	EXITCODE=$?
    fi
fi
#### check success/failure
if [ "$EXITCODE" -ne 0 ] ; then
    g.message -e "Retrieving data."
    rm -f "${TEMPFILE}"*
    exit 1
fi

if [ $GIS_FLAG_U -eq 0 ] ; then
    if [ ! -e "${TEMPFILE}.gpst" ] || [ `wc -l < "${TEMPFILE}.gpst"` -le 1 ] ; then
	g.message -w 'No Data! Exiting.'
	rm -f "${TEMPFILE}"*
	exit 0
    fi
else
    if [ "`cat "${TEMPFILE}.gard" | grep -v '^\[' | grep -v '^#' -c`" -eq 0 ] ; then
	g.message -w 'No Data! Exiting.'
	rm -f "${TEMPFILE}"*
	exit 0
    fi
fi

if [ $GIS_FLAG_U -eq 0 ] ; then
    #### check which projection we are working with
    PROJ="`head -n 1 "${TEMPFILE}.gpst" | sed -e 's/Format: //' | sed -e 's/  UTC.*//'`"
    if [ $VERBOSE -eq 1 ] ; then
	g.message message="Coordinate format: ${PROJ}"
    fi
    if [ "$PROJ" != "DDD" ] ; then
	# Why? Because v.in.ascii cannot, and cs2cs with trouble deals with DMS
	# or DM.MM formatted input and I'm not going to start doing that sort
	# of math in a shell script.
	g.message -e message="Only DDD coordinates currently supported. [$PROJ]"
	rm -f "${TEMPFILE}"*
	exit 1
    fi
    IS_WGS84="`head -n 1 "$TEMPFILE".gpst | grep 'WGS 84'`"
else
    # gardump
    IS_WGS84=TRUE
fi

g.message -v "Processing data..."

###################################
if [ $CREATE_POINTS -eq 1 ] ; then
###################################

    if [ $GIS_FLAG_U -eq 0 ] ; then
        # gpstrans
	if [ $WPT -eq 1 ] ; then
	    cat "${TEMPFILE}.gpst" | sed -e '1d' | awk -F '\t' '{print $6 " " $5}' > "$TEMPFILE".base
	    cat "${TEMPFILE}.gpst" | sed -e '1d' | cut -f1,2,3 | tr '\t' '|' > "$TEMPFILE".attributes
	    ATTR_COLS='x DOUBLE PRECISION, y DOUBLE PRECISION, type VARCHAR(1), name VARCHAR(10), comments VARCHAR(40)'
	fi
	if [ $RTE -eq 1 ] ; then
	    cat "${TEMPFILE}.gpst" | sed -e '1d' | grep '^W' | awk -F '\t' '{print $6 " " $5}' > "$TEMPFILE".base
	    cat "${TEMPFILE}.gpst" | sed -e '1d' | grep '^W' | cut -f1,2,3 | tr '\t' '|' > "$TEMPFILE".attributes
	    ATTR_COLS='x DOUBLE PRECISION, y DOUBLE PRECISION, type VARCHAR(1), name varchar(10), comments VARCHAR(40)'
	fi
	if [ $TRK -eq 1 ] ; then
	    # we use uniq here as gpstrans can dupe up track points !?
	    uniq "${TEMPFILE}.gpst" | sed -e '1d' | grep '^T' | awk -F '\t' '{print $4 " " $3}' > "$TEMPFILE".base
	    uniq "${TEMPFILE}.gpst" | sed -e '1d' | grep '^T' | cut -f1,2 | tr '\t' '|' > "$TEMPFILE".attributes
	    ATTR_COLS='x DOUBLE PRECISION, y DOUBLE PRECISION, type VARCHAR(1), localtime VARCHAR(40)'
	    HAVE_ALT=FALSE
	fi
    else
	# gardump from garmin-utils
	if [ $WPT -eq 1 ] || [ $RTE -eq 1 ] ; then
	    # **n [route name]
	    # lat long [A:alt] [S:sym] [D:display] [I:id] [C:cmnt] [W:wpt info] [L:link]
	    grep -E -v '^\[|^#|^\*\*' "${TEMPFILE}.gard" | awk '{print $2 " " $1}' > "$TEMPFILE".base

	    ROUTE_NUM=""
	    ROUTE_NAME=""
	    # this will be very slow :-(  maybe could be written as an awk script?
	    while read LINE ; do
		unset A_VAL S_VAL D_VAL I_VAL C_VAL W_VAL L_VAL
		if [ `echo "$LINE" | grep -E -c '^\[|^#'` -eq 1 ] ; then
		    continue
		fi
		if [ `echo "$LINE" | grep -c '^\*\*'` -eq 1 ] ; then
		   ROUTE_NUM=`echo "$LINE" | cut -f1 -d' ' | sed -e 's/^\*\*//'`
		   ROUTE_NAME=`echo "$LINE" | grep ' ' | cut -f2- -d' '`
		   continue
		fi
		A_VAL=`echo "$LINE" | sed -e 's/ [ASDICWL]:/\n&/g' | grep '^ A:' | sed -e 's/^ A://'`
		S_VAL=`echo "$LINE" | sed -e 's/ [ASDICWL]:/\n&/g' | grep '^ S:' | sed -e 's/^ S://'`
		D_VAL=`echo "$LINE" | sed -e 's/ [ASDICWL]:/\n&/g' | grep '^ D:' | sed -e 's/^ D://'`
		I_VAL=`echo "$LINE" | sed -e 's/ [ASDICWL]:/\n&/g' | grep '^ I:' | sed -e 's/^ I://'`
		C_VAL=`echo "$LINE" | sed -e 's/ [ASDICWL]:/\n&/g' | grep '^ C:' | sed -e 's/^ C://'`
		W_VAL=`echo "$LINE" | sed -e 's/ [ASDICWL]:/\n&/g' | grep '^ W:' | sed -e 's/^ W://'`
		L_VAL=`echo "$LINE" | sed -e 's/ [ASDICWL]:/\n&/g' | grep '^ L:' | sed -e 's/^ L://'`
### hack for broken v.in.ascii scan (last col must not be empty for all records)
###  poi_link column should be INTEGER type.
		if [ -z "$L_VAL" ] ; then
		   L_VAL=NULL
		fi

		if [ $WPT -eq 1 ] ; then
		    echo "$A_VAL|$S_VAL|$D_VAL|$I_VAL|$C_VAL|$W_VAL|$L_VAL" >> "$TEMPFILE".attributes
		elif [ $RTE -eq 1 ] ; then
		    echo "$ROUTE_NUM|$ROUTE_NAME|$A_VAL|$S_VAL|$D_VAL|$I_VAL|$C_VAL|$W_VAL|$L_VAL" >> "$TEMPFILE".attributes
		fi
	    done < "${TEMPFILE}.gard"

	    if [ $WPT -eq 1 ] ; then
		ATTR_COLS='x DOUBLE PRECISION, y DOUBLE PRECISION, altitude DOUBLE PRECISION, symbol INTEGER, smbl_flag INTEGER, name VARCHAR(15), comments VARCHAR(50), poi_code VARCHAR(40), poi_link VARCHAR(4)'
	    elif [ $RTE -eq 1 ] ; then
		ATTR_COLS='x DOUBLE PRECISION, y DOUBLE PRECISION, route_num INTEGER, route_name VARCHAR(40), altitude DOUBLE PRECISION, symbol INTEGER, smbl_flag INTEGER, name VARCHAR(15), comments VARCHAR(50), poi_code VARCHAR(40), poi_link VARCHAR(4)'
	    fi
	fi

	if [ $TRK -eq 1 ] ; then
	    # [yyyy-mm-dd hh:mm:ss] lat long [alt] [start]
	    unset HAVE_ALT
	    # some tracks don't have time/date, so we have to decide on the fly
	    grep -v '^\[\|^#\|^Track:' "${TEMPFILE}.gard" | \
	      awk '{ if ( $0 ~ /..:..:../) {
			print $4 " " $3
		     } else {
			print $2 " " $1
		     }
		   }' > "$TEMPFILE".base

	    grep -v '^\[\|^#\|^Track:' "${TEMPFILE}.gard" | \
	      awk '{ if ( $0 ~ /..:..:../) {
			print $1 "|" $2 "|" $5 "|" $6
		     } else {
			print "||" $3 "|" $4
		     }
		   }' > "$TEMPFILE.attr"

	    # check if there is any altitude data
	    if [ `cut -f3 -d'|' "$TEMPFILE.attr" | grep -c 'start'` -ge 1 ] ; then
		HAVE_ALT=FALSE
		ATTR_COLS='x DOUBLE PRECISION, y DOUBLE PRECISION, gmt_date VARCHAR(10), gmt_time VARCHAR(8), new_track VARCHAR(5)'
		if [ $GIS_FLAG_Z -eq 1 ] ; then
		    g.message -w "No altitude data found, creating 2D vector map"
		fi
	    else
		HAVE_ALT=TRUE
		ATTR_COLS='x DOUBLE PRECISION, y DOUBLE PRECISION, gmt_date VARCHAR(10), gmt_time VARCHAR(8), altitude DOUBLE PRECISION, new_track VARCHAR(5)'
	    fi

	    # check if there is any track name data
	    if [ `grep -c '^Track:' "${TEMPFILE}.gard"` -ge 1 ] ; then
		ATTR_COLS="$ATTR_COLS, track_name VARCHAR(15)"

		# create data for track name column
# need extra if(TRK) else NULL stuff for v.in.ascii empty last column bug
		grep -v '^\[\|^#' "${TEMPFILE}.gard" | awk \
		  '/^Track:/ {TRK=$0; sub(/^Track: /, "", TRK)} ;
		   /^[-0-9]/ {if(TRK) {print TRK} else {print "NULL"}}' > "$TEMPFILE.trackname"
		paste -d'|' "$TEMPFILE.attr" "$TEMPFILE.trackname"  > "$TEMPFILE.attributes"
	    else
		cp "$TEMPFILE.attr" "$TEMPFILE.attributes"
	    fi
	fi
    fi

    #### reproject if needed (only consider 2D)
    if [ -z "$IS_WGS84" ] || [ $KEEP_WGS84 -eq 1 ] ; then
	g.message "No projection transformation performed"
	cp "${TEMPFILE}.base" "${TEMPFILE}.P_base"
    else
	g.message "Attempting waypoint projection transform with cs2cs..."
	cs2cs -f %.7f $IN_PROJ +to $OUT_PROJ < "${TEMPFILE}.base" > "${TEMPFILE}.P_base"
	EXITCODE=$?
	# check if transform REALLY worked (e.g. grid file not found)
	BAD_PTS="`grep -c "^\*" "${TEMPFILE}.P_base"`"
	if [ "$BAD_PTS" -gt 0 ] ; then
	    g.message message=""
	    g.message -w "$BAD_PTS point(s) failed reprojection."
	    EXITCODE=1
	fi
	if [ $EXITCODE -ne 0 ] ; then
	    g.message -w "Projection transform failed, retaining WGS84"
	    g.message message=""
	    cp -f "${TEMPFILE}.base" "${TEMPFILE}.P_base"
	fi
    fi
    cat "${TEMPFILE}.P_base" | awk '{print $1 "|" $2}' > "${TEMPFILE}.vertices"

    #### and put back together
    # wpt list:   x|y|    W   MOB    04-OCT-03 08:07
    paste -d"|" "$TEMPFILE".vertices "$TEMPFILE".attributes > "$TEMPFILE".asc


    if [ -z "$NAME" ] ; then
	g.message "ASCII file redirected to stdout"
	cat "${TEMPFILE}.asc" 2> /dev/null
    else
	#### import into new ascii points file
	if [ $WPT -eq 1 ] ; then
	    g.message "Importing Waypoints..."
	    v.in.ascii input="${TEMPFILE}.asc" output="$NAME" cat=0 columns="$ATTR_COLS" --quiet
	    EXITCODE=$?
	fi
	if [ $RTE -eq 1 ] ; then
	    g.message "Importing Routes as points..."
	    v.in.ascii input="${TEMPFILE}.asc" output="$NAME" cat=0 columns="$ATTR_COLS"
	    EXITCODE=$?
	fi
	if [ $TRK -eq 1 ] ; then
	    if [ $GIS_FLAG_Z -eq 1 ] && [ "$HAVE_ALT" = "TRUE" ] ; then
		g.message "Importing Track as 3D points..."
		v.in.ascii input="${TEMPFILE}.asc" output="$NAME" cat=0 columns="$ATTR_COLS" -z z=5
		EXITCODE=$?
	    else
		g.message "Importing Track as points..."
		v.in.ascii input="${TEMPFILE}.asc" output="$NAME" cat=0 columns="$ATTR_COLS"
		EXITCODE=$?
	    fi
	fi

	if [ $EXITCODE -ne 0 ] ; then
	    g.message -e "While importing data with v.in.ascii"
	    rm -f "${TEMPFILE}"*
	    exit 1
	fi

    fi

#####################
else # CREATE_LINES
#####################

    if [ $GIS_FLAG_U -eq 0 ] ; then
	#gpstrans

	#### prepare line components
	if [ $RTE -eq 1 ] ; then
	    # add vertex counts
	    cat "${TEMPFILE}.gpst" | sed -e '1d' | "$TAC" | awk 'BEGIN { FS="\t" ; R=0 } \
		$1=="W" { printf(" %.7f %.7f\n", $6, $5) ; ++R } ; \
		$1=="R" { printf("L %d 1\n", R) ; R=0 } END {;}' | "$TAC" > "${TEMPFILE}.base"

	    # create attr table: cat(int), id number(int 0-19), name varchar(16+), starting_wpt(varchar 10)
	    cat "${TEMPFILE}.gpst" | grep '^R' | cut -f2,3 | grep -n '^' | \
		sed -e 's/:/\t/' > "${TEMPFILE}.route_ids"
	    cat "${TEMPFILE}.gpst" | sed -e '1d' | grep '^R' -A 1 | grep '^W' | cut -f2 > "${TEMPFILE}.route_start"
	    paste "${TEMPFILE}.route_ids" "${TEMPFILE}.route_start" > "${TEMPFILE}.route_atts"
	    ATTR_FILE="${TEMPFILE}.route_atts"
	    ATTR_COLS='cat INT, route_id INT, name VARCHAR(20), start_wpt VARCHAR(10)'

	elif [ $TRK -eq 1 ] ; then
	    # add vertex counts
	    cat "${TEMPFILE}.gpst" | sed -e '1d' | "$TAC" | awk 'BEGIN { FS="\t" ; R=0 } \
		$1=="T" { printf(" %.7f %.7f\n", $4, $3) ; ++R } ; \
		$1=="" { printf("L %d 1\n", R) ; R=0 } END {;}' | "$TAC" > "${TEMPFILE}.base"

	    # create attr table: cat(int), start_time varchar(40), start_lat(double precision), start_lon(double precision), \
	    #			    end_time varchar(40), end_lat(double precision), end_lon(double precision)
	    cat "${TEMPFILE}.gpst" | sed -e '1d' | grep '^$' -B 1 | grep '^T' | cut -f2,3,4 > "${TEMPFILE}.end_time"
	    cat "${TEMPFILE}.gpst" | grep '^T' | tail -n 1 | cut -f2,3,4 >> "${TEMPFILE}.end_time"
	    cat "${TEMPFILE}.gpst" | sed -e '1d' | grep '^$' -A 1 | grep '^T' | cut -f2,3,4 | \
		grep -n '^' | sed -e 's/:/\t/'  > "${TEMPFILE}.start_time"
	    paste "${TEMPFILE}.start_time" "${TEMPFILE}.end_time" > "${TEMPFILE}.track_atts"
	    ATTR_FILE="${TEMPFILE}.track_atts"
	    ATTR_COLS='cat INT, start_time VARCHAR(40), start_lat DOUBLE PRECISION, start_lon DOUBLE PRECISION, end_time VARCHAR(40), end_lat DOUBLE PRECISION, end_lon DOUBLE PRECISION'
	fi

    else
	# gardump
	if [ $RTE -eq 1 ] ; then
	    # add vertex counts
	    grep -v '^\[\|^#' "${TEMPFILE}.gard" | "$TAC" | awk 'BEGIN { R=0 } \
		/^[-0-9]/ { printf(" %.7f %.7f\n", $2, $1) ; ++R } ; \
		/^\*\*/ { printf("L %d 1\n", R) ; R=0 } END {;}' | "$TAC" > "${TEMPFILE}.base"

	    # create attr table: cat(int), id number(int 0-19), name varchar(40), starting_wpt(varchar 15)
	    # grep -n is to insert cat number, starting from 1. (route numbers start from 0)
	    grep '^\*\*' "${TEMPFILE}.gard" | sed -e 's/^\*\*//' -e 's/ /|/' \
	       | grep -n '^' | sed -e 's/:/|/' > "${TEMPFILE}.route_ids"

	    grep -A 1 '^\*\*' "${TEMPFILE}.gard" | grep -E -v '^\*\*|^--' | \
	      sed -e 's/.* I://' | awk '{print $1}' > "${TEMPFILE}.route_start"

	    paste -d'|' "${TEMPFILE}.route_ids" "${TEMPFILE}.route_start" > "${TEMPFILE}.route_atts"

	    ATTR_FILE="${TEMPFILE}.route_atts"
	    ATTR_COLS='cat int, route_id INT, name VARCHAR(40), start_wpt VARCHAR(15)'

	elif [ $TRK -eq 1 ] ; then
	    # add vertex counts
	    # some tracks don't have time/date, so we have to decide on the fly
	    grep -v '^\[\|^#\|^Track:' "${TEMPFILE}.gard" | "$TAC" | awk 'BEGIN { R=0 } \
	    ! /start/ {
	      if($0 ~ /..:..:../ ) { printf(" %.7f %.7f\n", $4, $3) }
	      else { printf(" %.7f %.7f\n", $2, $1) }
	      ++R
	    } ;

	    /start/ {
	      if($0 ~ /..:..:../ ) { printf(" %.7f %.7f\nL %d 1\n", $4, $3, R+1) }
	      else { printf(" %.7f %.7f\nL %d 1\n", $2, $1, R+1) }
	      R=0
	    }
	    END {;}' | "$TAC" > "${TEMPFILE}.base"

	    # create attr table: cat(int), \
	    #  start_time varchar(40), start_lat(double precision), start_lon(double precision), \
	    #  end_time varchar(40), end_lat(double precision), end_lon(double precision)
	    #  [track_name varchar(15)]

	    # - format time string in ISO 8601 format
	    # - some tracks have timestamps some don't
	    # - use grep -n to add "line number: string" for cat as track nums start as 0

	    # crop out start times
	    grep 'start$' "${TEMPFILE}.gard" | \
	      awk '{ if ( $0 ~ /..:..:../ ) {
			print $1 "T" $2 "Z|" $3 "|" $4
		     } else {
			print "|" $1 "|" $2
		     }
		   }' | grep -n '^' | sed -e 's/:/|/' > "${TEMPFILE}.start_time"

	    # find and crop out end times. if only 1 pt in trk, use start as end time
	    grep -v '^#\|^\[\|^Track:' "${TEMPFILE}.gard" | grep -B 1 'start$' | \
	      grep -v '^--' | awk 'BEGIN { FIRST=1 } \
		/start/ {
		  if (FIRST != 1) { print TIME "|" LAT "|" LON } else { FIRST=0 } ;
		  if ( $0 ~ /..:..:../ ) {
		    TIME=$1 "T" $2 "Z"; LAT=$3; LON=$4
		  } else {
		    TIME=""; LAT=$1; LON=$2
		  }
		} ;
		! /start/ {
		  if ( $0 ~ /..:..:../ ) {
		    TIME=$1 "T" $2 "Z"; LAT=$3; LON=$4
		  } else {
		    TIME=""; LAT=$1; LON=$2
		  }
		}' > "${TEMPFILE}.end_time"

	    # get time & coord of final point
	    grep -B 1 'end transfer' "${TEMPFILE}.gard" | grep '^[0-9]' | awk \
	       '{ if ( $0 ~ /..:..:../ ) {
		    print $1 "T" $2 "Z|" $3 "|" $4
		  } else {
		    print "|" $1 "|" $2
		  }
		}' >> "${TEMPFILE}.end_time"

	    ATTR_COLS='cat INT, start_time VARCHAR(40), start_lat DOUBLE PRECISION, start_lon DOUBLE PRECISION, end_time VARCHAR(40), end_lat DOUBLE PRECISION, end_lon DOUBLE PRECISION'

	    # check if there is any track name data
	    unset HAVE_TRACK_NAME
	    if [ `grep -c '^Track:' "${TEMPFILE}.gard"` -ge 1 ] ; then
		HAVE_TRACK_NAME=TRUE
		ATTR_COLS="$ATTR_COLS, track_name VARCHAR(15)"

		# extract data for track name column
		grep -v '^\[\|^#' "${TEMPFILE}.gard" | grep '^Track:\|start' | awk \
		  '/^Track:/ {TRK=$0; sub(/^Track: /, "", TRK)} ;
		   /^[-0-9]/ {print TRK}' > "$TEMPFILE.trackname"
		paste -d'|' "${TEMPFILE}.start_time" "${TEMPFILE}.end_time" "$TEMPFILE.trackname" > "${TEMPFILE}.track_atts"
	    else
		HAVE_TRACK_NAME=FALSE
		paste -d'|' "${TEMPFILE}.start_time" "${TEMPFILE}.end_time" > "${TEMPFILE}.track_atts"
	    fi
	    ATTR_FILE="${TEMPFILE}.track_atts"
	fi
    fi

    #### reproject if needed
    if [ -z "$IS_WGS84" ] || [ $KEEP_WGS84 -eq 1 ] ; then
	g.message "No projection transformation performed"
	cat "${TEMPFILE}.base" | awk 'BEGIN {;} $1=="L" { print } ; \
	    $1!="L" { printf(" %.7f %.7f\n", $1, $2) } END {;}' > "${TEMPFILE}.P_base"
    else
	g.message "Attempting waypoint projection transform with cs2cs..."
	cs2cs -tL -f %.7f $IN_PROJ +to $OUT_PROJ < "${TEMPFILE}.base" > "${TEMPFILE}.P_mid"
	EXITCODE=$?
	# check if transform REALLY worked (e.g. grid file not found)
	BAD_PTS="`grep -c "^\*" "${TEMPFILE}.P_mid"`"
	if [ "$BAD_PTS" -gt 0 ] ; then
	    g.message message=""
	    g.message -w "$BAD_PTS vertices failed reprojection."
	    EXITCODE=1
	fi
	if [ $EXITCODE -ne 0 ] ; then
	    g.message -w "Projection transform failed, retaining WGS84"
	    g.message message=""
	    cat "${TEMPFILE}.base" | awk 'BEGIN {;} $1=="L" { print } ; \
		$1!="L" { printf(" %.7f %.7f\n", $1, $2) } END {;}' > "${TEMPFILE}.P_base"
	else
	    cat "${TEMPFILE}.P_mid" | awk 'BEGIN {;} $1=="L" { print } ; \
		$1!="L" { printf(" %.7f %.7f\n", $1, $2) } END {;}' > "${TEMPFILE}.P_base"
	fi
    fi

    # add category numbers
    cat "${TEMPFILE}.P_base" | awk 'BEGIN { FS=" " ; R=0 } \
	$1=="L" { printf(" 1 %d\nL %d 1\n", R, $2) ; ++R } ; \
	$1!="L" { print } END { printf(" 1 %d\n", R) }' | sed -e '1d' > "${TEMPFILE}.P_baseC"

    # add z for 3D maps
    unset HAVE_ALT
    if [ $GIS_FLAG_Z -eq 1 ] ; then
	# check if there is any altitude data
	if [ `grep -v '^\[\|^#\|^Track:' "${TEMPFILE}.gard" | tr -s ' ' '|' | cut -f6 -d'|' | grep -c start` -ge 1 ] ; then
	    HAVE_ALT=TRUE
	else
	    HAVE_ALT=FALSE
	    if [ $GIS_FLAG_Z -eq 1 ] ; then
		g.message -w "No altitude data found, creating 2D vector map"
	    fi
	fi
    else
	HAVE_ALT=FALSE
    fi

    if [ "$HAVE_ALT" = "TRUE" ] ; then
	# cut out altitude data and add blank lines between track lines
	grep -v '^\[\|^#\|^Track:' "${TEMPFILE}.gard" | "$TAC" | \
	  awk '{ if($0 ~ /..:..:../ ) {
		   print $5 " " $6
		 } else {
		   print $3 " " $4
		 }
	       }' | sed -e 's/ start/\n/' -e 's/ $//' | "$TAC" > "${TEMPFILE}.alt"

	paste -d' ' "${TEMPFILE}.P_base" "${TEMPFILE}.alt" > "${TEMPFILE}.P_baseZ"
    else
	cp "${TEMPFILE}.P_base" "${TEMPFILE}.P_baseZ"
    fi

    # add category numbers
    cat "${TEMPFILE}.P_baseZ" | awk 'BEGIN { FS=" " ; R=0 } \
	$1=="L" { printf(" 1 %d\nL %d 1\n", R, $2) ; ++R } ; \
	$1!="L" { print } END { printf(" 1 %d\n", R) }' | sed -e '1d' \
	  > "${TEMPFILE}.P_baseC"


    #### create digit header
    cat << EOF > "${TEMPFILE}.dig"
ORGANIZATION: GRASSroots organization
DIGIT DATE:   `date "+%Y/%m/%d"`
DIGIT NAME:   $PROG
MAP NAME:     $NAME
MAP DATE:     `date +%Y`
MAP SCALE:    1
OTHER INFO:   Imported by `echo $USER@$HOSTNAME`
ZONE:         0
MAP THRESH:   0
VERTI:
EOF

    #### merge in vertices
    cat "${TEMPFILE}.P_baseC" >> "${TEMPFILE}.dig"

    #### if no name for vector file given, cat to stdout
    if [ -z "$NAME" ] ; then
	g.message "ASCII file redirected to stdout"
	cat "${TEMPFILE}.dig" 2> /dev/null
    else
	#### import to binary vector file
	if [ $GIS_FLAG_Z -eq 1 ] && [ "$HAVE_ALT" = "TRUE" ] ; then
	    ZFLAG="-z"
	else
	    ZFLAG=""
	fi

	g.message "Importing with v.in.ascii..."
	v.in.ascii format=standard output="$NAME" input="${TEMPFILE}.dig" $ZFLAG

	#### check success/failure
	if [ $? -eq 0 ] ; then
	    g.message -v message="Line vector <$NAME> successfully created"
	else
	    g.message -e "An error occured creating <$NAME>, please check"'!'
	    rm -f "${TEMPFILE}"*
	    exit 1
	fi

	# create db links if they don't exist
	db.connect -c
	DRIVER="`db.connect -p | grep '^driver:' | cut -f2 -d:`"
	if [ "$DRIVER" = "dbf" ] && [ ! -d "$LOCATION/dbf/" ] ; then
	    mkdir "$LOCATION/dbf/"
	fi

	g.message "Creating new table.."
	echo "CREATE TABLE $NAME ($ATTR_COLS)" | db.execute
	if [ $? -ne 0 ] ; then
	    g.message -e "Map created but failed to create database table."
	    rm -f "${TEMPFILE}"*
	    exit 1
	fi


	g.message "Populating table with attributes.."
# echo "COPY $NAME FROM '$ATTR_FILE'" | db.execute

# "COPY table FROM 'filename.txt'" does not work for DBF and there is no
#   db.in.ascii yet, so we use a hack...

### <hack>
	if [ $RTE -eq 1 ] ; then
	    # =>  INSERT INTO $NAME VALUES (2, 1, 'AB', 'B')
	    awk -F'|' -v NAME="$NAME" \
	      '{ printf("INSERT INTO %s VALUES (%d, %d, ^%s^, ^%s^);\n", NAME, $1, $2, $3, $4) }' \
	      "$ATTR_FILE" | tr '^' \' > "$ATTR_FILE"_exe
	fi
	if [ $TRK -eq 1 ] ; then
	    # =>  INSERT INTO $NAME VALUES (,,,,,);
	    if [ "$HAVE_TRACK_NAME" = "TRUE" ] ; then
	    		awk -F'|' -v NAME="$NAME" \
		  '{ printf("INSERT INTO %s VALUES (%d, ^%s^, %.7f, %.7f, ^%s^, %.7f, %.7f, ^%s^);\n", \
		     NAME, $1, $2, $3, $4, $5, $6, $7, $8) }' "$ATTR_FILE" | \
		  tr '^' \' > "$ATTR_FILE"_exe
	    else
		awk -F'|' -v NAME="$NAME" \
		  '{ printf("INSERT INTO %s VALUES (%d, ^%s^, %.7f, %.7f, ^%s^, %.7f, %.7f);\n", \
		     NAME, $1, $2, $3, $4, $5, $6, $7) }' "$ATTR_FILE" | \
		  tr '^' \' > "$ATTR_FILE"_exe
	    fi
	fi

	db.execute input="$ATTR_FILE"_exe
	if [ $? -ne 0 ] ; then
	    g.message -e "Map created but failed to populate database table."
	    # need to connect it before we can delete it. :-/
	    v.db.connect map="$NAME" table="$NAME" 2> /dev/null
	    v.db.droptable -f map=$NAME --quiet
	    rm -f "${TEMPFILE}"*
	    exit 1
	fi
### </hack>

	g.message "Connecting attribute table to vector file..."
	v.db.connect map="$NAME" table="$NAME"
    fi

fi  # if CREATE_POINTS or CREATE_LINES


# list column names
if [ $VERBOSE -eq 1 ] && [ -n "$NAME" ] ; then
    g.message message="<$NAME> columns:"
    db.columns "$NAME"
fi

# write cmd history:
v.support map="$NAME" cmdhist="${CMDLINE}"

#### clean up the mess
\rm -f "${TEMPFILE}"*

#### end
g.message "Done."

exit 0
