#!/usr/bin/perl

# bus.pl v0.30

# Robert Rothenberg <rrwo@cpan.org> Copyright (C) 2004.  All Rights
# Reserved.  This program is free software; you can redistribute it
# and/or modify it under the same terms as Perl itself.

# This is a demonstration of how to use the Algorithm::ScheduledPath
# module.  It builds a directed graph out of bus route information
# (from the __DATA__ block at the end of the code) and displays a list
# of bus routes between two destinations.

# TO-DO:
# * command line arguments to turn this into a generic script
# * bus schedule data from separate file or web site
# * filter by max transfers
# * filter by max travel time
# * filter by min depart time, max arrive time
# * option to show more than one  alternate transfers

use strict;
use warnings;

use Algorithm::ScheduledPath 0.31;
use Algorithm::ScheduledPath::Edge;
use Algorithm::ScheduledPath::Path;

my %PathIds = ( );

my $Graph  = parse_data();

# Change the points searched.

my $Routes = $Graph->find_routes('KRKCDY', 'STANDR', 1);

print "-"x40, "\n";

if (@$Routes) {
  foreach my $route (sort by_arrival @$Routes) {
    my $trip = $route->compressed;
    foreach my $leg (@{$trip->get_legs}) {
      print join("\t", $PathIds{$leg->path_id},
		 $leg->origin, unparse_time($leg->depart_time),
		 $leg->destination, unparse_time($leg->arrive_time)
      ), "\n";

    }
    print "\nTravel Time", "\t"x3, unparse_time($route->travel_time), "\n";
    print "-"x40, "\n";
  }
}

sub by_depart {
  $a->depart_time <=> $b->depart_time;
}

sub by_arrival {
  $a->arrive_time <=> $b->arrive_time;
}

sub unparse_time {
  my $time = shift;
  my $hour = int($time / 60);
  my $min  = $time % 60;
  return sprintf('%02d:%02d', $hour, $min);
}


sub parse_time {
  my $time = shift;
  my $hour = 0+substr($time,0,2);
  my $min  = 0+substr($time,2,2);
  return $min+(60*$hour);
}

sub parse_data {

  my $graph = new Algorithm::ScheduledPath;

  my $path_id = 1;

  while (my $line=<DATA>) {
    chomp($line);
    if ($line) {
      $line =~ s/\x23.+$//g;
      my ($bus_no, @stops) = split /\s+/, $line;

      $PathIds{$path_id} = $bus_no;

      my ($orig, $depart);
      while (@stops) {
	my $dest = shift @stops;
	my ($arrive, $depart2) = split /\//, shift @stops;
	$depart2 ||= $arrive;

	if (defined $orig) {
	  my $e = new Algorithm::ScheduledPath::Edge( {
            path_id     => $path_id,
            origin      => $orig,
            depart_time => parse_time($depart),
            destination => $dest,
            arrive_time => parse_time($arrive), 
          } );
	  $graph->add_leg($e);
	}

	($orig, $depart) = ($dest, $depart2);
      }
      $path_id++;      
    }
  }
  return $graph;
}


__DATA__

# Below is sample data based on bus schedules in Fife, Scotland.
# These are not complete, nor are they accurate.

X1	KRKCDY	0725	GLNRTH	0752
X1	KRKCDY	0805	GLNRTH	0832
X1	KRKCDY	0835	GLNRTH	0902
X1	KRKCDY	0905	GLNRTH	1032
X1	KRKCDY	0935	GLNRTH	1002
X1	KRKCDY	1005	GLNRTH	1132
X1	KRKCDY	1035	GLNRTH	1102

X1	GLNRTH	1951	KRKCDY	2016
X1	GLNRTH	2051	KRKCDY	2116
X1	GLNRTH	2151	KRKCDY	2216
X1	GLNRTH	2251	KRKCDY	2316

6	KRKCDY	0737	LEVIN	0827
6A	KRKCDY	0837	LEVIN	0915
6	KRKCDY	0907	LEVIN	0945
6A	KRKCDY	0937	LEVIN	1015
6	Ldy	1007	LEVIN	1045

6	LEVIN	1650	KRKCDY	1721
6	LEVIN	1720	KRKCDY	1751

