Completed
Push — master ( aae2fd...925a43 )
by
unknown
06:06
created

LingoTree::findNextTerm()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30
Metric Value
dl 0
loc 25
ccs 0
cts 13
cp 0
rs 8.439
cc 5
eloc 12
nc 6
nop 3
crap 30
1
<?php
2
3
/**
4
 * File holding the Extensions\Lingo\LingoTree class
5
 *
6
 * This file is part of the MediaWiki extension Lingo.
7
 *
8
 * @copyright 2011 - 2016, Stephan Gambke
9
 * @license   GNU General Public License, version 2 (or any later version)
10
 *
11
 * The Lingo extension is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by the Free
13
 * Software Foundation; either version 2 of the License, or (at your option) any
14
 * later version.
15
 *
16
 * The Lingo extension is distributed in the hope that it will be useful, but
17
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19
 * details.
20
 *
21
 * You should have received a copy of the GNU General Public License along
22
 * with this program. If not, see <http://www.gnu.org/licenses/>.
23
 *
24
 * @author Stephan Gambke
25
 *
26
 * @file
27
 * @ingroup Lingo
28
 */
29
namespace Extensions\Lingo;
30
31
/**
32
 * The Extensions\Lingo\LingoTree class.
33
 *
34
 * Vocabulary:
35
 * Term - The term as a normal string
36
 * Definition - Its definition (any object)
37
 * Element - An element (leaf) in the glossary tree
38
 * Path - The path in the tree to the leaf representing a term
39
 *
40
 * The glossary is organized as a tree (nested arrays) where the path to the
41
 * definition of a term is the lexemes of the term followed by -1 as the end
42
 * marker.
43
 *
44
 * Example:
45
 * The path to the definition of the term "foo bar baz" would be
46
 * 'foo'.' '.'bar'.' '.'baz'.'-1'. It could thus be accessed as
47
 * $mTree['foo'][' ']['bar'][' ']['baz'][-1]
48
 *
49
 * @ingroup Lingo
50
 */
51
class LingoTree {
52
53
	private $mTree = array();
54
	private $mList = array();
55
	private $mMinLength = 1000;
56
57
	/**
58
	 * Adds a string to the Lingo Tree
59
	 * @param String $term
60
	 */
61
	public function addTerm( &$term, $definition ) {
62
		if ( !$term ) {
63
			return;
64
		}
65
66
		if ( isset( $this->mList[ $term ] ) ) { // term exists, store 2nd definition
67
			$this->mList[ $term ]->addDefinition( $definition );
68
		} else {
69
70
			$matches = array();
71
			preg_match_all( LingoParser::$regex, $term, $matches );
72
73
			$elt = $this->addElement( $matches[ 0 ], $term, $definition );
74
			$this->mList[ $term ] = &$elt[ -1 ];
75
76
			$this->mMinLength = min( array( $this->mMinLength, strlen( $term ) ) );
77
		}
78
	}
79
80
	/**
81
	 * Adds an element to the Lingo Tree
82
	 *
83
	 * @param array $path An array containing the constituing lexemes of the term
84
	 * @param String $term
85
	 * @param String $definition
86
	 * @return Array the tree node the element was stored in
87
	 */
88
	protected function &addElement( Array &$path, &$term, &$definition ) {
89
90
		$tree = &$this->mTree;
91
92
		// end of path, store description; end of recursion
93
		while ( ( $step = array_shift( $path ) ) !== null ) {
94
95
			if ( !isset( $tree[ $step ] ) ) {
96
				$tree[ $step ] = array();
97
			}
98
99
			$tree = &$tree[ $step ];
100
		}
101
102
		if ( isset( $tree[ -1 ] ) ) {
103
			$tree[ -1 ]->addDefinition( $definition );
104
		} else {
105
			$tree[ -1 ] = new LingoElement( $term, $definition );
106
		}
107
108
		return $tree;
109
	}
110
111
	public function getMinTermLength() {
112
		return $this->mMinLength;
113
	}
114
115
	public function getTermList() {
116
		return $this->mList;
117
	}
118
119
	public function findNextTerm( &$lexemes, $index, $countLexemes ) {
120
121
		$start = $lastindex = $index;
122
		$definition = null;
123
124
		// skip until the start of a term is found
125
		while ( $index < $countLexemes && !$definition ) {
126
			$currLex = &$lexemes[ $index ][ 0 ];
127
128
			// Did we find the start of a term?
129
			if ( array_key_exists( $currLex, $this->mTree ) ) {
130
				list( $lastindex, $definition ) = $this->findNextTermNoSkip( $this->mTree[ $currLex ], $lexemes, $index, $countLexemes );
131
			}
132
133
			// this will increase the index even if we found something;
134
			// will be corrected after the loop
135
			$index++;
136
		}
137
138
		if ( $definition ) {
139
			return array( $index - $start - 1, $lastindex - $index + 2, $definition );
140
		} else {
141
			return array( $index - $start, 0, null );
142
		}
143
	}
144
145
	public function findNextTermNoSkip( Array &$tree, &$lexemes, $index, $countLexemes ) {
146
147
		if ( $index + 1 < $countLexemes && array_key_exists( $currLex = $lexemes[ $index + 1 ][ 0 ], $tree ) ) {
148
			$ret = $this->findNextTermNoSkip( $tree[ $currLex ], $lexemes, $index + 1, $countLexemes );
149
		} else {
150
			$ret = array( $index, &$tree[ -1 ] );
151
		}
152
153
		return $ret;
154
	}
155
156
}
157