Passed
Branch main (c6fb67)
by ANDREY
03:35 queued 01:11
created

GlyphBlock::renderBorderLeft()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 9
c 0
b 0
f 0
nc 5
nop 0
dl 0
loc 11
rs 8.8333
1
<?php
2
3
namespace VPA\Console\Glyphs;
4
5
use VPA\Console\FrameConfigInterface;
6
use VPA\Console\Symbol;
7
8
abstract class GlyphBlock extends Glyph
9
{
10
    /**
11
     * @var mixed
12
     */
13
    private int $deltaWidth;
14
    private int $deltaHeight;
15
16
    public function __construct(protected FrameConfigInterface $globalConfig)
17
    {
18
        parent::__construct($globalConfig);
19
        $this->config = array_merge(
20
            parent::getConfig(),
21
            [
22
                'paddingTop' => 0,
23
                'paddingLeft' => 0,
24
                'paddingRight' => 0,
25
                'paddingBottom' => 0,
26
                'borderTop' => 0,
27
                'borderLeft' => 0,
28
                'borderRight' => 0,
29
                'borderBottom' => 0,
30
            ]
31
        );
32
        $this->calculateDeltaWidth();
33
        $this->calculateDeltaHeight();
34
    }
35
36
    public function getContentWidth(): int
37
    {
38
        return $this->width - $this->deltaWidth;
39
    }
40
41
    public function getDeltaWidth(): int
42
    {
43
        return $this->deltaWidth;
44
    }
45
46
    public function getDeltaHeight(): int
47
    {
48
        return $this->deltaHeight;
49
    }
50
51
52
    public function getContentHeight(): int
53
    {
54
        return $this->height - $this->deltaHeight;
55
    }
56
57
    private function calculateDeltaWidth(): void
58
    {
59
        $this->deltaWidth = $this->__get('paddingLeft') +
60
            $this->__get('borderLeft') +
61
            $this->__get('paddingRight') +
62
            $this->__get('borderRight');
63
    }
64
65
    private function calculateDeltaHeight(): void
66
    {
67
        $this->deltaHeight = $this->__get('paddingTop') +
68
            $this->__get('borderTop') +
69
            $this->__get('paddingBottom') +
70
            $this->__get('borderBottom');
71
    }
72
73
    public function setPadding(int $paddingLeft, int $paddingRight, int $paddingTop, int $paddingBottom): GlyphBlock
74
    {
75
        $this->__set('paddingTop', $paddingTop);
76
        $this->__set('paddingLeft', $paddingLeft);
77
        $this->__set('paddingRight', $paddingRight);
78
        $this->__set('paddingBottom', $paddingBottom);
79
        $this->calculateDeltaWidth();
80
        $this->calculateDeltaHeight();
81
        return $this;
82
    }
83
84
    public function setBorder(int $borderLeft, int $borderRight, int $borderTop, int $borderBottom): GlyphBlock
85
    {
86
        $this->__set('borderTop', $borderTop);
87
        $this->__set('borderLeft', $borderLeft);
88
        $this->__set('borderRight', $borderRight);
89
        $this->__set('borderBottom', $borderBottom);
90
        $this->calculateDeltaWidth();
91
        $this->calculateDeltaHeight();
92
        return $this;
93
    }
94
95
    public function appendWidth(int $value): void
96
    {
97
        $this->offsetX = $this->__get('paddingLeft') + $this->__get('borderLeft');
98
        $this->contentWidth = $value;
99
        $this->width = $value + $this->deltaWidth;
100
    }
101
102
    public function appendHeight(int $value): void
103
    {
104
        $this->offsetY = $this->__get('paddingTop') + $this->__get('borderTop');
105
        $this->contentHeight = $value;
106
        $this->height = $value + $this->deltaHeight;
107
    }
108
109
    public function getWidthByContent(int $endOfPreviousSibling = 0): int
110
    {
111
        if ($this->renderedWidth) {
112
            return $this->width;
113
        }
114
        $this->offsetX = $this->__get('paddingLeft') + $this->__get('borderLeft');
115
        $this->setX($endOfPreviousSibling);
116
        $this->contentWidth = 0;
117
        foreach ($this->getChildren() as $child) {
118
            $childWidth = $child->getWidthByContent();
119
            $this->contentWidth = ($childWidth > $this->contentWidth) ? $childWidth : $this->contentWidth;
120
        }
121
        $this->width = $this->contentWidth + $this->getDeltaWidth();
122
        $this->renderedWidth = true;
123
        return $this->width;
124
    }
125
126
    public function getHeightByContent(int $endOfPreviousSibling = 0): int
127
    {
128
        if ($this->renderedHeight) {
129
            return $this->height;
130
        }
131
        $deltaTop = $this->__get('paddingTop') + $this->__get('borderTop');
132
        $this->setY($endOfPreviousSibling);
133
        $this->offsetY = $deltaTop;
134
        $this->height = 0;
135
        $offset = 0;
136
        foreach ($this->children as $child) {
137
            $height = $child->getHeightByContent($offset);
138
            $offset += $height;
139
            $this->contentHeight = $offset;
140
        }
141
        $this->height = $this->contentHeight + $this->getDeltaHeight();
142
        $this->renderedHeight = true;
143
        return $this->height;
144
    }
145
146
    public function render(): Glyph
147
    {
148
        $width = $this->getWidthByContent();
149
        $height = $this->getHeightByContent();
150
        for ($i = 0; $i < $height; $i++) {
151
            $this->renderMap[$i] = array_fill(0, $width, $this->gc('space'));
152
        }
153
        parent::render();
154
        $this->renderBorder();
155
        $this->renderBySprites();
156
        return $this;
157
    }
158
159
    protected function renderBorder(): void
160
    {
161
        $this->renderBorderTop();
162
        $this->renderBorderBottom();
163
        $this->renderBorderLeft();
164
        $this->renderBorderRight();
165
    }
166
167
    private function renderBorderTop(): void
168
    {
169
        if ($this->__get('borderTop')) {
170
            for ($i = 0; $i < $this->getWidth(); $i++) {
171
                $this->renderMap[0][$i] = $this->gc('lineHorizontal');
172
            }
173
        }
174
    }
175
176
    private function renderBorderBottom()
177
    {
178
        $height = $this->getHeight();
179
        if ($this->__get('borderBottom')) {
180
            for ($i = 0; $i < $this->getWidth(); $i++) {
181
                $this->renderMap[$height - 1][$i] = $this->gc('lineHorizontal');
182
            }
183
        }
184
    }
185
186
    private function renderBorderLeft()
187
    {
188
        $height = $this->getHeight();
189
        if ($this->__get('borderLeft')) {
190
            for ($i = 0; $i < $this->getWidth(); $i++) {
191
                if ($i == 0 && $this->renderMap[$i][0]->is($this->gc('lineHorizontal'))) {
192
                    $this->renderMap[$i][0] = $this->gc('cornerLeftTop');
193
                } elseif ($i == $height - 1 && $this->renderMap[$i][0]->is($this->gc('lineHorizontal'))) {
194
                    $this->renderMap[$i][0] = $this->gc('cornerLeftBottom');
195
                } else {
196
                    $this->renderMap[$i][0] = $this->gc('lineVertical');
197
                }
198
            }
199
        }
200
    }
201
202
    private function renderBorderRight(): void
203
    {
204
        $width = $this->getWidth();
205
        $height = $this->getHeight();
206
        if ($this->__get('borderRight')) {
207
            for ($i = 0; $i < $height; $i++) {
208
                if ($i == 0 && $this->renderMap[$i][$width - 1]->is($this->gc('lineHorizontal'))) {
209
                    $this->renderMap[$i][$width - 1] = $this->gc('cornerRightTop');
210
                } elseif (
211
                    $i == $height - 1 &&
212
                    $this->renderMap[$i][$width - 1]->is($this->gc('lineHorizontal'))
213
                ) {
214
                    $this->renderMap[$i][$width - 1] = $this->gc('cornerRightBottom');
215
                } else {
216
                    $this->renderMap[$i][$width - 1] = $this->gc('lineVertical');
217
                }
218
            }
219
        }
220
    }
221
222
    protected function renderBySprites(): void
223
    {
224
        $this->cachedRenderMap = $this->renderMap;
225
        foreach ($this->renderMap as $y => $line) {
226
            foreach ($line as $x => $symbol) {
227
                $codes = $this->getSprite($x, $y);
228
                $newSymbol = $this->pattern($codes);
229
                if ($newSymbol) {
230
                    $this->renderMap[$y][$x] = $newSymbol;
231
                }
232
            }
233
        }
234
    }
235
236
    private function getSprite(int $x, int $y): string
237
    {
238
        $codes = [
239
            isset($this->cachedRenderMap[$y - 1][$x]) ? $this->cachedRenderMap[$y - 1][$x]->getAlias() : '0',
240
            isset($this->cachedRenderMap[$y][$x - 1]) ? $this->cachedRenderMap[$y][$x - 1]->getAlias() : '0',
241
            isset($this->cachedRenderMap[$y][$x]) ? $this->cachedRenderMap[$y][$x]->getAlias() : '0',
242
            isset($this->cachedRenderMap[$y][$x + 1]) ? $this->cachedRenderMap[$y][$x + 1]->getAlias() : '0',
243
            isset($this->cachedRenderMap[$y + 1][$x]) ? $this->cachedRenderMap[$y + 1][$x]->getAlias() : '0',
244
        ];
245
        return implode("", $codes);
246
    }
247
248
    private function pattern(string $codes): object|bool
249
    {
250
        switch ($codes) {
251
            case '00|-|':
252
            case '00--|':
253
                return $this->gc('cornerLeftTop');
254
            case '0-|0|':
255
            case '0--0|':
256
                return $this->gc('cornerRightTop');
257
            case '|0|-|':
258
            case '|0|-z':
259
                return $this->gc('cornerLeftMiddle');
260
            case '|-|0|':
261
            case '|-|0c':
262
                return $this->gc('cornerRightMiddle');
263
            case '|-|00':
264
                return $this->gc('cornerRightBottom');
265
            case '|0|-0':
266
                return $this->gc('cornerLeftBottom');
267
            case '0---|':
268
            case '0-|-|':
269
            case '0-e-|':
270
                return $this->gc('cornerMiddleTop');
271
            case '|---0':
272
            case '--|-0':
273
            case '|-c-0':
274
                return $this->gc('cornerMiddleBottom');
275
            case '|-|-|':
276
            case '|-c-|':
277
            case '|-q-|':
278
            case '|-x-|':
279
                return $this->gc('cornerMiddleMiddle');
280
        }
281
        return false;
282
    }
283
284
285
286
}
287