Passed
Push — main ( 4059b3...f7ff17 )
by ANDREY
02:27
created

Glyph::getWidthByContent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 7
ccs 3
cts 4
cp 0.75
crap 2.0625
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace VPA\Console\Glyphs;
4
5
use VPA\Console\Color;
6
use VPA\Console\FrameConfigInterface;
7
use VPA\Console\FrameSymbol;
8
use VPA\Console\Nodes;
9
use VPA\Console\Symbol;
10
use VPA\Console\SymbolMode;
11
use VPA\DI\Injectable;
12
13
#[Injectable]
14
abstract class Glyph
15
{
16
    use Nodes;
17
18
    protected array $children = [];
19
    protected array $config = [];
20
    protected ?Glyph $parent = null;
21
    protected int $documentWidth = 80;
22
    protected int $width = 0;
23
    protected int $height = 0;
24
    protected ?bool $isFirstSibling = null;
25
    protected ?bool $isLastSibling = null;
26
    protected bool $isRendered = false;
27
    protected array $renderMap = [];
28
    protected array $cachedRenderMap = [];
29
    protected int $X = 0;
30
    protected int $Y = 0;
31
    protected int $offsetX = 0;
32
    protected int $offsetY = 0;
33
    protected bool $renderedWidth = false;
34
    protected bool $renderedHeight = false;
35
    protected int $contentWidth = 0;
36
    protected int $contentHeight = 0;
37
    protected array $symbolConfig = [];
38
39
40 54
    public function __construct(protected FrameConfigInterface $globalConfig)
41
    {
42 54
        $this->config = [
43
            'overflowX' => 'none',
44
            'overflowY' => 'none',
45
            'paddingLeft' => 0,
46
            'paddingRight' => 0,
47
            'paddingTop' => 0,
48
            'paddingBottom' => 0,
49
            'width' => 'auto',
50
            'maxWidth' => 100,
51
            'mode' => SymbolMode::DEFAULT,
52
            'color' => Color::WHITE,
53
        ];
54
    }
55 39
56
    public function __isset(string $name): bool
57 39
    {
58
        return array_key_exists($name, $this->config);
59
    }
60 38
61
    public function __set(string $name, mixed $value): void
62 38
    {
63 37
        if ($this->__isset($name)) {
64 37
            $this->config[$name] = $value;
65
            return;
66 1
        }
67 1
        throw new \Exception(
68
            sprintf(
69
                "The property %s not exists for the %s element.",
70 1
                $name,
71
                get_class($this)
72
            )
73
        );
74
    }
75 51
76
    public function __get(string $name): mixed
77 51
    {
78
        return $this->config[$name] ?? null;
79
    }
80 37
81
    public function setConfig(array $config): Glyph
82 37
    {
83 37
        $this->config = array_merge($this->config, $config);
84
        return $this;
85
    }
86 46
87
    public function getConfig(): array
88 46
    {
89
        return $this->config;
90
    }
91 28
92
    public function addChild(Glyph $child): Glyph
93 28
    {
94 28
        $this->children[] = $child;
95 28
        $child->setParent($this);
96
        return $child;
97
    }
98 26
99
    public function getChildren(): array
100 26
    {
101
        return $this->children;
102
    }
103 14
104
    public function assign(): array
105 14
    {
106 1
        if ($this->isRendered) {
107
            return $this->renderMap;
108 14
        }
109 14
        $this->isRendered = true;
110 14
        $this->render();
111
        return $this->renderMap;
112
    }
113 3
114
    public function display(): void
115 3
    {
116 3
        $this->assign();
117
        $this->printMap();
118
    }
119 14
120
    public function render(): Glyph
121 14
    {
122 14
        $width = $this->getWidth();
123 14
        $height = $this->getHeight();
124
        $this->symbolConfig = [
125 14
            'mode' => SymbolMode::DEFAULT,
126 14
            'color' => $this->__get('borderColor'),
127
            'backgroundColor' => $this->__get('backgroundColor'),
128 14
        ];
129 14
        for ($i = 0; $i < $height; $i++) {
130
            $this->renderMap[$i] = array_fill(0, $width, clone $this->gc('space'));
131 14
        }
132 13
        foreach ($this->children as $child) {
133
            $this->mergeMaps($child->render());
134 14
        }
135
        return $this;
136
    }
137 1
138
    public function isFirstSibling(Glyph $child): bool
139 1
    {
140 1
        $first = reset($this->children);
141
        return $first !== false && $first === $child;
142
    }
143 1
144
    public function isLastSibling(Glyph $child): bool
145 1
    {
146 1
        $last = end($this->children);
147
        return $last !== false && $last === $child;
148
    }
149 2
150
    public function ifFirstSibling(array $config): Glyph
151 2
    {
152 1
        if (!$this->parent) {
153
            return $this;
154 1
        }
155 1
        $first = $this->parent->isFirstSibling($this);
156 1
        if ($first) {
157 1
            foreach ($config as $property => $value) {
158
                $this->__set($property, $value);
159
            }
160 1
        }
161
        return $this;
162
    }
163 2
164
    public function ifLastSibling(array $config): Glyph
165 2
    {
166 1
        if (!$this->parent) {
167
            return $this;
168 1
        }
169 1
        $last = $this->parent->isLastSibling($this);
170 1
        if ($last) {
171 1
            foreach ($config as $property => $value) {
172
                $this->__set($property, $value);
173
            }
174 1
        }
175
        return $this;
176
    }
177 2
178
    public function getDocumentWidth(): int
179 2
    {
180 1
        if (is_null($this->parent)) {
181
            return $this->documentWidth;
182 1
        } else {
183
            return $this->parent->getDocumentWidth();
184
        }
185
    }
186 3
187
    protected function printMap(): void
188 3
    {
189 3
        foreach ($this->renderMap as $y => $list) {
190
            echo implode("", $list) . "\n";
191
        }
192
    }
193 17
194
    public function getWidthByContent(int $endOfPreviousSibling = 0): int
195 17
    {
196 17
        $this->X = $endOfPreviousSibling;
197
        foreach ($this->children as $child) {
198
            $this->width = $child->getWidthByContent(0);
199 17
        }
200
        return $this->width;
201
    }
202 23
203
    public function getHeightByContent(int $endOfPreviousSibling = 0): int
204 23
    {
205 23
        $this->Y = $endOfPreviousSibling;
206
        foreach ($this->children as $child) {
207
            $this->height = $child->getHeightByContent();
208 23
        }
209
        return $this->height;
210
    }
211 24
212
    protected function gc(string $name): object
213 24
    {
214 24
        $property = $this->globalConfig->__get($name);
215 14
        if ($property instanceof Symbol) {
216
            return $property->setConfig($this->symbolConfig);
217 16
        }
218
        return $property;
219
    }
220
221 34
222
    public function getWidth(): int
223 34
    {
224
        return $this->width;
225
    }
226 18
227
    public function setX(int $x): void
228 18
    {
229
        $this->X = $x;
230
    }
231 23
232
    public function setY(int $y): void
233 23
    {
234
        $this->Y = $y;
235
    }
236 13
237
    public function setWidth(int $width): Glyph
238 13
    {
239 13
        $configWidth = $this->__get('width');
240 12
        if ($configWidth == 'auto') {
241
            $this->width = $width;
242 1
        } else {
243
            $this->width = intval($configWidth);
244 13
        }
245 9
        foreach ($this->getChildren() as $child) {
246
            $child->__set('maxWidth', $width);
247 13
        }
248 13
        $this->renderedWidth = true;
249
        return $this;
250
    }
251 17
252
    public function getHeight(): int
253 17
    {
254
        return $this->height;
255
    }
256 10
257
    public function setHeight(int $height): Glyph
258 10
    {
259 10
        $this->height = $height;
260 10
        $this->renderedHeight = true;
261
        return $this;
262
    }
263 28
264
    public function setParent(Glyph $parent): void
265 28
    {
266
        $this->parent = $parent;
267
    }
268 31
269
    public function getParent(): Glyph|null
270 31
    {
271
        return $this->parent;
272
    }
273 13
274
    private function mergeMaps(Glyph $render): void
275 13
    {
276 13
        $offsetX = $render->X + $this->offsetX;
277 13
        $offsetY = $render->Y + $this->offsetY;
278 13
        foreach ($render->renderMap as $y => $line) {
279 13
            foreach ($line as $x => $item) {
280 13
                $coordX = $offsetX + $x;
281 13
                $coordY = $offsetY + intval($y);
282
                $this->renderMap[$coordY][$coordX] = $item;
283
            }
284
        }
285
    }
286
}
287