From fd6d12d355e5fb5596168b91affe71eb059c0e99 Mon Sep 17 00:00:00 2001
From: Daniel Friesel <derf@finalrewind.org>
Date: Sun, 28 Apr 2019 22:33:09 +0200
Subject: Handle inconsistent data when calculating monthly/yearly stats

Closes #11
---
 lib/Travelynx.pm                  | 25 ++++++++++++++++++-------
 lib/Travelynx/Command/database.pm | 13 +++++++++++++
 templates/_history_stats.html.ep  | 23 +++++++++++++++++++++++
 3 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm
index 6434e00..1e7c965 100755
--- a/lib/Travelynx.pm
+++ b/lib/Travelynx.pm
@@ -1445,8 +1445,9 @@ sub startup {
 			my $interchange_real = 0;
 			my $num_trains       = 0;
 			my $num_journeys     = 0;
+			my @inconsistencies;
 
-			my $next_departure = 0;
+			my $next_departure = epoch_to_dt(0);
 
 			for my $journey (@journeys) {
 				$num_trains++;
@@ -1472,18 +1473,27 @@ sub startup {
 
 				# Note that journeys are sorted from recent to older entries
 				if (    $journey->{rt_arrival}
-					and $next_departure
-					and $next_departure - $journey->{rt_arrival}->epoch
+					and $next_departure->epoch
+					and $next_departure->epoch - $journey->{rt_arrival}->epoch
 					< ( 60 * 60 ) )
 				{
-					$interchange_real
-					  += ( $next_departure - $journey->{rt_arrival}->epoch )
-					  / 60;
+					if ( $next_departure->epoch - $journey->{rt_arrival}->epoch
+						< 0 )
+					{
+						push( @inconsistencies,
+							$next_departure->strftime('%d.%m.%Y %H:%M') );
+					}
+					else {
+						$interchange_real
+						  += (  $next_departure->epoch
+							  - $journey->{rt_arrival}->epoch )
+						  / 60;
+					}
 				}
 				else {
 					$num_journeys++;
 				}
-				$next_departure = $journey->{rt_departure}->epoch;
+				$next_departure = $journey->{rt_departure};
 			}
 			return {
 				km_route             => $km_route,
@@ -1495,6 +1505,7 @@ sub startup {
 				min_interchange_real => $interchange_real,
 				delay_dep            => $delay_dep,
 				delay_arr            => $delay_arr,
+				inconsistencies      => \@inconsistencies,
 			};
 		}
 	);
diff --git a/lib/Travelynx/Command/database.pm b/lib/Travelynx/Command/database.pm
index b5e8cf5..bd22512 100644
--- a/lib/Travelynx/Command/database.pm
+++ b/lib/Travelynx/Command/database.pm
@@ -330,6 +330,19 @@ my @migrations = (
 		}
 		$db->update( 'schema_version', { version => 4 } );
 	},
+
+	# v4 -> v5
+	# Handle inconsistent data (overlapping journeys) in statistics. Introduces
+	# the "inconsistencies" stats key -> rebuild all stats.
+	sub {
+		my ($db) = @_;
+		$db->query(
+			qq{
+				truncate journey_stats;
+				update schema_version set version = 5;
+			}
+		);
+	},
 );
 
 sub setup_db {
diff --git a/templates/_history_stats.html.ep b/templates/_history_stats.html.ep
index f203631..715fa1a 100644
--- a/templates/_history_stats.html.ep
+++ b/templates/_history_stats.html.ep
@@ -1,3 +1,26 @@
+% if (@{$stats->{inconsistencies}}) {
+	<div class="row">
+		<div class="col s12">
+			<div class="card red darken-4">
+				<div class="card-content white-text">
+					<i class="material-icons small right">warning</i>
+					<span class="card-title">Inkonsistente Reisedaten</span>
+					<p>
+						Die folgenden Abfahrtszeiten liegen vor der Ankunftszeit der
+						vorherigen Zugfahrt und wurden bei der Wartezeitberechnung
+						ignoriert.
+						<ul>
+							% for my $date (@{$stats->{inconsistencies}}) {
+								<li><%= $date %></li>
+							% }
+						</ul>
+					</p>
+				</div>
+			</div>
+		</div>
+	</div>
+% }
+
 <div class="row">
 	<div class="col s12">
 		<table class="striped">
-- 
cgit v1.2.3