SpacecraftSystemManager::deactivate()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 3
dl 0
loc 10
ccs 5
cts 5
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Component\Spacecraft\System;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Collection;
9
use Stu\Component\Spacecraft\System\Exception\ActivationConditionsNotMetException;
10
use Stu\Component\Spacecraft\System\Exception\AlreadyActiveException;
11
use Stu\Component\Spacecraft\System\Exception\AlreadyOffException;
12
use Stu\Component\Spacecraft\System\Exception\DeactivationConditionsNotMetException;
13
use Stu\Component\Spacecraft\System\Exception\InsufficientCrewException;
14
use Stu\Component\Spacecraft\System\Exception\InsufficientEnergyException;
15
use Stu\Component\Spacecraft\System\Exception\InvalidSystemException;
16
use Stu\Component\Spacecraft\System\Exception\SpacecraftSystemException;
17
use Stu\Component\Spacecraft\System\Exception\SystemCooldownException;
18
use Stu\Component\Spacecraft\System\Exception\SystemDamagedException;
19
use Stu\Component\Spacecraft\System\Exception\SystemNotActivatableException;
20
use Stu\Component\Spacecraft\System\Exception\SystemNotDeactivatableException;
21
use Stu\Component\Spacecraft\System\Exception\SystemNotFoundException;
22
use Stu\Module\Control\StuTime;
23
use Stu\Module\Spacecraft\Lib\SpacecraftWrapperInterface;
24
use Stu\Orm\Entity\SpacecraftSystem;
25
use Stu\Orm\Entity\Spacecraft;
26
27
final class SpacecraftSystemManager implements SpacecraftSystemManagerInterface
28
{
29
    /**
30
     * @param array<SpacecraftSystemTypeInterface> $systemList
31
     */
32 20
    public function __construct(private array $systemList, private StuTime $stuTime) {}
33
34 26
    #[\Override]
35
    public function activate(
36
        SpacecraftWrapperInterface $wrapper,
37
        SpacecraftSystemTypeEnum $type,
38
        bool $force = false,
39
        bool $isDryRun = false
40
    ): void {
41 26
        $time = $this->stuTime->time();
42 26
        $system = $this->lookupSystem($type);
43
44 26
        if (!$force) {
45 26
            $this->checkActivationConditions($wrapper, $system, $type, $time);
46
        }
47
48 12
        if ($isDryRun) {
49 5
            return;
50
        }
51
52 11
        $epsSystem = $wrapper->getEpsSystemData();
53 11
        if ($epsSystem !== null) {
54 11
            $epsSystem->lowerEps($system->getEnergyUsageForActivation())->update();
55
        }
56
57 11
        $this->setCooldown($wrapper, $type, $time, $system);
58
59 11
        $system->activate($wrapper, $this);
60
    }
61
62 11
    private function setCooldown(
63
        SpacecraftWrapperInterface $wrapper,
64
        SpacecraftSystemTypeEnum $type,
65
        int $time,
66
        SpacecraftSystemTypeInterface $system
67
    ): void {
68 11
        $shipSystem = $wrapper->get()->getSystems()[$type->value] ?? null;
69 11
        if ($shipSystem !== null && $system->getCooldownSeconds() !== null) {
70 1
            $shipSystem->setCooldown($time + $system->getCooldownSeconds());
71
        }
72
    }
73
74 17
    #[\Override]
75
    public function deactivate(SpacecraftWrapperInterface $wrapper, SpacecraftSystemTypeEnum $type, bool $force = false): void
76
    {
77 17
        $system = $this->lookupSystem($type);
78
79 16
        if (!$force) {
80 11
            $this->checkDeactivationConditions($wrapper, $system, $type);
81
        }
82
83 9
        $system->deactivate($wrapper);
84
    }
85
86 3
    #[\Override]
87
    public function deactivateAll(SpacecraftWrapperInterface $wrapper): void
88
    {
89 3
        foreach ($wrapper->get()->getSystems() as $shipSystem) {
90
            try {
91 3
                $this->deactivate($wrapper, $shipSystem->getSystemType(), true);
92 1
            } catch (SpacecraftSystemException) {
93 1
                continue;
94
            }
95
        }
96
    }
97
98 4
    #[\Override]
99
    public function getEnergyUsageForActivation(SpacecraftSystemTypeEnum $type): int
100
    {
101 4
        $system = $this->lookupSystem($type);
102
103 4
        return $system->getEnergyUsageForActivation();
104
    }
105
106 16
    #[\Override]
107
    public function getEnergyConsumption(SpacecraftSystemTypeEnum $type): int
108
    {
109 16
        $system = $this->lookupSystem($type);
110
111 16
        return $system->getEnergyConsumption();
112
    }
113
114 49
    #[\Override]
115
    public function lookupSystem(SpacecraftSystemTypeEnum $type): SpacecraftSystemTypeInterface
116
    {
117 49
        $system = $this->systemList[$type->value] ?? null;
118 49
        if ($system === null) {
119 1
            throw new InvalidSystemException();
120
        }
121
122 48
        return $system;
123
    }
124
125 26
    private function checkActivationConditions(
126
        SpacecraftWrapperInterface $wrapper,
127
        SpacecraftSystemTypeInterface $system,
128
        SpacecraftSystemTypeEnum $type,
129
        int $time
130
    ): void {
131 26
        $ship = $wrapper->get();
132 26
        $shipSystem = $ship->getSystems()[$type->value] ?? null;
133 26
        if ($shipSystem === null) {
134 8
            throw new SystemNotFoundException();
135
        }
136
137 23
        if ($shipSystem->getStatus() === 0) {
138 1
            throw new SystemDamagedException();
139
        }
140
141 22
        $mode = $shipSystem->getMode();
142 22
        if ($mode === SpacecraftSystemModeEnum::MODE_ALWAYS_OFF) {
143 1
            throw new SystemNotActivatableException();
144
        }
145
146 21
        if ($mode->isActivated()) {
147 6
            throw new AlreadyActiveException();
148
        }
149
150 17
        if (!$ship->hasEnoughCrew() && !$system->canBeActivatedWithInsufficientCrew()) {
151 2
            throw new InsufficientCrewException();
152
        }
153
154 15
        $epsSystem = $wrapper->getEpsSystemData();
155 15
        if ($epsSystem === null || $epsSystem->getEps() < $system->getEnergyUsageForActivation()) {
156 1
            throw new InsufficientEnergyException($system->getEnergyUsageForActivation());
157
        }
158
159 14
        $cooldown = $shipSystem->getCooldown();
160 14
        if ($cooldown !== null && $cooldown > $time) {
161 1
            throw new SystemCooldownException($cooldown - $time);
162
        }
163
164 13
        $reason = '';
165 13
        if (!$system->checkActivationConditions($wrapper, $reason)) {
166 1
            throw new ActivationConditionsNotMetException($reason);
167
        }
168
    }
169
170 11
    private function checkDeactivationConditions(
171
        SpacecraftWrapperInterface $wrapper,
172
        SpacecraftSystemTypeInterface $system,
173
        SpacecraftSystemTypeEnum $type
174
    ): void {
175 11
        $ship = $wrapper->get();
176 11
        $shipSystem = $ship->getSystems()[$type->value] ?? null;
177 11
        if ($shipSystem === null) {
178 2
            throw new SystemNotFoundException();
179
        }
180
181 10
        $mode = $shipSystem->getMode();
182 10
        if ($mode === SpacecraftSystemModeEnum::MODE_ALWAYS_ON) {
183 1
            throw new SystemNotDeactivatableException();
184
        }
185
186
        if (
187 9
            $mode === SpacecraftSystemModeEnum::MODE_OFF
188 9
            ||  $mode === SpacecraftSystemModeEnum::MODE_ALWAYS_OFF
189
        ) {
190 5
            throw new AlreadyOffException();
191
        }
192
193 5
        $reason = '';
194 5
        if (!$system->checkDeactivationConditions($wrapper, $reason)) {
195 1
            throw new DeactivationConditionsNotMetException($reason);
196
        }
197
    }
198
199
    #[\Override]
200
    public function handleDestroyedSystem(SpacecraftWrapperInterface $wrapper, SpacecraftSystemTypeEnum $type): void
201
    {
202
        $system = $this->lookupSystem($type);
203
204
        $system->handleDestruction($wrapper);
205
    }
206
207 1
    #[\Override]
208
    public function handleDamagedSystem(SpacecraftWrapperInterface $wrapper, SpacecraftSystemTypeEnum $type): void
209
    {
210 1
        $system = $this->lookupSystem($type);
211
212 1
        $system->handleDamage($wrapper);
213
    }
214
215 17
    #[\Override]
216
    public function getActiveSystems(Spacecraft $ship, bool $sort = false): Collection
217
    {
218 17
        $activeSystems = [];
219 17
        $prioArray = [];
220 17
        foreach ($ship->getSystems() as $system) {
221 17
            if ($system->getMode()->isActivated()) {
222 17
                $activeSystems[] = $system;
223 17
                if ($sort) {
224
                    $prioArray[$system->getSystemType()->value] = $system->getSystemType()->getPriority();
225
                }
226
            }
227
        }
228
229 17
        if ($sort) {
230
            usort(
231
                $activeSystems,
232
                fn(SpacecraftSystem $a, SpacecraftSystem $b): int => $prioArray[$a->getSystemType()->value] <=> $prioArray[$b->getSystemType()->value]
233
            );
234
        }
235
236 17
        return new ArrayCollection($activeSystems);
237
    }
238
}
239