7	KRKCDY	0610	LEVIN	0648
7	KRKCDY	0652	LEVIN	0730
7A	KRKCDY	0712	LEVIN	0755
7	KRKCDY	0758	LEVIN	0836
7	KRKCDY	0820	LEVIN	0858
7	KRKCDY	0857	LEVIN	0935
7	KRKCDY	0927	LEVIN	1005
7A	KRKCDY	0947	LEVIN	1025
7	KRKCDY	0957	LEVIN	1035
7A	KRKCDY	1017	LEVIN	1055
7	KRKCDY	1027	LEVIN	1105
7A	KRKCDY	1047	LEVIN	1125

7	KRKCDY	0620	DNFMLN	0740
7	KRKCDY	0732	DNFMLN	0853
7	KRKCDY	0822	DNFMLN	0935
7	KRKCDY	0852	DNFMLN	1005
7	KRKCDY	0922	DNFMLN	1035

7	LEVIN	1845	KRKCDY	1921	DNFMLN	2030
7	LEVIN	1945	KRKCDY	2021	DNFMLN	2130
7	LEVIN	2045	KRKCDY	2121	DNFMLN	2230
7	LEVIN	2145	KRKCDY	2221	DNFMLN	2330
7	LEVIN	2245	KRKCDY	2321

138	KRKCDY	0835	LEVIN	0913
13	KRKCDY	0915	LEVIN	1012
13	KRKCDY	1015	LEVIN	1112

13	LEVIN	1715	KRKCDY	1805
13	LEVIN	1815	KRKCDY	1912
13	LEVIN	1915	KRKCDY	2012
13	LEVIN	2015	KRKCDY	2112
13	LEVIN	2115	KRKCDY	2212
13	LEVIN	2215	KRKCDY	2312

14	DNFMLN	0545	STRLNG	0655
14	DNFMLN	0610	STRLNG	0725
14A	DNFMLN	0711	STRLNG	0831
14	DNFMLN	0746	STRLNG	0909
14	DNFMLN	0851	STRLNG	1008
14A	DNFMLN	0951	STRLNG	1108

23	STRLNG	0700	CUPAR	0837	STANDR	0855
23	STRLNG	0705	CUPAR	0840	STANDR	0858
23	STRLNG	0910	CUPAR	1043	STANDR	1103

23	STANDR	0604	CUPAR	0622
23	STANDR	0659	CUPAR	0717
23	STANDR	0709	CUPAR	0727
23	STANDR	0710	CUPAR	0730	STRLNG	0905
23	STANDR	0800	CUPAR	0829
23	STANDR	0850	CUPAR	0908
23	STANDR	0910	CUPAR	0928	STRLNG	1104

23	STANDR	1735	CUPAR	1753	STRLNG	1929
23	STANDR	2355	CUPAR	2429

X24	DNFMLN	0600	GLNRTH	0633	CUPAR	0656	STANDR	0717
X24	GLNRTH	0653	CUPAR	0716	STANDR	0737
X24	DNFMLN	0700	GLNRTH	0733	CUPAR	0756	STANDR	0817
X24	DNFMLN	0730	GLNRTH	0803	CUPAR	0826	STANDR	0847
X24	DNFMLN	0755	GLNRTH	0838
X24	DNFMLN	0835	GLNRTH	0908	CUPAR	0931	STANDR	0952
X24	DNFMLN	0930	GLNRTH	1003	CUPAR	1026	STANDR	1047

X24	GLNRTH	0632	DNFMLN	0702
X24	GLNRTH	0815	DNFMLN	0845
X24	GLNRTH	0845	DNFMLN	0915
X24	GLNRTH	0915	DNFMLN	0945
X24	GLNRTH	1015	DNFMLN	1045

X24	STANDR	1825	CUPAR	1846	GLNRTH	1915	DNFMLN	1945
X24	STANDR	1905	CUPAR	1926	GLNRTH	1955	DNFMLN	2025
X24	STANDR	1935	CUPAR	1956	GLNRTH	2025	DNFMLN	2055

24	STANDR	1950	CUPAR	2009	GLNRTH	2040
24	STANDR	2050	CUPAR	2109	GLNRTH	2140
24	STANDR	2150	CUPAR	2209	GLNRTH	2240
24	STANDR	2250	CUPAR	2309	GLNRTH	2340

X26	LEVIN	0640	STANDR	0754
X26	DNFMLN	0620	KRKCDY	0655	LEVIN	0721	STANDR	0833

