Passed
Push — master ( e3850c...c33285 )
by Ransford
02:22
created

RangeHelper::overlapping()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 10
nc 10
nop 1
dl 0
loc 18
rs 8.8333
c 0
b 0
f 0
1
<?php
2
/**
3
 * Billing Boss
4
 *
5
 * @link      https://github.com/ranskills/billing-boss-php
6
 * @copyright Copyright (c) 2018 Ransford Ako Okpoti
7
 * @license   Refer to the LICENSE distributed with this library
8
 * @since     1.0
9
 */
10
namespace BillingBoss;
11
12
final class RangeHelper
13
{
14
    const VALIDATION_NO_RANGE_FOUND = 'NO RANGE FOUND';
15
    const VALIDATION_OK = 'OK';
16
    //todo change to overlapping range
17
    const VALIDATION_OVERLAPPING_VALUES = 'OVERLAPPING VALUES';
18
    const VALIDATION_CONFLICT = 'CONFLICT';
19
20
    public static function validate($str)
21
    {
22
        $matches = [];
23
        $numMatches = preg_match_all(sprintf('/%s/', Expr::RANGE), $str, $matches);
24
        if ($numMatches === 0) {
25
            return [self::VALIDATION_NO_RANGE_FOUND, []];
26
        }
27
28
        $numAstericks = substr_count($str, '*');
29
        if ($numAstericks > 1) {
30
            return [self::VALIDATION_CONFLICT, []];
31
        }
32
33
        $lowerLimits = $matches[1];
34
        $upperLimits = $matches[2];
0 ignored issues
show
Unused Code introduced by
The assignment to $upperLimits is dead and can be removed.
Loading history...
35
        $numRanges = count($lowerLimits);
0 ignored issues
show
Unused Code introduced by
The assignment to $numRanges is dead and can be removed.
Loading history...
36
37
        $ranges = self::getRangeLimits($str);
38
        if (count($ranges) === 0) {
39
            return [self::VALIDATION_CONFLICT, []];
40
        }
41
42
        if (self::overlapping($ranges)) {
43
            return [self::VALIDATION_OVERLAPPING_VALUES, []];
44
        }
45
        
46
        return [self::VALIDATION_OK, $ranges];
47
    }
48
49
    private static function overlapping(array $ranges)
50
    {
51
        $numRanges = count($ranges);
52
53
        for ($i = 0; $i < $numRanges; $i++) {
54
            for ($j = $i + 1; $j < $numRanges; $j++) {
55
                $inRange = self::isInRange($ranges[$i], $ranges[$j][0]) ||
56
                            self::isInRange($ranges[$i], $ranges[$j][1]) ||
57
                            self::isInRange($ranges[$j], $ranges[$i][0]) ||
58
                            self::isInRange($ranges[$j], $ranges[$i][1]);
59
60
                if ($inRange) {
61
                    return true;
62
                }
63
            }
64
        }
65
66
        return false;
67
    }
68
69
    public static function getRangeLimits($str)
70
    {
71
        $ranges = [];
72
73
        $numMatches = preg_match_all(sprintf('/%s/', Expr::RANGE), $str, $matches);
74
        if ($numMatches === 0) {
75
            return $ranges;
76
        }
77
78
        $lowerLimits = $matches[1];
79
        $upperLimits = $matches[2];
80
        $len = count($lowerLimits);
81
82
        for ($i = 0; $i < $len; $i++) {
83
            if (is_numeric($upperLimits[$i]) && floatval($lowerLimits[$i]) > floatval($upperLimits[$i])) {
84
                return [];
85
            }
86
            $ranges[] = [$lowerLimits[$i], $upperLimits[$i]];
87
        }
88
89
        return $ranges;
90
    }
91
92
    public static function isInRange(array $range, $value)
93
    {
94
        if ($value === '*') {
95
            return false;
96
        }
97
 
98
        if (is_numeric($range[1])) {
99
            return $value >= $range[0] && $value <= $range[1];
100
        }
101
102
        return $value >= $range[0];
103
    }
104
}
105