Structure   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 2
dl 0
loc 141
ccs 35
cts 35
cp 1
rs 10
c 0
b 0
f 0

6 Methods

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