#!/bin/sh
#
############################################################################
#
# MODULE:      v.out.gpsbabel
#
# PURPOSE:     Exports a GRASS vector map to a GPS receiver
#		or data file using GpsBabel
#
# COPYRIGHT:   (c) 2008 Hamish Bowman, and 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.
#
# AUTHOR:     Hamish Bowman, Dunedin, New Zealand
#
#############################################################################
#
# REQUIREMENTS:
#      -  GpsBabel from 	http://gpsbabel.sourceforge.net
#      -  cs2cs from PROJ.4 (for m.proj)	http://proj.osgeo.org
#
#      - report supported GpsBabel formats:
#	 gpsbabel -^2 | tr '\t' ';' | sort -t';' -k3
#
#############################################################################
#
# How to do it
#   http://www.gdal.org/ogr/drv_gpx.html
#   gpsbabel [options] -i INTYPE -f INFILE -o OUTTYPE -F OUTFILE
#
#############################################################################

#%Module
#%  description: Exports a vector map to a GPS receiver or file format supported by GpsBabel.
#%  keywords: vector, export, GPS
#%End
#%flag
#%  key: w
#%  description: Export as waypoints
#%end
#%flag
#%  key: r
#%  description: Export as routes
#%end
#%flag
#%  key: t
#%  description: Export as tracks
#%end
############ TODO:
##%flag
##%  key: z
##%  description: Export altitude from 3D vector's z-coordinate
##%end
############
#%option
#% key: input
#% type: string
#% description: Name of input vector map
#% gisprompt: old,vector,vector
#% required: yes
#%end
#%option
#% key: type
#% type: string
#% description: Feature type(s)
#% options: point,centroid,line,boundary
#% multiple: yes
#%end
#%option
#% key: output
#% type: string
#% description: Name for output file or GPS device
#% gisprompt: new_file,file,output
#% key_desc: name
#% required: yes
#%end
#%option
#% key: format
#% type: string
#% description: GpsBabel supported output format
#% answer: gpx
#%end
#%option
#% key: layer
#% type: integer
#% label: Layer number
#% description: A single vector map can be connected to multiple database tables. This number determines which table to use.
#% answer: 1
#% required : no
#% guisection: Subset
#%end
#%option
#% key: where
#% type: string
#% label: WHERE conditions of SQL statement without 'where' keyword
#% description: Example: income < 1000 and inhab >= 10000
#% required : no
#% guisection: Subset
#%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
    # 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

eval `g.gisenv`
: ${GISBASE?} ${GISDBASE?} ${LOCATION_NAME?} ${MAPSET?}
LOCATION="$GISDBASE"/"$LOCATION_NAME"/"$MAPSET"

PROG=`basename "$0"`

#### check for gpsbabel 
if [ ! -x "`which gpsbabel`" ] ; then
    g.message -e "The gpsbabel program was not found, please install it first.
                  http://gpsbabel.sourceforge.net"
    exit 1
fi

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

# check if we will overwrite data
if [ -e "$GIS_OPT_OUTPUT" ] ; then
   if [ -z "$GRASS_OVERWRITE" ] || [ "$GRASS_OVERWRITE" -ne 1 ] ; then
      g.message -e "Output file already exists."
      exit 1
   fi
fi


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


cleanup()
{
   g.message -v "Cleaning up ..."
   \rm -f "$TEMPFILE" "$TEMPFILE.gpx"
   # only try to remove map if it exists to avoid ugly warnings
   g.findfile element=vector file="tmp_vogb_epsg4326_$$" > /dev/null
   if [ $? -eq 0 ] ; then
      g.remove vect="tmp_vogb_epsg4326_$$"  --quiet
   fi
   g.findfile element=vector file="tmp_vogb_extr_$$" > /dev/null
   if [ $? -eq 0 ] ; then
      g.remove vect="tmp_vogb_extr_$$"  --quiet
   fi
}

#### trap ctrl-c so that we can clean up tmp
trap 'cleanup' 2 3 15


#### process command line arguments 
WPT=$GIS_FLAG_W ; RTE=$GIS_FLAG_R ; TRK=$GIS_FLAG_T

if [ $WPT -eq 1 ] && ([ $RTE -eq 1 ] || [ $TRK -eq 1 ]) ; then
    g.message -e "One feature at a time please."
    rm -f "$TEMPFILE"
    exit 1
fi
# logic eludes me at pressent..  [combine with above]
if [ $RTE -eq 1 ] && [ $TRK -eq 1 ] ; then
    g.message -e "One feature at a time please."
    rm -f "$TEMPFILE"
    exit 1
fi

if [ $WPT -eq 0 ] && [ $RTE -eq 0 ] && [ $TRK -eq 0 ] ; then
    g.message -e "No features requested for export."
    cleanup
    exit 1
fi

# set some reasonable defaults
if [ $WPT -eq 1 ] ; then
   if [ -z "$GIS_OPT_TYPE" ] ; then
      GIS_OPT_TYPE="point"
   fi
else
   if [ -z "$GIS_OPT_TYPE" ] ; then
      GIS_OPT_TYPE="line"
   fi
fi


