#!/usr/bin/env perl

# convert Trello JSON export containing location data into a
# Google Maps/Earth KML file with each list in a separate
# folder.
# TODO: add some basic styling, maybe using sequential paddles
# http://kml4earth.appspot.com/icons.html
# https://code.google.com/archive/p/kml-samples/source/default/source
#
# TODO: add first label color to style: .labels[0].color
# TODO: include first checklist .checklists, have state==(in)complete for
# check status
#
use strict;
use JSON;
use XML::LibXML;

my ($In) = @ARGV;
die "$0: $In: file not found\n" unless -f $In;
my $json = slurp($In);
# no idea why a Unicode Control-K is in their export data...
$json =~ s/\\u000b/\\n/g;
my $trello = decode_json($json);

my %listname;
my @listname;
foreach my $list (@{$trello->{lists}}) {
	next if $list->{closed};
	$listname{$list->{id}} = $list->{name};
	push(@listname,$list->{name});
}

my %lists;
foreach my $card (@{$trello->{cards}}) {
	next if $card->{closed};
	next unless defined $card->{badges};
	next unless $card->{badges}->{location};
	my $list = $listname{$card->{idList}};
	$lists{$list} = [] unless ref $lists{$list} eq "ARRAY";
	$card->{desc} = join("<br/>",split(/\n/,$card->{desc}));
	push(@{$lists{$list}}, {
		name => $card->{name},
		desc => $card->{desc},
		address => $card->{address},
		lat => $card->{coordinates}->{latitude},
		lon => $card->{coordinates}->{longitude},
	});
}

my $dom = XML::LibXML::Document->new('1.0', 'UTF-8');

my $kml = $dom->createElementNS('http://www.opengis.net/kml/2.2','kml');
$dom->setDocumentElement($kml);

my $doc = newNode($dom, 'Document', {
	name => $trello->{name},
	desc => $trello->{desc},
});
$kml->appendChild($doc);

foreach my $list (@listname) {
	next unless defined $lists{$list};
	my $folder = newNode($dom, 'Folder', {
		name => $list,
	});
	$doc->appendChild($folder);
	foreach my $card (@{$lists{$list}}) {
		$folder->appendChild(newPlacemark($dom, $card));
	}
}

my $outfile = $In;
$outfile =~ s/\.[^.]+$//;
$outfile .= ".kml";
open (my $out, '>:raw', $outfile)
	or die "$0: $outfile: $!\n";
$dom->toFH($out,1);
close($out);
exit 0;

sub newNode {
	my ($dom, $type, $data) = @_;
	my $node = $dom->createElement($type);
	if (defined $data and defined $data->{name}) {
		my $name = $dom->createElement('name');
		$name->appendText($data->{name});
		$node->appendChild($name);
	}
	if (defined $data and defined $data->{desc}) {
		my $desc = $dom->createElement('description');
		$desc->appendText($data->{desc});
		$desc->appendText("\n" . $data->{address})
			if defined $data->{address};
		$node->appendChild($desc);
	}
	return $node;
}

sub newPlacemark {
	my ($dom, $data) = @_;
	my $node = newNode($dom, 'Placemark', $data);
	my $point = newNode($dom, 'Point');
	$node->appendChild($point);
	my $coord = newNode($dom, 'coordinates');
	$coord->appendText($data->{lon} . ',' . $data->{lat});
	$point->appendChild($coord);
	return $node;
}

sub slurp {
    do {local( @ARGV, $/ ) = $_[0]; <>}
}
