Completed
Push — master ( b1115e...998ae3 )
by ignace nyamagana
22:33 queued 07:16
created

RomanNumber::startsWith()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 11
rs 10
1
<?php
2
3
/**
4
 * League.Period (https://period.thephpleague.com)
5
 *
6
 * (c) Ignace Nyamagana Butera <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace League\Period\Chart\Label;
15
16
use function in_array;
17
use function strtolower;
18
use function strtoupper;
19
20
final class RomanNumber implements LabelGenerator
21
{
22
    public const UPPER = 1;
23
    public const LOWER = 2;
24
    private const CHARACTER_MAP = [
25
        'M'  => 1000, 'CM' => 900,  'D' => 500,
26
        'CD' => 400,   'C' => 100, 'XC' => 90,
27
        'L'  => 50,   'XL' => 40,   'X' => 10,
28
        'IX' => 9,     'V' => 5,   'IV' => 4,
29
        'I'  => 1,
30
    ];
31
32
    /**
33
     * @var DecimalNumber
34
     */
35
    private $decimalNumber;
36
37
    /**
38
     * @var int
39
     */
40
    private $case;
41
42
    /**
43
     * New instance.
44
     */
45
    public function __construct(DecimalNumber $decimalNumber, int $case = self::UPPER)
46
    {
47
        $this->decimalNumber = $decimalNumber;
48
        $this->case = $this->filterLetterCase($case);
49
    }
50
51
    /**
52
     * filter letter case state.
53
     */
54
    private function filterLetterCase(int $case): int
55
    {
56
        if (!in_array($case, [self::UPPER, self::LOWER], true)) {
57
            return self::UPPER;
58
        }
59
60
        return $case;
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function generate(int $nbLabels): \Iterator
67
    {
68
        foreach ($this->decimalNumber->generate($nbLabels) as $key => $label) {
69
            yield $key => $this->convert($label);
70
        }
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76
    public function format(string $label): string
77
    {
78
        if (self::UPPER === $this->case) {
79
            return strtoupper($label);
80
        }
81
82
        return strtolower($label);
83
    }
84
85
    /**
86
     * Convert a integer number into its roman representation.
87
     *
88
     * @see https://stackoverflow.com/a/15023547
89
     */
90
    private function convert(string $number): string
91
    {
92
        $retVal = '';
93
        while ($number > 0) {
94
            foreach (self::CHARACTER_MAP as $roman => $int) {
95
                if ($number >= $int) {
96
                    $number -= $int;
97
                    $retVal .= $roman;
98
                    break;
99
                }
100
            }
101
        }
102
103
        if (self::LOWER === $this->case) {
104
            return strtolower($retVal);
105
        }
106
107
        return $retVal;
108
    }
109
110
    /**
111
     * Returns the starting Letter.
112
     */
113
    public function startingAt(): int
114
    {
115
        return $this->decimalNumber->startingAt();
116
    }
117
118
    /**
119
     * Tells whether the roman letter is upper cased.
120
     */
121
    public function isUpper(): bool
122
    {
123
        return self::UPPER === $this->case;
124
    }
125
126
    /**
127
     * Tells whether the roman letter is lower cased.
128
     */
129
    public function isLower(): bool
130
    {
131
        return self::LOWER === $this->case;
132
    }
133
134
    /**
135
     * Return an instance with the starting Letter.
136
     *
137
     * This method MUST retain the state of the current instance, and return
138
     * an instance that contains the starting Letter.
139
     */
140
    public function startsWith(int $int): self
141
    {
142
        $labelGenerator = $this->decimalNumber->startsWith($int);
143
        if ($labelGenerator === $this->decimalNumber) {
144
            return $this;
145
        }
146
147
        $clone = clone $this;
148
        $clone->decimalNumber = $labelGenerator;
149
150
        return $clone;
151
    }
152
153
    /**
154
     * Return an instance with the new letter case setting.
155
     *
156
     * This method MUST retain the state of the current instance, and return
157
     * an instance that contains the letter case setting.
158
     */
159
    public function withLetterCase(int $case): self
160
    {
161
        $case = $this->filterLetterCase($case);
162
        if ($case === $this->case) {
163
            return $this;
164
        }
165
166
        $clone = clone $this;
167
        $clone->case = $case;
168
169
        return $clone;
170
    }
171
}
172