X26	STANDR	1715	LEVIN	1835	KRKCDY	1902	DNFMLN	1935
X26	LEVIN	1915	KRKCDY	1945	DNFMLN	2017
X26	STANDR	1805	LEVIN	1925	KRKCDY	1955	DNFMLN	2027
X26	LEVIN	2015	KRKCDY	2045	DNFMLN	2117

32	KRKCDY	0740	GLNRTH	0841
32	KRKCDY	0930	GLNRTH	1026
32	KRKCDY	1030	GLNRTH	1126

32	GLNRTH	1910	KRKCDY	2006
32	GLNRTH	2110	KRKCDY	2206

37	KRKCDY	0600	GLNRTH	0635
37	KRKCDY	0700	GLNRTH	0747
37	KRKCDY	0730	GLNRTH	0805
37	KRKCDY	0750	GLNRTH	0825
37	KRKCDY	0810	GLNRTH	0845
37	KRKCDY	0830	GLNRTH	0905
37	KRKCDY	0850	GLNRTH	0925

39	KRKCDY	0740	GLNRTH	0814
39	KRKCDY	0800	GLNRTH	0834
39	KRKCDY	0820	GLNRTH	0854
39	KRKCDY	0840	GLNRTH	0914
39	KRKCDY	0900	GLNRTH	0934

39	GLNRTH	2125	KRKCDY	2158
39	GLNRTH	2225	KRKCDY	2258


40	KRKCDY	0812	GLNRTH	0853
40	KRKCDY	0912	GLNRTH	0953
40	KRKCDY	1012	GLNRTH	1053
40	KRKCDY	1112	GLNRTH	1153

40	GLNRTH	1657	KRKCDY	1809


X60	LEVIN	0555	STANDR	0630
X60	LEVIN	0641	STANDR	0715
X60	LEVIN	0716	STANDR	0751
X59	KRKCDY	0814	GLNRTH	0835	CUPAR	0856
X60	LEVIN	0806	STANDR	0841
X59	KRKCDY	0909	GLNRTH	0930	CUPAR	0951
X60	LEVIN	0916	STANDR	0951
X60	KRKCDY	0948	LEVIN	1016	STANDR	1051
X59	KRKCDY	1008	GLNRTH	1029	CUPAR	1050
X60	KRKCDY	1048	LEVIN	1116	STANDR	1151
X59	KRKCDY	1108	GLNRTH	1129	CUPAR	1150

X60	STANDR	1700	LEVIN	1736	KRKCDY	1803
X59	CUPAR	1711	GLNRTH	1732
X60	STANDR	1735	LEVIN	1811
X60	STANDR	1800	LEVIN	1836	KRKCDY	1903
X59	CUPAR	1821	GLNRTH	1842
X59	CUPAR	1921	GLNRTH	1947	KRKCDY	2011
X60	STANDR	1930	LEVIN	2005
X59	GLNRTH	2047	KRKCDY	2111
X60	STANDR	2030	LEVIN	2105
X59	GLNRTH	2147	KRKCDY	2211
X60	STANDR	2330	LEVIN	2405

64	CUPAR	0730	STANDR	0813
64	CUPAR	0850	STANDR	0933
64B	CUPAR	0925	STANDR	1013
64	CUPAR	1028	STANDR	1113

64	STANDR	1715	CUPAR	1758
64A	STANDR	1915	CUPAR	1956
64A	STANDR	2115	CUPAR	2156
64A	STANDR	2315	CUPAR	2356

66	GLNRTH	0628	CUPAR	0728
67	GLNRTH	0645	CUPAR	0720
267	GLNRTH	0755	CUPAR	0838
66	GLNRTH	0755	CUPAR	0856
67	GLNRTH	1000	CUPAR	1055

66	CUPAR	1810	GLNRTH	1908
66	CUPAR	1920	GLNRTH	2018
66	CUPAR	2120	GLNRTH	2218
66	CUPAR	2320	GLNRTH	2418

95	LEVIN	0545	STANDR	0705
95	LEVIN	0640	STANDR	0750
95	LEVIN	0705	STANDR	0840
95	LEVIN	0835	STANDR	0957
95	LEVIN	0935	STANDR	1057

95	STANDR	1815	LEVIN	1936
95	STANDR	1900	LEVIN	2021
95	STANDR	1945	LEVIN	2105
95	STANDR	2045	LEVIN	2205
95	STANDR	2145	LEVIN	2305
95	STANDR	2245	LEVIN	2405


