#!/usr/bin/perl 

use strict;
use warnings;

#trackgpx2shp_bare.pl - convert a gpx file to a track log, without using Geo::Track::Log
# useage:  trackgpx2shp.pl tk.gpx out
# will create out.shp/out.shx/out.dbf

my ($in, $out) = @ARGV;
die "Usage: $0 <tracklog> <shapefile>\n" unless $in and $out;

use Geo::Shapelib;  # wraps Frank W.'s shapelib library
use XML::Simple; 
#use Geo::Track::Log; # Rich Gibson's track log manipulation-used to parse the gpx file
use Time::Piece;
use Data::Dumper;

my $id = 0;
my (@vertices, $last_time, $last_elevation);

my $shp = new Geo::Shapelib;
$shp->{Name}	   = $out;
$shp->{Shapetype}  = 3; # PolyLine, according to Geo::Shapelib source
$shp->{FieldNames} = ['ID', 'Date', 'Elevation'];
$shp->{FieldTypes} = ['Integer', 'String:19', 'Double:10:6'];

# parse the gpx file 
my $xml = XML::Simple->new(
       ForceArray => [ 'trk', 'trkseg', 'trkpt' ],
       KeyAttr    => [],
       NormaliseSpace => 2
    );

my $gpx = eval { $xml->XMLin($in) } or die "Invalid GPX track: $@";
my $track; # reference to an array of hashrefs
for my $trk (@{$gpx->{trk}}) {
    for my $seg (@{$trk->{trkseg}}) {
        my $new_segment_flag = 1;
        for my $pt (@{$seg->{trkpt}}) {
            $pt->{time} =~ y/TZ/ /d; # "2004-08-29T01:44:11Z" -> "2004-08-29 01:44:11"
            $pt->{new_segment_flag} = $new_segment_flag;
            $new_segment_flag = 0;
           
            push @$track, {
                lat => $pt->{lat},
                long => $pt->{lon},
                elevation => $pt->{ele},
                timestamp => $pt->{time},
                new_segment_flag => $pt->{new_segment_flag},
            };
        }
    }
}


# walk the track
foreach my $pt  (@$track) {
    # try: print Dumper($pt) to see what is in a $pt
    my $long = $pt->{long};
    my $lat  = $pt->{lat};
    $last_time = $pt->{timestamp} unless $last_time;
    $last_elevation = $pt->{elevation} unless $last_elevation;
    if ($pt->{new_segment_flag}) {
        # print "this is a new segment!\n";
		add_shape();
    }

    push @vertices, [$long, $lat];
    $last_time = $pt->{timestamp};
    $last_elevation = $pt->{elevation};
}

add_shape();
$shp->save($out);

sub add_shape {
    # a shape needs two vertices.  If not, return and try again when you have
    # more vertices.
    return unless (@vertices > 2);
	push @{$shp->{Shapes}}, {
	       SHPType => 3, # PolyLine
	       ShapeId => $id,
	       NVertices => scalar @vertices,
	       Vertices  => [@vertices]
	};

    # this is for the matching DBF.
    push @{$shp->{ShapeRecords}}, [$id++, $last_time, $last_elevation];
    print "id: $id last_time: $last_time last_elevation: $last_elevation\n";

    @vertices = ();
}