# SQL extract if needed
if [ -n "$GIS_OPT_WHERE" ] ; then
   g.message -v "Extracting data ..."

   v.extract in="$GIS_OPT_INPUT" out="tmp_vogb_extr_$$" \
      type="$GIS_OPT_TYPE" layer="$GIS_OPT_LAYER" \
      where="$GIS_OPT_WHERE" --quiet

   if [ $? -ne 0 ] ; then
       g.message -e "Error executing SQL query"
       cleanup
       exit 1
   fi

   eval `v.info -t map="tmp_vogb_extr_$$"`
   if [ "$primitives" -eq 0 ] ; then
      g.message -e "SQL query returned an empty map (no $GIS_OPT_TYPE features?)"
      cleanup
      exit 1
   fi

   INMAP="tmp_vogb_extr_$$"
else
#   g.copy "$GIS_OPT_INPUT,tmp_vogb_extr_$$"   # to get a copy of DB into local mapset
#   INMAP="tmp_vogb_extr_$$"
   INMAP="$GIS_OPT_INPUT"
fi


#### set up projection info
# TODO: check if we are already in ll/WGS84.  If so skip m.proj step.


# TODO: multi layer will probably fail badly due to sed 's/^ 1   /'
#   output as old GRASS 4 vector ascii and fight with dig_ascii/?
#   Change to s/^ \([0-9]   .*\)    /# \1/' ??? mmph.

# reproject to lat/lon WGS84
g.message -v "Reprojecting data ..."

v.out.ascii in="$INMAP" format=standard | \
   sed -e 's/^\([PLBCFKA]\)/#\1/' -e 's/^ 1     /# 1  /' | \
   tail -n +11 | m.proj -od --quiet | \
   sed -e 's/\t\([-\.0-9]*\) .*/ \1/' \
     -e 's/^\([-\.0-9]\)/ \1/' \
     -e 's/^#//' | \
    v.in.ascii out=tmp_vogb_epsg4326_$$ -n format=standard --quiet

if [ $? -ne 0 ] ; then
    g.message -e "Error reprojecting data"
    cleanup
    exit 1
fi


# don't v.db.connect directly as source table will be removed with
# temporary map in that case. So we make a temp copy of it to work with.
DB_PARAMS=`v.db.connect -gl map="$INMAP" fs='|' layer="$GIS_OPT_LAYER" 2> /dev/null`
if [ -n "$DB_PARAMS" ] ; then
   DB_TABLE=`echo "$DB_PARAMS" | cut -f2 -d'|'`
   DB_KEY=`echo "$DB_PARAMS" | cut -f3 -d'|'`
   DB_DATABASE=`echo "$DB_PARAMS" | cut -f4 -d'|'`
   DB_DRIVER=`echo "$DB_PARAMS" | cut -f5 -d'|'`

   db.copy from_driver="$DB_DRIVER" from_database="$DB_DATABASE" \
      from_table="$DB_TABLE"  to_table="tmp_vogb_epsg4326_$$"

   if [ $? -ne 0 ] ; then
       g.message -e "Error copying temporary DB"
       cleanup
       exit 1
   fi

   v.db.connect map="tmp_vogb_epsg4326_$$" table="tmp_vogb_epsg4326_$$" --quiet
   if [ $? -ne 0 ] ; then
      g.message -e "Error reconnecting temporary DB"
      cleanup
      exit 1
   fi
fi


# export as GPX using v.out.ogr
if [ $TRK -eq 1 ] ; then
   LINETYPE="lco=FORCE_GPX_TRACK=YES"
elif [ $RTE -eq 1 ] ; then
   LINETYPE="lco=FORCE_GPX_ROUTE=YES"
else
   LINETYPE=""
fi

# BUG: cat is being reported as evelation and attribute output is skipped.
#   (v.out.ogr DB reading or ->OGR GPX driver bug ?)
#   v.out.ogr -> shapefile -> GPX works, but we try to avoid that as it's
#     lossy. Also that would allow ogr2ogr -a_srs $IN_PROJ -t_srs EPSG:4326
#     so skip m.proj pains.. if that is done ogr2ogr -s_srs MUST HAVE +wktext
#     with PROJ.4 terms or else the +nadgrids will be ignored! best to feed
#     it  IN_PROJ="`g.proj -jf` +wktext"  in that case.

g.message -v "Exporting data ..."

v.out.ogr in="tmp_vogb_epsg4326_$$" dsn="$TEMPFILE.gpx" type="$GIS_OPT_TYPE" \
  format=GPX ${LINETYPE} dsco="GPX_USE_EXTENSIONS=YES" --quiet

if [ $? -ne 0 ] ; then
    g.message -e "Error exporting data"
    cleanup
    exit 1
fi

if [ "$GIS_OPT_FORMAT" = gpx ] ; then
   # short circuit, we have what we came for.
   mv -f "$TEMPFILE.gpx" "$GIS_OPT_OUTPUT"
   cleanup
   g.message -v "Fast exit."
   exit 0
fi


# run gpsbabel
GTYPE=""
if [ $WPT -eq 1 ] ; then
   GTYPE="-w"
elif [ $TRK -eq 1 ] ; then
   GTYPE="-t"
elif [ $RTE -eq 1 ] ; then
   GTYPE="-r"
fi

g.message -v "Running GpsBabel ..."

gpsbabel $GTYPE -i gpx -f "$TEMPFILE.gpx" \
    -o "$GIS_OPT_FORMAT" -F "$GIS_OPT_OUTPUT"

if [ $? -ne 0 ] ; then
    g.message -e "Error running GpsBabel"
    cleanup
    exit 1
fi


cleanup
g.message -v "Done."
exit
