Passed
Push — master ( 05d583...7eb4ad )
by Karthik
06:02
created

ItemOption::generate()   B

Complexity

Conditions 10
Paths 64

Size

Total Lines 43
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 10.0082

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 24
c 1
b 0
f 0
nc 64
nop 1
dl 0
loc 43
ccs 22
cts 23
cp 0.9565
crap 10.0082
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace cyberinferno\Cabal\Helpers;
4
5
use cyberinferno\Cabal\Helpers\Exceptions\InvalidCraftLevelException;
6
use cyberinferno\Cabal\Helpers\Exceptions\InvalidOptionException;
7
use cyberinferno\Cabal\Helpers\Exceptions\MaxOptionException;
8
use cyberinferno\Cabal\Helpers\Exceptions\OptionLimitException;
9
10
/**
11
 * Class ItemOption
12
 *
13
 * Contains methods helpful to generate item option
14
 *
15
 * @package cyberinferno\Cabal\Helpers
16
 * @author Karthik P
17
 */
18
class ItemOption
19
{
20
    const MAX_OPTIONS = 4;
21
22
    const MIN_SLOTS = 0;
23
    const MAX_SLOTS = 4;
24
25
    const MIN_CRAFTS = 0;
26
    const MAX_CRAFTS = 3;
27
28
    const OUTPUT_FORMAT_INTEGER = 'int';
29
    const OUTPUT_FORMAT_HEXADECIMAL = 'hex';
30
31
    /**
32
     * @var int Max number of slots the generated item option will have
33
     */
34
    protected $_slots;
35
    /**
36
     * @var array
37
     */
38
    protected $_slotOptions = [];
39
    /**
40
     * @var int Max number of crafts the generated item option will have
41
     */
42
    protected $_crafts;
43
    /**
44
     * @var array
45
     */
46
    protected $_craftOptions = [];
47
    /**
48
     * @var array
49
     */
50
    protected $_availableCraftLevels = ['9', 'A', 'B', 'C', 'D', 'E', 'F'];
51
    /**
52
     * @var array
53
     */
54
    protected $_availableOptions = [
55
        '1', '2', '3', '4', '5',
56
        '6', '7', '8', '9', 'A',
57
        'B', 'C', 'D', 'E', 'F'
58
    ];
59
60
    /**
61
     * ItemOption constructor.
62
     * @param int $slots
63
     * @param int $crafts
64
     * @throws \cyberinferno\Cabal\Helpers\Exceptions\MaxOptionException
65
     */
66 54
    public function __construct($slots = 0, $crafts = 0)
67
    {
68 54
        if ($slots < self::MIN_SLOTS) {
69 3
            $slots = self::MIN_SLOTS;
70
        }
71 54
        if ($slots > self::MAX_SLOTS) {
72 3
            $slots = self::MAX_SLOTS;
73
        }
74 54
        if ($crafts < self::MIN_CRAFTS) {
75 3
            $crafts = self::MIN_CRAFTS;
76
        }
77 54
        if ($crafts > self::MAX_CRAFTS) {
78 3
            $crafts = self::MAX_CRAFTS;
79
        }
80 54
        if ($slots + $crafts > self::MAX_OPTIONS) {
81 3
            throw new MaxOptionException('Maximum number of options cannot exceed ' . self::MAX_OPTIONS);
82
        }
83 51
        $this->_slots = $slots;
84 51
        $this->_crafts = $crafts;
85 51
    }
86
87
    /**
88
     * Returns the number of slots in the option
89
     *
90
     * @return int
91
     */
92 9
    public function getSlots()
93
    {
94 9
        return $this->_slots;
95
    }
96
97
    /**
98
     * Returns the number of crafts in the option
99
     *
100
     * @return int
101
     */
102 9
    public function getCrafts()
103
    {
104 9
        return $this->_crafts;
105
    }
106
107
    /**
108
     * Returns slot options
109
     *
110
     * @return array
111
     */
112 6
    public function getSlotOptions()
113
    {
114 6
        return $this->_slotOptions;
115
    }
116
117
    /**
118
     * Sets a slot option
119
     *
120
     * @param string $option
121
     * @return ItemOption
122
     * @throws InvalidOptionException
123
     * @throws OptionLimitException
124
     */
125 12
    public function setSlotOption($option)
126
    {
127 12
        if (!in_array(strval($option), $this->_availableOptions)) {
128 3
            throw new InvalidOptionException();
129
        }
130 9
        if (count($this->_slotOptions) == $this->_slots) {
131 3
            throw new OptionLimitException('Slot option cannot exceed ' . $this->_slots);
132
        }
133 9
        $this->_slotOptions[] = ['option' => (string)$option];
134 9
        return $this;
135
    }
136
137
    /**
138
     * Returns craft options
139
     *
140
     * @return array
141
     */
142 6
    public function getCraftOptions()
143
    {
144 6
        return $this->_craftOptions;
145
    }
146
147
    /**
148
     * Sets a craft option
149
     *
150
     * @param string $craftLevel
151
     * @param string $option
152
     * @return ItemOption
153
     * @throws InvalidCraftLevelException
154
     * @throws InvalidOptionException
155
     * @throws OptionLimitException
156
     */
157 15
    public function setCraftOption($craftLevel, $option)
158
    {
159 15
        if (!in_array(strval($craftLevel), $this->_availableCraftLevels)) {
160 3
            throw new InvalidCraftLevelException();
161
        }
162 12
        if (!in_array(strval($option), $this->_availableOptions)) {
163 3
            throw new InvalidOptionException();
164
        }
165 9
        if (count($this->_craftOptions) == $this->_crafts) {
166 3
            throw new OptionLimitException('Craft option cannot exceed ' . $this->_crafts);
167
        }
168 9
        $this->_craftOptions[] = [
169 9
            'craftLevel' => (string)$craftLevel,
170 9
            'option' => (string)$option
171
        ];
172 9
        return $this;
173
    }
174
175
    /**
176
     * Returns the generated item option based upon the criteria set
177
     *
178
     * @param string $format
179
     * @return string|int
180
     */
181 3
    public function generate($format = self::OUTPUT_FORMAT_INTEGER)
182
    {
183 3
        $optionString = '';
184 3
        $slotsToFillArray = [];
185
        // Craft options should be at the end of the hex string hence we start prepending all craft options to output
186 3
        foreach ($this->_craftOptions as $craftOption) {
187 3
            $optionString = $craftOption['craftLevel'] . $craftOption['option'] . $optionString;
188
        }
189
        // We calculate slots to fill based upon slot options
190 3
        foreach ($this->_slotOptions as $slotOption) {
191 3
            if (isset($slotsToFillArray[$slotOption['option']])) {
192
                // Item cannot have 4 set of same options
193 3
                if ($slotsToFillArray[$slotOption['option']] == 3) {
194 3
                    continue;
195
                }
196 3
                $slotsToFillArray[$slotOption['option']]++;
197
            } else {
198 3
                $slotsToFillArray[$slotOption['option']] = 1;
199
            }
200
        }
201
        // Sorting slots to fill array to make sure multiple slot options stay in the end
202 3
        arsort($slotsToFillArray, SORT_NUMERIC);
203
        // Build the output with slot options
204 3
        foreach ($slotsToFillArray as $option => $fill) {
205 3
            if (strlen($optionString) == 7) {
206
                // Means we prematurely reached the end due to wrong options being set hence go out of the loop
207
                break;
208
            }
209 3
            if (strlen($optionString) == 6) {
210
                // Ignore slots to fill value
211 3
                $optionString = $option . $optionString;
212
            } else {
213 3
                $optionString = $fill . $option . $optionString;
214
            }
215
        }
216 3
        if (strlen($optionString) < 7) {
217
            // Fill the output with 0s if there are empty slots
218 3
            $optionString = str_repeat('0', 7 - strlen($optionString)) . $optionString;
219
        }
220 3
        if ($format != self::OUTPUT_FORMAT_INTEGER) {
221 3
            return $this->_slots . $optionString;
222
        }
223 3
        return hexdec($this->_slots . $optionString);
224
    }
225
226
    /**
227
     * Extracts item options from generated item option
228
     *
229
     * @param int|string $generatedItemOption
230
     * @return array
231
     */
232 3
    public static function extract($generatedItemOption)
233
    {
234 3
        if (is_int($generatedItemOption)) {
235 3
            $generatedItemOption = dechex($generatedItemOption);
236
        }
237 3
        if (strlen($generatedItemOption) < 8) {
238 3
            $generatedItemOption = str_repeat('0', 8 - strlen($generatedItemOption)) . $generatedItemOption;
239
        }
240 3
        $generatedItemOption = strtoupper($generatedItemOption);
241 3
        if (hexdec($generatedItemOption) > hexdec('4FFFFFFF')) {
242
            // Invalid generated option hence return default values
243
            return [
244
                'slots' => 0,
245
                'crafts' => 0,
246
                'slotOptions' => [],
247
                'craftOptions' => []
248
            ];
249
        }
250 3
        $craftOptions = [];
251 3
        $slotOptions = [];
252
        // Extract last 3 options
253 3
        for ($i = 1; $i <= 3; $i++) {
254 3
            $currentOption = substr($generatedItemOption, -1 * ($i * 2), 2);
255 3
            if (in_array($currentOption[0], ['9', 'A', 'B', 'C', 'D', 'E', 'F'])) {
256 3
                $craftOptions[] = [
257 3
                    'craftLevel' => $currentOption[0],
258 3
                    'craftOption' => $currentOption[1]
259
                ];
260
            } else {
261 3
                for ($j = 1; $j <= (int)$currentOption[0]; $j++) {
262 3
                    if ($currentOption[1] == '0') {
263
                        continue;
264
                    }
265 3
                    $slotOptions[] = [
266 3
                        'slotOption' => $currentOption[1]
267
                    ];
268
                }
269
            }
270
        }
271 3
        if ($generatedItemOption[1] != '0') {
272
            $slotOptions[] = [
273
                'slotOption' => $generatedItemOption[1]
274
            ];
275
        }
276
        return [
277 3
            'slots' => (int)$generatedItemOption[0],
278 3
            'crafts' => count($craftOptions),
279 3
            'slotOptions' => $slotOptions,
280 3
            'craftOptions' => $craftOptions
281
        ];
282
    }
283
}