Completed
Push — master ( 40005e...a996c4 )
by Vitaly
02:07
created

StructureCollection::addUniqueStructure()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 1
crap 2
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 3
    public static function fromStringsArray(array $strings): StructureCollection
31
    {
32
        // Create internalCollection
33 3
        $structureCollection = new StructureCollection();
34 3
        foreach ($strings as $string) {
35 3
            $structureCollection->structures[$string] = new Structure($string);
36
        }
37
38 3
        return $structureCollection;
39
    }
40
41
    /**
42
     * Get collection of StructureCollection instances grouped by longest common prefixes.
43
     *
44
     * @return StructureCollection[] Longest common prefixes array of StructureCollection instances
45
     */
46 2
    public function getCommonPrefixesCollection(): array
47
    {
48 2
        $this->sort();
49
50
        /** @var StructureCollection[] $commonPrefixes */
51 2
        $commonPrefixes = [];
52
53
        /** @var Structure[] $usedStructures */
54 2
        $usedStructures = [];
55
56
        // Iterate sorted character group internalCollection
57 2
        foreach ($this->structures as $initialStructure) {
58 2
            $oneCommonPrefixFound = false;
59
            // Iterate all character group internalCollection again
60 2
            foreach ($this->structures as $comparedStructure) {
61
                // Ignore same internalCollection
62 2
                if ($initialStructure !== $comparedStructure) {
63 2
                    $foundPrefix = $initialStructure->getCommonPrefix($comparedStructure);
64
65
                    // If we have found common prefix between two structures
66 2
                    if ($foundPrefix !== '') {
67
                        /**
68
                         * Try to find if this prefix can be merged into already found common prefix
69
                         * as our structures collection is already sorted.
70
                         */
71 2
                        $foundPrefixStructure = new Structure($foundPrefix);
72 2
                        foreach ($commonPrefixes as $existingPrefix => $structures) {
73 2
                            $internalPrefix = (new Structure($existingPrefix))->getCommonPrefix($foundPrefixStructure);
74 2
                            if ($internalPrefix !== '') {
75 2
                                $foundPrefix = $internalPrefix;
76 2
                                break;
77
                            }
78
                        }
79
80 2
                        $this->addToCommonPrefixesCollection(
81
                            $commonPrefixes,
82
                            $foundPrefix,
83
                            $comparedStructure,
84
                            $usedStructures
85
                        );
86
87 2
                        $oneCommonPrefixFound = true;
88
                    }
89
                }
90
            }
91
92 2
            if (!$oneCommonPrefixFound) {
93 1
                $this->addToCommonPrefixesCollection(
94
                    $commonPrefixes,
95 1
                    $initialStructure->getString(),
96
                    $initialStructure,
97
                    $usedStructures
98
                );
99
            }
100
        }
101
102
        // Sort common prefixes
103 2
        $commonPrefixesCollection = new StructureCollection();
104 2
        foreach ($commonPrefixes as $prefix => $structures) {
105 2
            $commonPrefixesCollection->add(new Structure($prefix));
106
        }
107 2
        $commonPrefixesCollection->sort();
108
109 2
        $final = [];
110 2
        foreach ($commonPrefixesCollection as $prefix => $structureCollection) {
111 2
            $final[$prefix] = $commonPrefixes[$prefix];
112
        }
113
114 2
        return $final;
115
    }
116
117
    /**
118
     * Sort structures.
119
     *
120
     * @param bool $ascending Ascending sorting order
121
     */
122
    protected function sort(bool $ascending = true): void
123
    {
124
        // Sort internalCollection
125 2
        uasort($this->structures, function (Structure $initial, Structure $compared) {
126 2
            return $initial->compare($compared);
127 2
        });
128
129
        // Sort descending if needed
130 2
        $this->structures = $ascending ? array_reverse($this->structures) : $this->structures;
131 2
    }
132
133 2
    private function addToCommonPrefixesCollection(
134
        array &$commonPrefixes,
135
        string $foundPrefix,
136
        Structure $comparedStructure,
137
        array &$usedStructures
138
    ): void {
139
        // Create new structure collection with common prefix
140 2
        if (!array_key_exists($foundPrefix, $commonPrefixes)) {
141 2
            $commonPrefixes[$foundPrefix] = new StructureCollection();
142
        }
143
144 2
        $newPrefix = substr($comparedStructure->getString(), strlen($foundPrefix));
145 2
        if ($newPrefix !== '' && !in_array($comparedStructure, $usedStructures, false)) {
146 2
            $usedStructures[] = $comparedStructure;
147
            // Add structure to structure collection
148 2
            $commonPrefixes[$foundPrefix]->add(new Structure($newPrefix));
149
        }
150 2
    }
151
152
    /**
153
     * Add structure to structure collection.
154
     *
155
     * @param Structure $structure Added structure
156
     */
157 2
    public function add(Structure $structure): void
158
    {
159 2
        $this->structures[$structure->getString()] = $structure;
160 2
    }
161
162
    /**
163
     * @param Structure $structure
164
     *
165
     * @return bool
166
     */
167
    public function has(Structure $structure): bool
168
    {
169
        return in_array($structure, $this->structures);
170
    }
171
}
172