1 package org.musicontroller.core;
2
3 import java.util.Collection;
4 import java.util.LinkedList;
5 import java.util.List;
6 import java.util.Set;
7 import java.util.TreeSet;
8
9
10
11
12
13
14 public class Keyword extends LinkableAbs implements Comparable<Keyword> {
15 private Keyword _parent;
16 private Set<Keyword> _children;
17
18
19 public static final int _maxSimilarityPower = 7;
20 public static final int _maxSimilarity = 1<<_maxSimilarityPower;
21
22 public Keyword() {
23 _parent = null;
24 _children = null;
25 }
26
27
28
29
30
31
32
33 public static Keyword construct(String name) {
34 Keyword me = new Keyword();
35 me.setName(name);
36 return me;
37 }
38
39
40
41
42
43
44
45 public static Keyword construct(String name, Keyword parent) {
46 Keyword me = new Keyword();
47 me.setName(name);
48 try {
49 me.setParent(parent);
50 } catch (KeywordCycleException e) {
51
52 }
53 return me;
54 }
55
56 public Keyword getParent() {
57 return _parent;
58 }
59
60 public void setParent(Keyword parent) throws KeywordCycleException {
61 if(parent!=null && parent.isChildOf(this)) {
62 throw new KeywordCycleException();
63 }
64 this._parent = parent;
65 }
66
67
68
69
70
71
72
73
74 public boolean isChildOf(Keyword other) {
75 if(other==null) {
76 return false;
77 }
78 if(this.equals(other)) {
79 return false;
80 }
81 if(this.getParent()==null) {
82 return false;
83 }
84 if(this.getParent().equals(other)) {
85 return true;
86 }
87 return this.getParent().isChildOf(other);
88 }
89
90
91
92
93
94 @Override
95 public boolean equals(Object obj) {
96 if (this==obj) {
97 return true;
98 }
99 if (obj instanceof Keyword) {
100 Keyword other = (Keyword) obj;
101 boolean result = this.getName().equalsIgnoreCase(other.getName()) &&
102 (
103 (this.getParent()==null && other.getParent()==null)
104 || (this.getParent() != null && (this.getParent().equals(other.getParent())))
105 );
106 return result;
107 } else {
108 return false;
109 }
110 }
111
112 @Override
113 public int hashCode() {
114 int result = 0;
115 if(getName()!=null) {
116 result += getName().toLowerCase().hashCode();
117 }
118 if(getParent()!=null) {
119 result = (17 * result) + getParent().hashCode();
120 }
121 return result;
122 }
123
124
125
126
127 public String toString() {
128 return this.getName();
129 }
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146 public int similarityScore(Keyword keyword,StringBuilder sbout) {
147 if(this.equals(keyword)) {
148 return 1<<_maxSimilarityPower ;
149 } else {
150 boolean commonAncestorFound = false;
151 List<Keyword> myLineage = calcLineage();
152 List<Keyword> othersLineage = keyword.calcLineage();
153 StringBuilder sb = new StringBuilder();
154 sb.append("<");
155 sb.append("kw1:");
156 sb.append(myLineage.toString());
157 sb.append(",kw2:");
158 sb.append(othersLineage.toString());
159 int generalisations = 0;
160 int specialisations = 0;
161 for (Keyword p1 : myLineage) {
162
163 specialisations = 0;
164 for (Keyword p2 : othersLineage) {
165 if (p1.equals(p2)) {
166 commonAncestorFound = true;
167 }
168 if(commonAncestorFound) {
169 break;
170 }
171 specialisations++;
172 }
173 if(commonAncestorFound) {
174 break;
175 }
176
177
178 generalisations++;
179 }
180 if(commonAncestorFound) {
181 sb.append(".G:");
182 sb.append(generalisations);
183 sb.append(",S:");
184 sb.append(specialisations);
185 sb.append("->");
186 sb.append((1 << (_maxSimilarityPower - generalisations)) - specialisations);
187 sb.append(">");
188 sbout.append(sb.toString());
189 }
190 int similarity = calculateSimilarity(commonAncestorFound,generalisations,specialisations);
191 return similarity;
192 }
193 }
194
195
196
197
198
199
200
201
202
203
204 public static int calculateSimilarity(boolean commonAncestorFound, int generalisations, int specialisations) {
205 if(!commonAncestorFound) {
206 return 0;
207 }
208 int remainingSimilarityPower = _maxSimilarityPower - generalisations;
209 int specialisationPenalty = 0;
210 if(remainingSimilarityPower<1) {
211 specialisationPenalty = 1;
212 } else {
213 specialisationPenalty = (1<< (remainingSimilarityPower-1));
214 }
215 if(remainingSimilarityPower<0) {
216 remainingSimilarityPower = 0;
217 }
218 return (1 << remainingSimilarityPower) - (specialisationPenalty * specialisations);
219 }
220
221
222
223
224
225
226
227
228
229 private List<Keyword> calcLineage() {
230 List<Keyword> l = new LinkedList<Keyword>();
231 l.add(this);
232
233 Keyword p = getParent();
234 while ((p!=null) && (this!=p)) {
235 l.add(p);
236 p = p.getParent();
237 }
238
239 return l;
240 }
241
242 public String getType() {
243 return "K";
244 }
245
246
247
248
249
250 public Set<Keyword> getChildren() {
251 return _children;
252 }
253
254
255
256
257
258
259
260
261
262 public boolean addChild(Keyword keyword) {
263 if (keyword==null) return false;
264 if (!keyword._parent.equals(this)) return false;
265
266 if (_children == null) {
267 _children = new TreeSet<Keyword>();
268 }
269 return _children.add(keyword);
270 }
271
272
273
274
275
276
277
278
279
280 public static Set<Keyword> constructHierarchy(Collection<Keyword> keywords) {
281 Set<Keyword> result = new TreeSet<Keyword>();
282
283
284
285
286
287 for (Keyword keyword : keywords) {
288 if (keyword.getParent()==null) {
289 result.add(keyword);
290 } else {
291 keyword.getParent().addChild(keyword);
292 }
293 }
294
295 return result;
296 }
297
298
299
300
301
302
303
304
305 public int getChildCount() {
306 if (_children==null) return 0;
307
308 int sum = 0;
309 for (Keyword child : _children) {
310 sum += 1 + child.getChildCount();
311 }
312 return sum;
313 }
314
315
316
317
318
319 public int compareTo(Keyword other) {
320 return getName().toLowerCase().compareTo(other.getName().toLowerCase());
321 }
322
323 }