RFC2550::convertPositiveTo()   B
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 3
nop 1
dl 0
loc 26
rs 8.5806
c 0
b 0
f 0
1
<?php
2
3
namespace Popy\Calendar\Formatter\NumberConverter;
4
5
use Popy\Calendar\Formatter\NumberConverterInterface;
6
7
/**
8
 * Converts years for RFC2550 Implementation.
9
 *
10
 * @link https://tools.ietf.org/html/rfc2550
11
 */
12
class RFC2550 implements NumberConverterInterface
13
{
14
    const ORD_START = 65;
15
    const POSITIVE_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^';
16
    const NEGATIVE_CHARS = '9876543210ZYXWVUTSRQPONMLKJIHGFEDCBA!';
17
18
    /**
19
     * @inheritDoc
20
     */
21
    public function to($input)
22
    {
23
        $input = (string)$input;
24
25
        if ($input[0] === '-' || preg_match('/^0+$/', $input)) {
26
            return $this->convertNegativeTo($input);
27
        }
28
29
        return $this->convertPositiveTo($input);
30
    }
31
32
    /**
33
     * Convert a positive value into its RFC2550 representation.
34
     *
35
     * @param string $input Value (as a string)
36
     *
37
     * @return string
38
     */
39
    protected function convertPositiveTo($input)
40
    {
41
        $extraLen = strlen($input) - 5;
42
43
        if ($extraLen < 0) {
44
            return str_pad($input, 4, '0', STR_PAD_LEFT);
45
        }
46
47
        if ($extraLen < 26) {
48
            return chr(static::ORD_START + $extraLen) . $input;
49
        }
50
51
        $extraLen -= 25;
52
53
        $prefix = '';
54
        $carets = '';
55
56
        do {
57
            $carets .= '^';
58
            $extraLen--;
59
60
            $prefix = chr(static::ORD_START + $extraLen % 26) . $prefix;
61
            $extraLen = intval($extraLen / 26);
62
        } while ($extraLen);
63
64
        return "${carets}${prefix}${input}";
65
    }
66
67
    /**
68
     * Converts a negative value into its RFC2550 representation.
69
     *
70
     * @param string $input Value (as a string)
71
     *
72
     * @return string
73
     */
74
    protected function convertNegativeTo($input)
75
    {
76
        $res = $this->convertPositiveTo(substr($input, 1));
77
78
        $res = strtr($res, static::POSITIVE_CHARS, static::NEGATIVE_CHARS);
79
80
        if (strlen($res) < 5) {
81
            $res = '/' . $res;
82
        } elseif ($res[0] !== '!') {
83
            $res = '*' . $res;
84
        }
85
86
        return $res;
87
    }
88
89
    /**
90
     * @inheritDoc
91
     */
92
    public function from($input)
93
    {
94
        if (strpos('!/*', $input[0]) !== false) {
95
            return $this->convertFromNegative($input);
96
        }
97
98
        return $this->convertFromPositive($input);
99
    }
100
101
    /**
102
     * Convert a positive representation.
103
     *
104
     * @param string $input
105
     *
106
     * @return string|null
107
     */
108
    public function convertFromPositive($input)
109
    {
110
        $matches = [];
111
112
        if (
113
            !preg_match(
114
                '
115
                /^0*(?<carets>\\^*)(?<alpha>[A-Z]*)(?<year>\d+)$/',
116
                $input,
117
                $matches
118
            )
119
        ) {
120
            return null;
121
        }
122
123
        if ($matches['alpha'] === '') {
124
            return $matches['year'];
125
        }
126
127
        if ($matches['carets'] === '') {
128
            $expectedLength = ord($matches['alpha']) - static::ORD_START + 5;
129
        } else {
130
            $len = strlen($matches['carets']);
131
132
            $expectedLength = 0;
133
134
            for ($i=0; $i < $len; $i++) {
135
                $expectedLength = $expectedLength * 26;
136
                $expectedLength += ord($matches['alpha'][$i]) - static::ORD_START;
137
                $expectedLength++;
138
            }
139
140
            $expectedLength += 30;
141
        }
142
143
        return str_pad($matches['year'], $expectedLength, '0', STR_PAD_RIGHT);
144
    }
145
146
    /**
147
     * Convert a negative representation.
148
     *
149
     * @param string $input
150
     *
151
     * @return string|null
152
     */
153
    public function convertFromNegative($input)
154
    {
155
        if (strpos('/*', $input[0]) !== false) {
156
            $input = substr($input, 1);
157
        }
158
159
        $input = strtr($input, static::NEGATIVE_CHARS, static::POSITIVE_CHARS);
160
161
        $res = $this->convertFromPositive($input);
162
163
        if (preg_match('/^0+$/', $res)) {
164
            return $res;
165
        }
166
167
        return '-' . $res;
168
    }
169
}
170