Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 113
0.00% covered (danger)
0.00%
0 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
TransportSuggestion
0.00% covered (danger)
0.00%
0 / 113
0.00% covered (danger)
0.00%
0 / 17
812
0.00% covered (danger)
0.00%
0 / 1
 getFieldValue
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 fromFieldValue
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 populateFromFieldValue
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 getPrettyPrint
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
72
 getMainConnection
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setMainConnection
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSideConnections
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addSideConnection
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getOriginInfo
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setOriginInfo
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDebug
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addDebug
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 generateOriginInfo
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
6
 getDestinationHalt
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getHaltAtStation
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
 getFlatHalts
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getRatingForHalt
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace Olz\Apps\Oev\Utils;
4
5use Olz\Utils\WithUtilsTrait;
6
7class TransportSuggestion {
8    use WithUtilsTrait;
9
10    protected TransportConnection $mainConnection;
11    /** @var array<array{connection: TransportConnection, joiningStationId: string}> */
12    protected array $sideConnections = [];
13    /** @var array<mixed> */
14    protected array $originInfo = [];
15    /** @var array<string> */
16    protected array $debug = [];
17
18    /** @return array<string, mixed> */
19    public function getFieldValue(): array {
20        return [
21            'mainConnection' => $this->mainConnection->getFieldValue(),
22            'sideConnections' => array_map(function ($side_connection) {
23                return [
24                    'connection' => $side_connection['connection']->getFieldValue(),
25                    'joiningStationId' => $side_connection['joiningStationId'],
26                ];
27            }, $this->sideConnections),
28            'originInfo' => $this->originInfo,
29            'debug' => implode("\n", $this->debug),
30        ];
31    }
32
33    /** @param array<string, mixed> $value */
34    public static function fromFieldValue(array $value): self {
35        $instance = new self();
36        $instance->populateFromFieldValue($value);
37        return $instance;
38    }
39
40    /** @param array<string, mixed> $value */
41    protected function populateFromFieldValue(array $value): void {
42        $this->mainConnection = TransportConnection::fromFieldValue($value['mainConnection']);
43        $this->sideConnections = array_map(function ($side_connection) {
44            return [
45                'connection' => TransportConnection::fromFieldValue($side_connection['connection']),
46                'joiningStationId' => $side_connection['joiningStationId'],
47            ];
48        }, $value['sideConnections']);
49        $this->originInfo = $value['originInfo'];
50        $this->debug = explode("\n", $value['debug']);
51    }
52
53    public function getPrettyPrint(): string {
54        $all_entries = [];
55        foreach ($this->mainConnection->getFlatHalts() as $halt) {
56            $all_entries[] = [
57                'halt' => $halt,
58                'connection_index' => 0,
59                'is_joining_halt' => false,
60            ];
61        }
62        $side_connection_index = 1;
63        foreach ($this->sideConnections as $side_connection) {
64            $has_joined = false;
65            foreach ($side_connection['connection']->getFlatHalts() as $halt) {
66                $is_joining_halt = $side_connection['joiningStationId'] == $halt->getStationId();
67                if (!$has_joined) {
68                    $all_entries[] = [
69                        'halt' => $halt,
70                        'connection_index' => $side_connection_index,
71                        'is_joining_halt' => $is_joining_halt,
72                    ];
73                }
74                if ($is_joining_halt) {
75                    $has_joined = true;
76                }
77            }
78            $side_connection_index++;
79        }
80        usort(
81            $all_entries,
82            function ($entry_a, $entry_b) {
83                $entry_a_value = $entry_a['halt']->getTimeSeconds();
84                $entry_b_value = $entry_b['halt']->getTimeSeconds();
85                return $entry_a_value < $entry_b_value ? -1 : 1;
86            }
87        );
88        $num_connections = count($this->sideConnections) + 1;
89        return implode("\n", array_map(function ($entry) use ($num_connections) {
90            $before_dot = str_repeat('  ', $entry['connection_index']);
91            $after_dot = str_repeat('  ', $num_connections - $entry['connection_index'] - 1);
92            $dot = $entry['is_joining_halt'] ? '<' : 'O';
93            $halt = $entry['halt'];
94            return "{$before_dot}{$dot}{$after_dot} {$halt->getTimeString()} {$halt->getStationName()}";
95        }, $all_entries));
96    }
97
98    public function getMainConnection(): TransportConnection {
99        return $this->mainConnection;
100    }
101
102    public function setMainConnection(TransportConnection $new_main_connection): void {
103        $this->mainConnection = $new_main_connection;
104    }
105
106    /** @return array<array{connection: TransportConnection, joiningStationId: string}> */
107    public function getSideConnections(): array {
108        return $this->sideConnections;
109    }
110
111    /** @param array{connection: TransportConnection, joiningStationId: string} $new_side_connection */
112    public function addSideConnection(array $new_side_connection): void {
113        $this->sideConnections[] = $new_side_connection;
114    }
115
116    /** @return array<mixed> */
117    public function getOriginInfo(): array {
118        return $this->originInfo;
119    }
120
121    /** @param array<mixed> $new_origin_info */
122    public function setOriginInfo(array $new_origin_info): void {
123        $this->originInfo = $new_origin_info;
124    }
125
126    /** @return array<string> */
127    public function getDebug(): array {
128        return $this->debug;
129    }
130
131    public function addDebug(string $line): void {
132        $this->debug[] = $line;
133    }
134
135    /**
136     * @param array<mixed> $origin_stations
137     *
138     * @return array<mixed>
139     */
140    public function generateOriginInfo(array $origin_stations): array {
141        $most_important_stations = array_slice($origin_stations, 0);
142        usort(
143            $most_important_stations,
144            function ($station_a, $station_b) {
145                $station_a_weight = $station_a['weight'] ?? 0;
146                $station_b_weight = $station_b['weight'] ?? 0;
147                return $station_a_weight < $station_b_weight ? 1 : -1;
148            }
149        );
150        $destination_halt = $this->getDestinationHalt();
151        return array_map(function ($station) use ($destination_halt) {
152            $station_id = $station['id'];
153            $halt_at_station = $this->getHaltAtStation($station_id);
154            return [
155                'halt' => [
156                    'stationId' => $station_id,
157                    'stationName' => $station['name'],
158                    'time' => $halt_at_station?->getTimeString() ?? '',
159                ],
160                'isSkipped' => $halt_at_station === null,
161                'rating' => $this->getRatingForHalt($halt_at_station, $destination_halt),
162            ];
163        }, $most_important_stations);
164    }
165
166    public function getDestinationHalt(): TransportHalt {
167        return $this->mainConnection->getDestinationHalt();
168    }
169
170    public function getHaltAtStation(string $station_id): ?TransportHalt {
171        $halts = $this->getFlatHalts();
172        $halts_at_station = array_values(array_filter(
173            $halts,
174            function ($halt) use ($station_id) {
175                return $halt->getStationId() === $station_id;
176            }
177        ));
178        $last_index = count($halts_at_station) - 1;
179        if ($last_index === -1) {
180            return null;
181        }
182        return $halts_at_station[$last_index];
183    }
184
185    /** @return array<TransportHalt> */
186    public function getFlatHalts(): array {
187        return array_merge(
188            $this->mainConnection->getFlatHalts(),
189            ...array_map(function ($side_connection) {
190                return $side_connection['connection']->getFlatHalts();
191            }, $this->sideConnections),
192        );
193    }
194
195    public function getRatingForHalt(?TransportHalt $halt, ?TransportHalt $destination_halt): float {
196        if (!$halt || !$destination_halt) {
197            return 0;
198        }
199        $duration_seconds = $destination_halt->getTimeSeconds() - $halt->getTimeSeconds();
200        return 1 / max(1, log($duration_seconds));
201    }
202}