1   package ixa.kaflib;
2   
3   import java.io.Serializable;
4   import java.util.*;
5   
6   
7   /** Class for representing terms. Terms refer to previous word forms (and groups multi-words) and attach lemma, part of speech, synset and name entity information. */
8   public class Term extends IReferable implements Serializable {
9   
10  	@Override
11  	public String toString() {
12  		return toString(true);
13  	}
14  
15  	public String toString(boolean trimmed) {
16  		if (trimmed) {
17  			return getForm().trim();
18  		}
19  		else {
20  			return getForm();
21  		}
22  	}
23  
24  	/** Term's ID (required) */
25      private String tid;
26  
27      /** Type of the term (optional). Currently, 2 values are possible: open and close. */
28      private String type;
29  
30      /** Lemma of the term (optional) */
31      private String lemma;
32  
33      /** Part of speech (optional). Possible values are:
34       * - common noun (N)
35       * - proper noun (R)
36       * - adjective (G)
37       * - verb (V)
38       * - preposition (P)
39       * - adverb (A)
40       * - conjunction (C)
41       * - determiner (D)
42       * - other (O)
43       **/
44      private String pos;
45  
46      /** Morphosyntactic feature encoded as a single attribute (optional) */
47      private String morphofeat;
48  
49      /** Declension case of the term (optional) */
50      private String termcase;
51  
52      /** Sentiment features (optional) */
53      private Sentiment sentiment;
54  
55      /** If it's a compound term, it's components (optional) */
56      private List<Term> components;
57  
58      /** Head component (optional) */
59      private Term head;
60  
61      /** Target elements are used to refer to the target word. If the term is a multiword, multiple target elements are used. (required)*/
62      private Span<WF> span;
63  
64      /** ExternalReferences are used to associate terms to external lexical or semantic resources, such as elements of a Knowledge base: semantic lexicon  (like WordNet) or an ontology (optional) */
65      private List<ExternalRef> externalReferences;
66  
67      private boolean isComponent;
68      private Term compound; // Parent compound term of this component
69  
70  	private String supersenseTag;
71  	private String wordnetSense;
72  	private String bbnTag;
73  	private String upos;
74  	private Map<String, Collection<String>> features = null;
75  
76  	public Map<String, Collection<String>> getFeatures() {
77  		return features;
78  	}
79  
80  	public void setFeatures(Map<String, Collection<String>> features) {
81  		this.features = features;
82  	}
83  
84  	public boolean hasFeatures() {
85  		return features != null;
86  	}
87  
88  	public String getUpos() {
89  		return upos;
90  	}
91  
92  	public void setUpos(String upos) {
93  		this.upos = upos;
94  	}
95  
96  	public boolean hasUpos() {
97  		return upos != null;
98  	}
99  
100 	public String getSupersenseTag() {
101 		return supersenseTag;
102 	}
103 
104 	public void setSupersenseTag(String supersenseTag) {
105 		this.supersenseTag = supersenseTag;
106 	}
107 
108 	public boolean hasSupersenseTag() {
109 		return supersenseTag != null;
110 	}
111 
112 	public void setWordnetSense(String wordnetSense) {
113 		this.wordnetSense = wordnetSense;
114 	}
115 
116 	public String getWordnetSense() {
117 		return wordnetSense;
118 	}
119 
120 	public boolean hasWordnetSense() {
121 		return wordnetSense != null;
122 	}
123 
124 	public String getBBNTag() {
125 	    return this.bbnTag;
126 	}
127 
128     public void setBBNTag(String bbnTag) {
129 	    this.bbnTag = bbnTag;
130     }
131 
132     public boolean hasBBNTag() {
133         return bbnTag != null;
134 	}
135 
136 	/** The term layer represents sentiment information which is context-independent and that can be found in a sentiment lexicon.
137      * It is related to concepts expressed by words/ terms (e.g. beautiful) or multi-word expressions (e. g. out of order).
138      * We provide possibilities to store sentiment information at word level and at sense/synset level. In the latter case, the sentiment information
139      * is included in the “external_reference” section and a WSD process may identify the correct sense with its sentiment information. The extension contains the following information categories.
140      */
141     public static class Sentiment implements Serializable {
142 
143 	/** Identifier and reference to an external sentiment resource (optional) */
144 	private String resource;
145 
146 	/** Refers to the property of a word to express positive, negative or no sentiment (optional). These values are possible:
147 	 * - Positive
148 	 * - Negative
149 	 * - Neutral
150 	 * - Or numerical value on a numerical scale
151 	 */
152 	private String polarity;
153 
154 	/** Refers to the strength of the polarity (optional). These values are possible:
155 	 * - Weak
156 	 * - Average
157 	 * - Strong
158 	 * - Or Numerical value
159 	 */
160 	private String strength;
161 
162 	/** Refers to the property of a words to express an opionion (or not) (optional).
163 	 * - Subjective/Objective
164 	 * - Factual/opinionated
165 	 */
166 	private String subjectivity;
167 
168 	/** Refers to a sentiment-related semantic type (optional):
169 	 * - Aesthetics_evaluation
170 	 * - Moral_judgment
171 	 * - Emotion
172 	 * - etc
173 	 */
174 	private String sentimentSemanticType;
175 
176 	/** Refers to words which modify the polarity of another word (optional):
177 	 * - Intensifier/weakener polarity shifter
178 	 */
179 	private String sentimentModifier;
180 
181 	/** Refers to words which themselves do not carry polarity, but are kind of vehicles of it (optional):
182 	 * - Find, think, in my opinion, according to...
183 	 */
184 	private String sentimentMarker;
185 
186 	/** Refers to a domain; mainly used in feature-based sentiment analysis (optional):
187 	 * - Values are related to specific domain. For the tourist domain, for example, staff, cleanliness, beds, bathroom, transportation, location, etc...
188 	 */
189 	private String sentimentProductFeature;
190 
191 	Sentiment() {
192 	}
193 
194 	Sentiment(Sentiment sentiment) {
195 	    this.resource = sentiment.resource;
196 	    this.polarity = sentiment.polarity;
197 	    this.strength = sentiment.strength;
198 	    this.subjectivity = sentiment.subjectivity;
199 	    this.sentimentSemanticType = sentiment.sentimentSemanticType;
200 	    this.sentimentModifier = sentiment.sentimentModifier;
201 	    this.sentimentMarker = sentiment.sentimentMarker;
202 	    this.sentimentProductFeature = sentiment.sentimentProductFeature;
203 	}
204 
205 	public boolean hasResource() {
206 	    return resource != null;
207 	}
208 
209 	public String getResource() {
210 	    return resource;
211 	}
212 
213 	public void setResource(String val) {
214 	    resource = val;
215 	}
216 
217 	public boolean hasPolarity() {
218 	    return polarity != null;
219 	}
220 
221 	public String getPolarity() {
222 	    return polarity;
223 	}
224 
225 	public void setPolarity(String val) {
226 	    polarity = val;
227 	}
228 
229 	public boolean hasStrength() {
230 	    return strength != null;
231 	}
232 
233 	public String getStrength() {
234 	    return strength;
235 	}
236 
237 	public void setStrength(String val) {
238 	    strength = val;
239 	}
240 
241 	public boolean hasSubjectivity() {
242 	    return subjectivity != null;
243 	}
244 
245 	public String getSubjectivity() {
246 	    return subjectivity;
247 	}
248 
249 	public void setSubjectivity(String val) {
250 	    subjectivity = val;
251 	}
252 
253 	public boolean hasSentimentSemanticType() {
254 	    return sentimentSemanticType != null;
255 	}
256 
257 	public String getSentimentSemanticType() {
258 	    return sentimentSemanticType;
259 	}
260 
261 	public void setSentimentSemanticType(String val) {
262 	    sentimentSemanticType = val;
263 	}
264 
265 	public boolean hasSentimentModifier() {
266 	    return sentimentModifier != null;
267 	}
268 
269 	public String getSentimentModifier() {
270 	    return sentimentModifier;
271 	}
272 
273 	public void setSentimentModifier(String val) {
274 	    sentimentModifier = val;
275 	}
276 
277 	public boolean hasSentimentMarker() {
278 	    return sentimentMarker != null;
279 	}
280 
281 	public String getSentimentMarker() {
282 	    return sentimentMarker;
283 	}
284 
285 	public void setSentimentMarker(String val) {
286 	    sentimentMarker = val;
287 	}
288 
289 	public boolean hasSentimentProductFeature() {
290 	    return sentimentProductFeature != null;
291 	}
292 
293 	public String getSentimentProductFeature() {
294 	    return sentimentProductFeature;
295 	}
296 
297 	public void setSentimentProductFeature(String val) {
298 	    sentimentProductFeature = val;
299 	}
300     }
301 
302     Term(String id, Span<WF> span, boolean isComponent) {
303 	/*
304 	if (span.size() < 1) {
305 	    throw new IllegalStateException("A Term must have at least one WF");
306 	}
307 	*/
308 	this.tid = id;
309 	this.components = new ArrayList();
310 	this.span = span;
311 	this.externalReferences = new ArrayList<ExternalRef>();
312 	this.isComponent = isComponent;
313     }
314 
315     /* Copy constructor */
316     Term(Term term, HashMap<String, WF> wfs) {
317 	// Copy simple fields
318 	this.tid = term.tid;
319 	this.type = term.type;
320 	this.lemma = term.lemma;
321 	this.pos = term.pos;
322 	this.morphofeat = term.morphofeat;
323 	this.termcase = term.termcase;
324 	// Copy sentiment
325 	if (term.hasSentiment()) {
326 	    this.sentiment = new Sentiment(term.sentiment);
327 	}
328 	// Copy components and head
329 	HashMap<String, Term> newComponents =
330 	    new HashMap<String, Term>();
331 	this.components = new ArrayList<Term>();
332 	for (Term component : term.components) {
333 	    Term copyComponent = new Term(component, wfs);
334 	    this.components.add(copyComponent);
335 	    newComponents.put(component.getId(), copyComponent);
336 	}
337 	if (term.hasHead()) {
338 	    this.head = newComponents.get(term.head.getId());
339 	}
340 	// Copy span
341 	List<WF> targets = term.span.getTargets();
342 	List<WF> copiedTargets = new ArrayList<WF>();
343 	for (WF wf : targets) {
344 	    WF copiedWf = wfs.get(wf.getId());
345 	    if (copiedWf == null) {
346 		throw new IllegalStateException("WF not found when copying Term " + term.getId());
347 	    }
348 	    copiedTargets.add(copiedWf);
349 	}
350 	if (term.span.hasHead()) {
351 	    WF copiedHead = wfs.get(term.span.getHead().getId());
352 	    this.span = new Span<WF>(copiedTargets, copiedHead);
353 	}
354 	else {
355 	    this.span = new Span<WF>(copiedTargets);
356 	}
357 	// Copy external references
358 	this.externalReferences = new ArrayList<ExternalRef>();
359 	for (ExternalRef externalRef : term.getExternalRefs()) {
360 	    this.externalReferences.add(new ExternalRef(externalRef));
361 	}
362     }
363 
364     public String getId() {
365 	return tid;
366     }
367 
368     void setId(String id) {
369 	this.tid = id;
370     }
371 
372     public boolean hasType() {
373 	return type != null;
374     }
375 
376     public String getType() {
377 	return type;
378     }
379 
380     public void setType(String type) {
381 	this.type = type;
382     }
383 
384     public boolean hasLemma() {
385 	return lemma != null;
386     }
387 
388     public String getLemma() {
389 	return lemma;
390     }
391 
392     public void setLemma(String lemma) {
393 	this.lemma = lemma;
394     }
395 
396     public boolean hasPos() {
397 	return pos != null;
398     }
399 
400     public String getPos() {
401 	return pos;
402     }
403 
404     public void setPos(String pos) {
405 	this.pos = pos;
406     }
407 
408     public boolean hasMorphofeat() {
409 	return morphofeat != null;
410     }
411 
412     public String getMorphofeat() {
413 	return morphofeat;
414     }
415 
416     public void setMorphofeat(String morphofeat) {
417 	this.morphofeat = morphofeat;
418     }
419 
420     public boolean hasCase() {
421 	return termcase != null;
422     }
423 
424     public String getCase() {
425 	return termcase;
426     }
427 
428     public void setCase(String termcase) {
429 	this.termcase = termcase;
430     }
431 
432     // MODIFIED BY FRANCESCO
433 
434     public String getForm() {
435         StringBuilder builder = new StringBuilder();
436         List<WF> sortedWFs = new ArrayList<WF>(span.getTargets());
437         Collections.sort(sortedWFs, WF.OFFSET_COMPARATOR);
438         int start = -1;
439         for (WF wf : sortedWFs){
440             if (start < 0) {
441                 start = wf.getOffset();
442             }
443             int index = wf.getOffset() - start;
444             if (index < builder.length()) {
445                 builder.setLength(index);
446             } else {
447                 while (builder.length() < index) {
448                     builder.append(' ');
449                 }
450             }
451             builder.append(wf.getForm());
452         }
453         return builder.toString();
454     }
455 
456    public String getStr() {
457        String strValue = this.getForm();
458        boolean valid = false;
459        while (!valid) {
460 	   if (strValue.startsWith("-") || strValue.endsWith("-")) {
461 	       strValue = strValue.replace("-", " - ");
462 	   }
463 	   else if (strValue.contains("--")) {
464 	       strValue = strValue.replace("--", "-");
465 	   }
466 	   else {
467 	       valid = true;
468 	   }
469        }
470        return strValue;
471     }
472 
473     public boolean hasHead() {
474 	return (this.head != null);
475     }
476 
477     public Term getHead() {
478         return this.head;
479     }
480 
481     /** Creates and adds a Sentiment object.
482      * @return a new sentiment.
483      */
484     public Sentiment createSentiment() {
485 	Sentiment newSentiment = new Sentiment();
486 	this.setSentiment(newSentiment);
487 	return newSentiment;
488     }
489 
490     public boolean hasSentiment() {
491 	return (this.sentiment != null);
492     }
493 
494     public Sentiment getSentiment() {
495 	return sentiment;
496     }
497 
498     public void setSentiment(Sentiment sentiment) {
499         this.sentiment = sentiment;
500     }
501 
502     public List<Term> getComponents() {
503 	return this.components;
504     }
505 
506     public void addComponent(Term component) {
507 	components.add(component);
508     }
509 
510     public void addComponent(Term component, boolean isHead) {
511 	components.add(component);
512 	if (isHead) {
513 	    this.head = component;
514 	}
515     }
516 
517     public List<WF> getWFs() {
518 	return this.span.getTargets();
519     }
520 
521     public WF getHeadWF() {
522 	return this.span.getHead();
523     }
524 
525     public void addWF(WF wf) {
526 	this.span.addTarget(wf);
527     }
528 
529     public void addWF(WF wf, boolean isHead) {
530 	this.span.addTarget(wf, isHead);
531     }
532 
533     public Span<WF> getSpan() {
534 	return this.span;
535     }
536 
537     public void setSpan(Span<WF> span) {
538 	this.span = span;
539     }
540 
541     public Integer getSent() {
542 	return this.getSpan().getTargets().get(0).getSent();
543 	/*
544 	if (!this.isComponent()) {
545 	    return this.getSpan().getTargets().get(0).getSent();
546 	} else {
547 	    return this.getCompound().getSent();
548 	}
549 	*/
550     }
551 
552     public List<ExternalRef> getExternalRefs() {
553 	return externalReferences;
554     }
555 
556     public void addExternalRef(ExternalRef externalRef) {
557 	externalReferences.add(externalRef);
558     }
559 
560     public void addExternalRefs(List<ExternalRef> externalRefs) {
561 	externalReferences.addAll(externalRefs);
562     }
563 
564     boolean isComponent() {
565 	return this.isComponent;
566     }
567 
568     public void setCompound(Term compound) {
569 	this.compound = compound;
570     }
571 
572     public Term getCompound() {
573 	return this.compound;
574     }
575 
576     // ADDED BY FRANCESCO
577 
578     public int getOffset() {
579         int offset = Integer.MAX_VALUE;
580         for (WF word : this.getWFs()) {
581             int wordOffset = word.getOffset();
582             if (wordOffset < offset) {
583                 offset = wordOffset;
584             }
585         }
586         return offset;
587     }
588 
589     public int getLength() {
590         int startOffset = Integer.MAX_VALUE;
591         int endOffset = Integer.MIN_VALUE;
592         for (WF word : this.getWFs()) {
593             int wordOffset = word.getOffset();
594 			int length = word.getLength();
595             if (wordOffset < startOffset) {
596                 startOffset = wordOffset;
597             }
598             if (wordOffset + length > endOffset) {
599                 endOffset = wordOffset + length;
600             }
601         }
602         return endOffset - startOffset;
603     }
604 
605     public static final Comparator<Term> OFFSET_COMPARATOR = new Comparator<Term>() {
606 
607         @Override
608         public int compare(Term first, Term second) {
609             return first.getOffset() - second.getOffset();
610         }
611 
612     };
613 
614 }