Passed
Push — master ( 200d88...9b81d7 )
by Alec
02:43 queued 15s
created

AStyleFrameRenderer   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 104
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 34
dl 0
loc 104
rs 10
c 3
b 0
f 0
wmc 15

7 Methods

Rating   Name   Duplication   Size   Complexity  
A render() 0 6 2
A createFrame() 0 16 3
A createFromStyle() 0 9 3
A isStylingDisabled() 0 3 1
A sequenceFrame() 0 6 1
A __construct() 0 6 1
A flattenStyle() 0 14 4
1
<?php
2
3
declare(strict_types=1);
4
// 24.03.23
5
namespace AlecRabbit\Spinner\Core\A;
6
7
use AlecRabbit\Spinner\Contract\IAnsiStyleConverter;
8
use AlecRabbit\Spinner\Contract\IFrame;
9
use AlecRabbit\Spinner\Contract\ISequencer;
10
use AlecRabbit\Spinner\Contract\IStyle;
11
use AlecRabbit\Spinner\Contract\IStyleFrameRenderer;
12
use AlecRabbit\Spinner\Contract\StyleMode;
13
use AlecRabbit\Spinner\Core\Factory\FrameFactory;
14
use AlecRabbit\Spinner\Core\Sequencer;
15
use AlecRabbit\Spinner\Exception\DomainException;
16
use AlecRabbit\Spinner\Exception\InvalidArgumentException;
17
use AlecRabbit\Spinner\Exception\LogicException;
18
use AlecRabbit\Spinner\Helper\Asserter;
19
20
abstract class AStyleFrameRenderer implements IStyleFrameRenderer
21
{
22
    /** @var class-string<ISequencer> */
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<ISequencer> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<ISequencer>.
Loading history...
23
    protected string $sequencer;
24
25
    /**
26
     * @param IAnsiStyleConverter $converter
27
     * @param class-string<ISequencer> $sequencer
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<ISequencer> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<ISequencer>.
Loading history...
28
     * @throws InvalidArgumentException
29
     */
30
    public function __construct(
31
        protected IAnsiStyleConverter $converter,
32
        string $sequencer = Sequencer::class,
33
    ) {
34
        Asserter::isSubClass($sequencer, ISequencer::class, __METHOD__);
35
        $this->sequencer = $sequencer;
36
    }
37
38
    /**
39
     * @throws LogicException
40
     * @throws InvalidArgumentException
41
     */
42
    public function render(int|string|IStyle $entry, StyleMode $styleMode = StyleMode::NONE): IFrame
43
    {
44
        if ($this->isStylingDisabled()) {
45
            throw new LogicException('Styling is disabled.'); // should never happen
46
        }
47
        return $this->createFrame($entry, $styleMode);
48
    }
49
50
    public function isStylingDisabled(): bool
51
    {
52
        return $this->converter->isDisabled();
53
    }
54
55
    /**
56
     * @throws LogicException
57
     * @throws InvalidArgumentException
58
     */
59
    protected function createFrame(int|string|IStyle $entry, StyleMode $styleMode): IFrame
60
    {
61
        if ($styleMode === StyleMode::NONE) {
62
            return FrameFactory::create('%s', 0);
63
        }
64
65
        if ($entry instanceof IStyle) {
66
            return $this->createFromStyle($entry, $styleMode);
67
        }
68
69
        $ansiCode = $this->converter->ansiCode($entry, $styleMode);
70
71
        $color = '3' . $ansiCode . 'm' . '%s';
72
73
        return
74
            $this->sequenceFrame($color, 0);
75
    }
76
77
    /**
78
     * @throws DomainException
79
     * @throws InvalidArgumentException
80
     * @throws LogicException
81
     */
82
    protected function createFromStyle(IStyle $entry, StyleMode $styleMode): IFrame
83
    {
84
        if ($entry->isEmpty() || $entry->isOptionsOnly()) {
85
            return FrameFactory::create('%s', $entry->getWidth());
86
        }
87
88
        $color = $this->flattenStyle($entry, $styleMode);
89
        return
90
            $this->sequenceFrame($color, $entry->getWidth());
91
    }
92
93
    /**
94
     * // FIXME: method has non-optimal implementation
95
     * @throws DomainException
96
     * @throws InvalidArgumentException
97
     * @throws LogicException
98
     */
99
    protected function flattenStyle(IStyle $entry, StyleMode $styleMode): string
100
    {
101
        $fgColor = $entry->getFgColor();
102
        $bgColor = $entry->getBgColor();
103
        $color = '';
104
        if (null !== $fgColor) {
105
            $color .= '3' . $this->converter->ansiCode((string)$fgColor, $styleMode);
106
        }
107
        if (null !== $bgColor) {
108
            $separator = null !== $fgColor ? ';' : '';
109
            $color .= $separator . '4' . $this->converter->ansiCode((string)$bgColor, $styleMode);
110
        }
111
        $color .= 'm%s';
112
        return $color;
113
    }
114
115
    /**
116
     * FIXME rename method
117
     */
118
    protected function sequenceFrame(string $color, int $width): IFrame
119
    {
120
        /** @var ISequencer $sequencer */
121
        $sequencer = $this->sequencer;
122
        return
123
            FrameFactory::create($sequencer::colorSequence($color), $width);
124
    }
125
}