Passed
Push — master ( aa3b71...5e2219 )
by Nico
55:07 queued 26:20
created

ShipMover::checkAndMove()   F

Complexity

Conditions 25
Paths 5832

Size

Total Lines 172
Code Lines 96

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 32
CRAP Score 232.3781

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 25
eloc 96
c 2
b 0
f 1
nc 5832
nop 2
dl 0
loc 172
ccs 32
cts 104
cp 0.3076
crap 232.3781
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Stu\Module\Ship\Lib\Movement;
4
5
use Stu\Lib\Information\InformationWrapper;
6
use Stu\Module\PlayerSetting\Lib\UserEnum;
7
use Stu\Module\Ship\Lib\Battle\AlertRedHelperInterface;
8
use Stu\Module\Ship\Lib\Fleet\LeaveFleetInterface;
9
use Stu\Module\Ship\Lib\Message\Message;
10
use Stu\Module\Ship\Lib\Message\MessageCollection;
11
use Stu\Module\Ship\Lib\Message\MessageCollectionInterface;
12
use Stu\Module\Ship\Lib\Movement\Component\PreFlight\PreFlightConditionsCheckInterface;
13
use Stu\Module\Ship\Lib\Movement\Route\FlightRouteInterface;
14
use Stu\Module\Ship\Lib\ShipWrapperInterface;
15
use Stu\Orm\Entity\ShipInterface;
16
use Stu\Orm\Repository\ShipRepositoryInterface;
17
18
//TODO unit tests
19
final class ShipMover implements ShipMoverInterface
20
{
21
    private MessageCollectionInterface $messages;
22
23 1
    public function __construct(
24
        private ShipRepositoryInterface $shipRepository,
25
        private ShipMovementInformationAdderInterface $shipMovementInformationAdder,
26
        private PreFlightConditionsCheckInterface $preFlightConditionsCheck,
27
        private LeaveFleetInterface $leaveFleet,
28
        private AlertRedHelperInterface $alertRedHelper
29
    ) {
30 1
        $this->messages = new MessageCollection();
31
    }
32
33 1
    private function addInformation(string $value): void
34
    {
35 1
        $this->messages->add(new Message(UserEnum::USER_NOONE, null, [$value]));
36
    }
37
38
    /**
39
     * @param array<string> $value
40
     */
41 1
    private function addInformationMerge(array $value): void
42
    {
43 1
        $this->messages->add(new Message(UserEnum::USER_NOONE, null, $value));
44
    }
45
46 1
    public function checkAndMove(
47
        ShipWrapperInterface $leadShipWrapper,
48
        FlightRouteInterface $flightRoute
49
    ): MessageCollectionInterface {
50
51 1
        $leadShip = $leadShipWrapper->get();
52 1
        $leadShipName = $leadShip->getName();
53 1
        $fleetWrapper = $leadShipWrapper->getFleetWrapper();
54
55 1
        $isFleetMode = $leadShip->isFleetLeader();
56 1
        $hasToLeaveFleet = $fleetWrapper !== null && !$isFleetMode;
57
58 1
        $wrappers = $isFleetMode && $fleetWrapper !== null ? $fleetWrapper->getShipWrappers() : [$leadShipWrapper];
59
60 1
        $isFixedFleetMode = $isFleetMode
61 1
            && $fleetWrapper !== null
62 1
            && $fleetWrapper->get()->isFleetFixed();
63
64 1
        $initialTractoredShips = $this->initTractoredShips($wrappers);
65
66 1
        $hasTravelled = false;
67
68
        // fly until destination arrived
69 1
        while (!$flightRoute->isDestinationArrived()) {
70 1
            $nextWaypoint = $flightRoute->getNextWaypoint();
71
72
            // nächstes Feld nicht passierbar
73 1
            if (!$nextWaypoint->getFieldType()->getPassable()) {
74
                $flightRoute->abortFlight();
75
                $this->addInformation(_('Das nächste Feld kann nicht passiert werden'));
76
                break;
77
            }
78
79 1
            $activeWrappers = array_filter(
80 1
                $wrappers,
81 1
                fn (ShipWrapperInterface $wrapper) => !$wrapper->get()->isDestroyed()
82 1
            );
83
84
            // check all flight pre conditions
85 1
            $conditionCheckResult = $this->preFlightConditionsCheck->checkPreconditions(
86 1
                $leadShipWrapper,
87 1
                $activeWrappers,
88 1
                $flightRoute,
89 1
                $isFixedFleetMode
90 1
            );
91
92 1
            if (!$conditionCheckResult->isFlightPossible()) {
93 1
                $flightRoute->abortFlight();
94 1
                $this->addInformation(_('Der Weiterflug wurde aus folgenden Gründen abgebrochen:'));
95 1
                $this->addInformationMerge($conditionCheckResult->getInformations());
96 1
                break;
97
            }
98
99
            $this->addInformationMerge($conditionCheckResult->getInformations());
100
101
            $movedTractoredShips = [];
102
103
            // move every ship by one field
104
            foreach ($activeWrappers as $wrapper) {
105
106
                $ship = $wrapper->get();
107
108
                if ($conditionCheckResult->isNotBlocked($ship)) {
109
110
                    $this->leaveFleetIfNotFleetLeader($ship, $hasToLeaveFleet);
111
112
                    $flightRoute->enterNextWaypoint(
113
                        $wrapper,
114
                        $this->messages
115
                    );
116
117
                    $tractoredShipWrapper = $wrapper->getTractoredShipWrapper();
118
                    if ($tractoredShipWrapper !== null) {
119
                        $flightRoute->enterNextWaypoint(
120
                            $tractoredShipWrapper,
121
                            $this->messages
122
                        );
123
124
                        $movedTractoredShips[] = [$wrapper->get(), $tractoredShipWrapper->get()];
125
                    }
126
127
                    $hasTravelled = true;
128
                }
129
            }
130
131
            $flightRoute->stepForward();
132
133
            // alert red check
134
            $alertRedInformations = new InformationWrapper();
135
            $this->alertRedHelper->doItAll($leadShip, $alertRedInformations);
136
137
            if (!$alertRedInformations->isEmpty()) {
138
                $this->addInformationMerge($alertRedInformations->getInformations());
139
            }
140
141
            // alert red check for tractored ships
142
            foreach ($movedTractoredShips as [$tractoringShip, $tractoredShip]) {
143
                if (!$tractoredShip->isDestroyed()) {
144
                    $alertRedInformations = new InformationWrapper();
145
                    $this->alertRedHelper->doItAll(
146
                        $tractoredShip,
147
                        $alertRedInformations,
148
                        $tractoringShip
149
                    );
150
151
                    if (!$alertRedInformations->isEmpty()) {
152
                        $this->addInformationMerge($alertRedInformations->getInformations());
153
                    }
154
                }
155
            }
156
157
            if ($this->areAllShipsDestroyed($activeWrappers)) {
158
                $flightRoute->abortFlight();
159
                $this->addInformation(_('Es wurden alle Schiffe zerstört'));
160
            }
161
        }
162
163
        //skip save and log info if flight did not happen
164 1
        if (!$hasTravelled) {
165 1
            return $this->messages;
166
        }
167
168
        // save all ships
169
        foreach ($wrappers as $wrapper) {
170
            $ship = $wrapper->get();
171
            if (!$ship->isDestroyed()) {
172
                $this->shipRepository->save($ship);
173
            }
174
175
            $tractoredShip = $ship->getTractoredShip();
176
            if ($tractoredShip !== null) {
177
                $this->shipMovementInformationAdder->pulledTractoredShip(
178
                    $ship,
179
                    $tractoredShip,
180
                    $flightRoute->getRouteMode(),
181
                    $this->messages
182
                );
183
            }
184
        }
185
186
187
        foreach ($initialTractoredShips as $tractoredShip) {
188
            $this->shipRepository->save($tractoredShip);
189
        }
190
191
        if ($this->areAllShipsDestroyed($wrappers)) {
192
            $this->shipMovementInformationAdder->reachedDestinationDestroyed(
193
                $leadShip,
194
                $leadShipName,
195
                $isFleetMode,
196
                $flightRoute->getRouteMode(),
197
                $this->messages
198
            );
199
        } else {
200
            $this->shipMovementInformationAdder->reachedDestination(
201
                $leadShip,
202
                $isFleetMode,
203
                $flightRoute->getRouteMode(),
204
                $this->messages
205
            );
206
        }
207
208
        //add info about anomalies
209
        foreach ($leadShipWrapper->get()->getLocation()->getAnomalies() as $anomaly) {
210
            $this->addInformation(sprintf('[b][color=yellow]In diesem Sektor befindet sich eine %s[/color][/b]', $anomaly->getAnomalyType()->getName()));
211
        }
212
        // add info about buyos
213
        foreach ($leadShipWrapper->get()->getCurrentMapField()->getBuoys() as $buoy) {
214
            $this->addInformation(sprintf('[b][color=yellow]Boje entdeckt: [/color][/b]%s', $buoy->getText()));
215
        }
216
217
        return $this->messages;
218
    }
219
220
    /**
221
     * @param array<ShipWrapperInterface> $wrappers
222
     * 
223
     * @return array<ShipInterface>
224
     */
225 1
    private function initTractoredShips(array $wrappers): array
226
    {
227 1
        $tractoredShips = [];
228
229 1
        foreach ($wrappers as $fleetShipWrapper) {
230 1
            $fleetShip = $fleetShipWrapper->get();
231
232 1
            $tractoredShip = $fleetShip->getTractoredShip();
233
            if (
234 1
                $tractoredShip !== null
235
            ) {
236
                $tractoredShips[] = $tractoredShip;
237
            }
238
        }
239
240 1
        return $tractoredShips;
241
    }
242
243
    private function leaveFleetIfNotFleetLeader(ShipInterface $ship, bool $hasToLeaveFleet): void
244
    {
245
        if ($hasToLeaveFleet && $ship->getFleet() !== null) {
246
            $this->leaveFleet->leaveFleet($ship);
247
            $this->addInformation(sprintf('Die %s hat die Flotte verlassen', $ship->getName()));
248
        }
249
    }
250
251
    /**
252
     * @param ShipWrapperInterface[] $wrappers
253
     */
254
    private function areAllShipsDestroyed(array $wrappers): bool
255
    {
256
        foreach ($wrappers as $wrapper) {
257
            if (!$wrapper->get()->isDestroyed()) {
258
                return false;
259
            }
260
        }
261
262
        return true;
263
    }
264
}
265