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

StructureCollection::isSameStructure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 2
crap 1
1
<?php declare(strict_types=1);
2
/**
3
 * Created by Vitaly Iegorov <[email protected]>.
4
 * on 08.04.17 at 09:08
5
 */
6
namespace samsonframework\stringconditiontree\string;
7
8
use samsonframework\stringconditiontree\AbstractIterable;
9
10
/**
11
 * Class StructureCollection
12
 *
13
 * @author Vitaly Egorov <[email protected]>
14
 */
15
class StructureCollection extends AbstractIterable
16
{
17
    /** string Internal collection name */
18
    protected const COLLECTION_NAME = 'structures';
19
20
    /** @var Structure[] */
21
    protected $structures = [];
22
23
    /**
24
     * Create structures collection from array of strings.
25
     *
26
     * @param array $strings Strings array
27
     *
28
     * @return StructureCollection StructureCollection instance
29
     *
30
     * @throws \InvalidArgumentException If collection variable is missing
31
     */
32 3
    public static function fromStringsArray(array $strings): StructureCollection
33
    {
34
        // Create internalCollection
35 3
        $structureCollection = new StructureCollection();
36 3
        foreach ($strings as $string) {
37 3
            $structureCollection->structures[$string] = new Structure($string);
38
        }
39
40 3
        return $structureCollection;
41
    }
42
43
    /**
44
     * Get collection of StructureCollection instances grouped by longest common prefixes.
45
     *
46
     * @return StructureCollection[] Longest common prefixes array of StructureCollection instances
47
     */
48 2
    public function getCommonPrefixesCollection(): array
49
    {
50 2
        $this->sort();
51
52
        /** @var StructureCollection[] $commonPrefixes */
53 2
        $commonPrefixes = [];
54
55
        // Iterate sorted character group internalCollection
56 2
        foreach ($this->structures as $initialStructure) {
57 2
            $oneCommonPrefixFound = false;
58
            // Iterate all character group internalCollection again
59 2
            foreach ($this->structures as $comparedStructure) {
60
                // Ignore same internalCollection
61 2
                if ($initialStructure !== $comparedStructure) {
62 2
                    $foundPrefix = $initialStructure->getCommonPrefix($comparedStructure);
63
64
                    // If we have found common prefix between two structures
65 2
                    if ($foundPrefix !== '') {
66
                        /**
67
                         * Try to find if this prefix can be merged into already found common prefix
68
                         * as our structures collection is already sorted.
69
                         */
70 2
                        $foundPrefixStructure = new Structure($foundPrefix);
71 2
                        foreach ($commonPrefixes as $existingPrefix => $structures) {
72 2
                            $internalPrefix = (new Structure($existingPrefix))->getCommonPrefix($foundPrefixStructure);
73 2
                            if ($internalPrefix !== '') {
74 2
                                $foundPrefix = $internalPrefix;
75 2
                                break;
76
                            }
77
                        }
78
79
                        // Create new structure collection with common prefix
80 2
                        if (!array_key_exists($foundPrefix, $commonPrefixes)) {
81 2
                            $commonPrefixes[$foundPrefix] = new StructureCollection();
82
                        }
83
84 2
                        $foundInOtherCollection = false;
85 2
                        foreach ($commonPrefixes as $prefix => $collection) {
86 2
                            if ($collection->has($comparedStructure)) {
87
                                $foundInOtherCollection = true;
88
                            }
89
                        }
90
91 2
                        $newPrefix = substr($comparedStructure->getString(), strlen($foundPrefix));
92 2
                        if (!$foundInOtherCollection && strlen($newPrefix)) {
93
                            // Add structure to structure collection
94 2
                            $commonPrefixes[$foundPrefix]->addUniqueStructure(new Structure($newPrefix));
95
                        }
96
97 2
                        $oneCommonPrefixFound = true;
98
                    }
99
                }
100
            }
101
102 2
            if (!$oneCommonPrefixFound) {
103 1
                $foundPrefix = $initialStructure->getString();
104
105
                // Create new structure collection with common prefix
106 1
                if (!array_key_exists($foundPrefix, $commonPrefixes)) {
107 1
                    $commonPrefixes[$foundPrefix] = new StructureCollection();
108
                }
109
110 1
                $foundInOtherCollection = false;
111 1
                foreach ($commonPrefixes as $prefix => $collection) {
112 1
                    if ($collection->has($initialStructure)) {
113
                        $foundInOtherCollection = true;
114
                    }
115
                }
116
117 1
                $newPrefix = substr($initialStructure->getString(), strlen($foundPrefix));
118 1
                if (!$foundInOtherCollection && strlen($newPrefix)) {
119
                    // Add structure to structure collection
120
                    $commonPrefixes[$foundPrefix]->addUniqueStructure(new Structure($newPrefix));
121
                }
122
            }
123
        }
124
125 2
        return $commonPrefixes;
126
    }
127
128
    /**
129
     * Sort structures.
130
     *
131
     * @param bool $ascending Ascending sorting order
132
     *
133
     * @return array|Structure|Structure[]
134
     */
135
    protected function sort(bool $ascending = true)
136
    {
137
        // Sort internalCollection
138 2
        uasort($this->structures, function (Structure $initial, Structure $compared) {
139 2
            return $initial->compare($compared);
140 2
        });
141
142
        // Sort descending if needed
143 2
        $this->structures = $ascending ? array_reverse($this->structures) : $this->structures;
144 2
    }
145
146
    /**
147
     * @param Structure $structure
148
     *
149
     * @return bool
150
     */
151 2
    public function has(Structure $structure): bool
152
    {
153 2
        foreach ($this->structures as $comparedStructure) {
154 2
            if ($this->isSameStructure($structure, $comparedStructure)) {
155 2
                return true;
156
            }
157
        }
158
159 2
        return false;
160
    }
161
162
    /**
163
     * Compare two structures.
164
     *
165
     * @param Structure $initial Initial structure
166
     * @param Structure $compared Compared structure
167
     *
168
     * @return bool True is structures are equal
169
     */
170 2
    protected function isSameStructure(Structure $initial, Structure $compared): bool
171
    {
172 2
        return $initial->getString() === $compared->getString();
173
    }
174
175
    /**
176
     * Add only unique structure to collection.
177
     *
178
     * @param Structure $structure Added structure
179
     */
180 2
    public function addUniqueStructure(Structure $structure): void
181
    {
182 2
        if (!$this->has($structure)) {
183 2
            $this->add($structure);
184
        }
185 2
    }
186
187
    /**
188
     * Add structure to structure collection.
189
     *
190
     * @param Structure $structure Added structure
191
     */
192 2
    public function add(Structure $structure): void
193
    {
194 2
        $this->structures[$structure->getString()] = $structure;
195 2
    }
196
}
197