Completed
Push — master ( 605ec5...e9cc16 )
by Vitaly
02:18
created

Structure   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 94.87%

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 2
dl 0
loc 146
ccs 37
cts 39
cp 0.9487
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 4
B compare() 0 29 5
B getCommonPrefix() 0 26 3
A getShortestStructure() 0 4 2
A isStringNotMatchingAnyCG() 0 4 2
A getString() 0 4 1
1
<?php declare(strict_types=1);
2
/**
3
 * Created by Vitaly Iegorov <[email protected]>.
4
 * on 06.04.17 at 07:30
5
 */
6
namespace samsonframework\stringconditiontree\string;
7
8
use samsonframework\stringconditiontree\AbstractIterable;
9
10
/**
11
 * This class describes string character group structure(CGS).
12
 *
13
 * @author Vitaly Egorov <[email protected]>
14
 */
15
class Structure extends AbstractIterable
16
{
17
    /** array Supported character group types */
18
    const CG_TYPES = [
19
        FixedVariableCG::class,
20
        VariableFixedCG::class,
21
        VariableCG::class,
22
        FixedCG::class,
23
    ];
24
25
    /** @var AbstractCG[] */
26
    public $groups = [];
27
28
    /** @var string Input string */
29
    public $string;
30
31
    /**
32
     * Create string character group structure from string string.
33
     *
34
     * @param string $input Input string for string character group structure
35
     */
36 21
    public function __construct(string $input)
37
    {
38 21
        $this->string = $input;
39
40 21
        parent::__construct('groups');
41
42
        // Iterate until string is cleared
43 21
        while (strlen($input)) {
44 21
            foreach (self::CG_TYPES as $characterGroupType) {
45
                // Try to create character group
46 21
                if (($group = $characterGroupType::fromString($input)) !== null) {
47 21
                    $this->groups[] = $group;
48
                    // Reset CG type iterator to preserve order
49 21
                    break;
50
                }
51
            }
52
        }
53 21
    }
54
55
    /**
56
     * Compare structure character groups.
57
     *
58
     * @param Structure $structure Compared string structure group
59
     *
60
     * @return int Comparison result
61
     */
62 18
    public function compare(Structure $structure): int
63
    {
64 18
        $initialStructureSize = count($this->groups);
65 18
        $comparedStructureSize = count($structure->groups);
66 18
        $maxSize = max($initialStructureSize, $comparedStructureSize);
67
68 18
        if ($initialStructureSize === 0) {
69
            return -1;
70
        }
71
72 18
        if ($comparedStructureSize === 0) {
73
            return 1;
74
        }
75
76
        // Iterate maximum sized structure
77 18
        for ($index = 0; $index < $maxSize; $index++) {
78
            // Get compared/initial group or last compared character group is size mismatches
79 18
            $comparedGroup = $structure->groups[$index] ?? $structure->groups[$comparedStructureSize - 1];
80 18
            $initialGroup = $this->groups[$index] ?? $this->groups[$initialStructureSize - 1];
81
82
            // Define if character group with higher priority
83 18
            if (($return = $initialGroup->compare($comparedGroup)) !== 0) {
84 16
                return $return;
85
            }
86
        }
87
88
        // Structures are equal
89 3
        return 0;
90
    }
91
92
    /**
93
     * Get longest common prefix between strings.
94
     *
95
     * @param Structure $compared Compared character group structure
96
     *
97
     * @return string Strings Longest common prefix or empty string
98
     *
99
     */
100 3
    public function getCommonPrefix(Structure $compared)
101
    {
102 3
        $longestPrefix = '';
103
104
        /** @var AbstractCG $group Iterate longest structure character groups */
105 3
        foreach ($this->getShortestStructure($compared) as $index => $group) {
106 3
            $initialGroup = $this->groups[$index];
107 3
            $comparedGroup = $compared->groups[$index];
108
109
            // Get longest matching prefix between character groups.
110 3
            $prefix = $initialGroup->getCommonPrefix($comparedGroup);
111
112
            // Concatenate common prefix
113 3
            $longestPrefix .= $prefix;
114
115
            /**
116
             * If returned prefix is not equal to initial/compared character groups then it means
117
             * that it is shorter and we need to stop searching.
118
             */
119 3
            if ($this->isStringNotMatchingAnyCG($prefix, $initialGroup, $comparedGroup)) {
120 3
                break;
121
            }
122
        }
123
124 3
        return $longestPrefix;
125
    }
126
127
    /**
128
     * Define shortest structure.
129
     *
130
     * @param Structure $compared Structure to compare
131
     *
132
     * @return Structure Shortest structure
133
     */
134 3
    private function getShortestStructure(Structure $compared): Structure
135
    {
136 3
        return $this->count() < $compared->count() ? $this : $compared;
137
    }
138
139
    /**
140
     * Define if string does not match any of the passed character groups.
141
     *
142
     * @param string     $string String for comparison
143
     * @param AbstractCG $initialGroup Initial character group
144
     * @param AbstractCG $comparedGroup Compared character group
145
     *
146
     * @return bool True if string not matching any of character groups
147
     */
148 3
    private function isStringNotMatchingAnyCG(string $string, AbstractCG $initialGroup, AbstractCG $comparedGroup): bool
149
    {
150 3
        return $string !== $initialGroup->getString() || $string !== $comparedGroup->getString();
151
    }
152
153
    /**
154
     * @return string Structure input string
155
     */
156 2
    public function getString(): string
157
    {
158 2
        return $this->string;
159
    }
160
}
161