Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 113 |
|
0.00% |
0 / 17 |
CRAP | |
0.00% |
0 / 1 |
| TransportSuggestion | |
0.00% |
0 / 113 |
|
0.00% |
0 / 17 |
812 | |
0.00% |
0 / 1 |
| getFieldValue | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
2 | |||
| fromFieldValue | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| populateFromFieldValue | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
| getPrettyPrint | |
0.00% |
0 / 37 |
|
0.00% |
0 / 1 |
72 | |||
| getMainConnection | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setMainConnection | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getSideConnections | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| addSideConnection | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getOriginInfo | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setOriginInfo | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getDebug | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| addDebug | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| generateOriginInfo | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
6 | |||
| getDestinationHalt | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getHaltAtStation | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
6 | |||
| getFlatHalts | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| getRatingForHalt | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace Olz\Apps\Oev\Utils; |
| 4 | |
| 5 | use Olz\Utils\WithUtilsTrait; |
| 6 | |
| 7 | class 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 | } |