001    /*
002     * The contents of this file are subject to the Mozilla Public
003     * License Version 1.1 (the "License"); you may not use this file
004     * except in compliance with the License. You may obtain a copy of
005     * the License at http://www.mozilla.org/MPL/
006     *
007     * Software distributed under the License is distributed on an "AS
008     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
009     * implied. See the License for the specific language governing
010     * rights and limitations under the License.
011     *
012     * The Original Code is Knowtator.
013     *
014     * The Initial Developer of the Original Code is University of Colorado.  
015     * Copyright (C) 2005 - 2008.  All Rights Reserved.
016     *
017     * Knowtator was developed by the Center for Computational Pharmacology
018     * (http://compbio.uchcs.edu) at the University of Colorado Health 
019     *  Sciences Center School of Medicine with support from the National 
020     *  Library of Medicine.  
021     *
022     * Current information about Knowtator can be obtained at 
023     * http://knowtator.sourceforge.net/
024     *
025     * Contributor(s):
026     *   Philip V. Ogren <philip@ogren.info> (Original Author)
027     *   Angus Roberts
028     *
029     */
030    
031    /**
032     * Changes
033     * 2/8/2007   ar        fixed recursive infinite loop bug in copyMention
034     * 8/11/2005  pvo    added isComplexSlotMention, getComplexMentionSlotValues (2 versions)
035     *                   getComplexSlotMentions 
036     *                   
037     * 11/19/2005 pvo   Added copyMention() method
038     *                                      added documentation for supporting methods.
039     *                                      Refactored a few existing methods.  Mostly added code for "null" conditions and javadocs.
040     */
041    
042    package edu.uchsc.ccp.knowtator;
043    
044    import java.util.ArrayList;
045    import java.util.Collection;
046    import java.util.HashSet;
047    import java.util.List;
048    import java.util.Map;
049    import java.util.Set;
050    
051    import org.apache.log4j.Logger;
052    
053    import edu.stanford.smi.protege.model.Cls;
054    import edu.stanford.smi.protege.model.Frame;
055    import edu.stanford.smi.protege.model.Instance;
056    import edu.stanford.smi.protege.model.KnowledgeBase;
057    import edu.stanford.smi.protege.model.SimpleInstance;
058    import edu.stanford.smi.protege.model.Slot;
059    import edu.stanford.smi.protege.model.ValueType;
060    import edu.stanford.smi.protege.util.CollectionUtilities;
061    
062    public class MentionUtil {
063            KnowtatorProjectUtil kpu;
064    
065            KnowledgeBase kb;
066    
067            AnnotationUtil annotationUtil;
068    
069            Logger logger = Logger.getLogger(KnowtatorManager.class);
070    
071            /** Creates a new instance of MentionUtil */
072            public MentionUtil(KnowtatorProjectUtil kpu) {
073                    this.kpu = kpu;
074                    this.kb = kpu.kb;
075            }
076    
077            public void setAnnotationUtil(AnnotationUtil annotationUtil) {
078                    this.annotationUtil = annotationUtil;
079            }
080    
081            /*
082             * Compares two mentions to see if they are exactly the same including
083             * (recursively) the slot mention values. If the values of two slot mentions
084             * are the same but in a different order, then true is returned.
085             * 
086             * @param compareAnnotationSpans indicate whether the corresponding
087             * annotations of the mentions must have the same spans for the mentions to
088             * be considered equal.
089             */
090            public boolean equals(SimpleInstance mention1, SimpleInstance mention2, boolean compareAnnotationSpans) {
091                    // return false if either mention (or both) is null.
092                    if (mention1 == null || mention2 == null)
093                            return false;
094                    // The two mentions must be the same type
095                    if (!mention1.getDirectType().equals(mention2.getDirectType()))
096                            return false;
097    
098                    if (compareAnnotationSpans) {
099                            if (!isSlotMention(mention1) && !compareAnnotationSpans(mention1, mention2))
100                                    return false;
101                    }
102    
103                    // if both mentions are class mentions
104                    if (isClassMention(mention1) && isClassMention(mention2)) {
105                            Cls mentionedCls1 = getMentionCls(mention1);
106                            Cls mentionedCls2 = getMentionCls(mention2);
107                            if (mentionedCls1 == null && mentionedCls2 == null)
108                                    return compareSlotMentions(mention1, mention2, compareAnnotationSpans);
109                            if (mentionedCls1 == null || mentionedCls2 == null)
110                                    return false;
111                            // return false if the mentioned classes are different
112                            if (!mentionedCls1.equals(mentionedCls2))
113                                    return false;
114                            return compareSlotMentions(mention1, mention2, compareAnnotationSpans);
115                    }
116                    if (isInstanceMention(mention1) && isInstanceMention(mention2)) {
117                            Instance mentionedInstance1 = getMentionInstance(mention1);
118                            Instance mentionedInstance2 = getMentionInstance(mention2);
119                            if (mentionedInstance1 == null && mentionedInstance2 == null)
120                                    return compareSlotMentions(mention1, mention2, compareAnnotationSpans);
121                            if (mentionedInstance1 == null || mentionedInstance2 == null)
122                                    return false;
123                            // return false if the mentioned classes are different
124                            if (!mentionedInstance1.equals(mentionedInstance2))
125                                    return false;
126                            return compareSlotMentions(mention1, mention2, compareAnnotationSpans);
127                    }
128                    if (isSlotMention(mention1) && isSlotMention(mention2)) {
129                            Slot mentionedSlot1 = getSlotMentionSlot(mention1);
130                            Slot mentionedSlot2 = getSlotMentionSlot(mention2);
131                            List<Object> slotValues1 = getSlotMentionValues(mention1);
132                            List<Object> slotValues2 = getSlotMentionValues(mention2);
133    
134                            if (mentionedSlot1 == null && mentionedSlot2 == null)
135                                    return false;
136                            if (!mentionedSlot1.equals(mentionedSlot2))
137                                    return false;
138                            if (slotValues1.size() == 0 && slotValues2.size() == 0)
139                                    return true;
140                            if (slotValues1.size() != slotValues2.size())
141                                    return false;
142    
143                            // This is the only "tricky" code in the method. The values of the
144                            // two slot mentions are not
145                            // required to be in the same order. The brute force approach was
146                            // used to simplify the code and
147                            // because it is assumed that few slot mentions will have many
148                            // values (usually 1).
149                            // For each slot value of mention1 it is assumed that there is no
150                            // match until one is found from
151                            // the other list of values. If each value is matched then we can
152                            // return true.
153                            for (Object slotValue1 : slotValues1) {
154                                    boolean matchedSlotValue = false;
155                                    for (Object slotValue2 : slotValues2) {
156                                            if (compareSlotValues(slotValue1, slotValue2, compareAnnotationSpans)) {
157                                                    matchedSlotValue = true;
158                                                    break;
159                                            }
160                                    }
161                                    if (!matchedSlotValue)
162                                            return false;
163                            }
164                            return true;
165                    }
166    
167                    return false;
168            }
169    
170            private boolean compareSlotValues(Object value1, Object value2, boolean compareAnnotationSpans) {
171                    if (value1 instanceof SimpleInstance && value2 instanceof SimpleInstance) {
172                            return equals((SimpleInstance) value1, (SimpleInstance) value2, compareAnnotationSpans);
173                    } else
174                            return value1.equals(value2);
175            }
176    
177            private boolean compareSlotMentions(SimpleInstance mention1, SimpleInstance mention2, boolean compareAnnotationSpans) {
178                    List<SimpleInstance> slotMentions1 = getSlotMentions(mention1);
179                    List<SimpleInstance> slotMentions2 = getSlotMentions(mention2);
180    
181                    for (SimpleInstance slotMention1 : slotMentions1) {
182                            Slot mentionedSlot = getSlotMentionSlot(slotMention1);
183                            List<Object> slotMention1Values = getSlotMentionValues(slotMention1);
184                            SimpleInstance slotMention2 = getSlotMention(mention2, mentionedSlot);
185                            if (slotMention2 == null && slotMention1Values.size() == 0)
186                                    continue;
187                            // return false if the two slot mentions for the slot are not equal
188                            if (!equals(slotMention1, slotMention2, compareAnnotationSpans))
189                                    return false;
190                    }
191                    for (SimpleInstance slotMention2 : slotMentions2) {
192                            Slot mentionedSlot = getSlotMentionSlot(slotMention2);
193                            List<Object> slotMention2Values = getSlotMentionValues(slotMention2);
194                            SimpleInstance slotMention1 = getSlotMention(mention1, mentionedSlot);
195                            if (slotMention1 == null && slotMention2Values.size() == 0)
196                                    continue;
197                            // return false if the two slot mentions for the slot are not equal
198                            if (!equals(slotMention1, slotMention2, compareAnnotationSpans))
199                                    return false;
200                    }
201                    return true;
202            }
203    
204            private boolean compareAnnotationSpans(SimpleInstance mention1, SimpleInstance mention2) {
205                    SimpleInstance annotation1 = getMentionAnnotation(mention1);
206                    if (annotation1 == null)
207                            return false;
208    
209                    SimpleInstance annotation2 = getMentionAnnotation(mention2);
210                    if (annotation2 == null)
211                            return false;
212    
213                    return annotationUtil.compareSpans(annotation1, annotation2);
214            }
215    
216            /**
217             * 
218             * @param mention
219             * @param copiesMap
220             * @return TODO simplify the signature.
221             */
222            public SimpleInstance copyMention(SimpleInstance mention, Map<SimpleInstance, SimpleInstance> copiesMap) {
223                    if (copiesMap != null && copiesMap.containsKey(mention))
224                            return copiesMap.get(mention);
225    
226                    if (isMention(mention)) {
227                            SimpleInstance mentionCopy = kb.createSimpleInstance(null, null, CollectionUtilities
228                                            .createCollection(mention.getDirectType()), true);
229                            if (copiesMap != null)
230                                    copiesMap.put(mention, mentionCopy);
231    
232                            // Cls mentionType = mentionCopy.getDirectType();
233    
234                            if (isClassMention(mention)) {
235                                    Cls mentionCls = getMentionCls(mention);
236                                    if (mentionCls != null)
237                                            setMentionCls(mentionCopy, mentionCls);
238                            } else if (isInstanceMention(mention)) {
239                                    SimpleInstance mentionInstance = getMentionInstance(mention);
240                                    if (mentionInstance != null)
241                                            setMentionInstance(mentionCopy, mentionInstance);
242                            }
243    
244                            if (isClassMention(mention) || isInstanceMention(mention)) {
245                                    List<SimpleInstance> slotMentions = getSlotMentions(mention);
246                                    for (SimpleInstance slotMention : slotMentions) {
247                                            addSlotMention(mentionCopy, copyMention(slotMention, copiesMap));
248                                    }
249                            } else if (isSlotMention(mention)) {
250                                    Slot mentionSlot = getSlotMentionSlot(mention);
251                                    setMentionSlot(mentionCopy, mentionSlot);
252                                    List<Object> slotValues = getSlotMentionValues(mention);
253                                    for (Object slotValue : slotValues) {
254                                            if (slotValue instanceof SimpleInstance)
255                                                    addValueToSlotMention(mentionCopy, copyMention((SimpleInstance) slotValue, copiesMap));
256                                            else
257                                                    addValueToSlotMention(mentionCopy, slotValue);
258                                    }
259                            }
260                            return mentionCopy;
261                    }
262                    return null;
263            }
264    
265            public SimpleInstance createClassMention(Cls cls) {
266                    SimpleInstance clsMention = kb.createSimpleInstance(null, null, CollectionUtilities
267                                    .createCollection(kpu.classMentionCls), true);
268                    // if(cls != null)
269                    // {
270                    clsMention.setOwnSlotValue(kpu.mentionClassSlot, cls);
271                    // }
272                    return clsMention;
273            }
274    
275            public SimpleInstance createInstanceMention(SimpleInstance simpleInstance) {
276                    SimpleInstance instanceMention = kb.createSimpleInstance(null, null, CollectionUtilities
277                                    .createCollection(kpu.instanceMentionCls), true);
278                    instanceMention.setOwnSlotValue(kpu.mentionInstanceSlot, simpleInstance);
279                    return instanceMention;
280            }
281    
282            /**
283             * This method adds a slotMention to a class or instance mention. Please
284             * refer to the knowtator model in knowtator.pprj and look at the class
285             * definition for "knowtator class mention". This method adds a value to the
286             * slot 'knowtator_slot_mention'.
287             * 
288             * @see #addValueToSlotMention(SimpleInstance, Object)
289             */
290    
291            public void addSlotMention(SimpleInstance mention, SimpleInstance slotMention) {
292                    if ((isClassMention(mention) || isInstanceMention(mention)) && isSlotMention(slotMention)) {
293                            mention.addOwnSlotValue(kpu.getSlotMentionSlot(), slotMention);
294                    }
295            }
296    
297            /**
298             * This method adds a value to a slotMention. Please refer to the knowtator
299             * model in knowtator.pprj and look at the class definition for "knowtator
300             * slot mention". This method adds a value to the slot
301             * 'knowtator_mention_slot_value'.
302             * 
303             * @param slotMention
304             *            must be an instance of a slot mention
305             * @param slotValue
306             *            can be a class mention, instance mention, or an Integer,
307             *            Float, String or Boolean.
308             */
309    
310            public void addValueToSlotMention(SimpleInstance slotMention, Object slotValue) {
311                    if (isComplexSlotMention(slotMention)) {
312                            if (slotValue instanceof SimpleInstance) {
313                                    SimpleInstance slotValueInstance = (SimpleInstance) slotValue;
314                                    if (isClassMention(slotValueInstance) || isInstanceMention(slotValueInstance)) {
315                                            slotMention.addOwnSlotValue(kpu.getMentionSlotValueSlot(), slotValueInstance);
316                                    }
317                            }
318                    } else if (isSlotMention(slotMention)) {
319                            slotMention.addOwnSlotValue(kpu.getMentionSlotValueSlot(), slotValue);
320                    }
321            }
322    
323            public void removeValueFromSlotMention(SimpleInstance slotMention, Object slotValue) {
324                    if (isSlotMention(slotMention)) {
325                            slotMention.removeOwnSlotValue(kpu.getMentionSlotValueSlot(), slotValue);
326                    }
327            }
328    
329            public SimpleInstance createSlotMention(Slot slot) {
330                    ValueType slotType = slot.getValueType();
331                    Cls instanceType = kpu.stringSlotMentionCls;
332                    if (slotType == ValueType.CLS || slotType == ValueType.INSTANCE)
333                            instanceType = kpu.complexSlotMentionCls;
334                    else if (slotType == ValueType.BOOLEAN)
335                            instanceType = kpu.booleanSlotMentionCls;
336                    else if (slotType == ValueType.FLOAT)
337                            instanceType = kpu.floatSlotMentionCls;
338                    else if (slotType == ValueType.INTEGER)
339                            instanceType = kpu.integerSlotMentionCls;
340    
341                    SimpleInstance slotMention = kb.createSimpleInstance(null, null, CollectionUtilities
342                                    .createCollection(instanceType), true);
343                    slotMention.setOwnSlotValue(kpu.mentionSlotSlot, slot);
344                    return slotMention;
345            }
346    
347            /**
348             * Creates a mention based on the passed in instance. Instance is the super
349             * interface for Cls, SimpleInstance and Slot. Depending on the Class of the
350             * passed instance, the return value will be a "class mention", "instance
351             * mention" or "slot mention".
352             * 
353             * @param instance
354             *            should be Cls, SimpleInstance or Slot
355             * @return null - if instance is not a Cls, SimpleInstance or Slot.
356             *         Otherwise, returns a "class mention", "instance mention", or
357             *         "slot mention"
358             */
359    
360            public SimpleInstance createMention(Instance instance) {
361                    if (instance instanceof Cls)
362                            return createClassMention((Cls) instance);
363                    else if (instance instanceof SimpleInstance)
364                            return createInstanceMention((SimpleInstance) instance);
365                    else if (instance instanceof Slot)
366                            return createSlotMention((Slot) instance);
367                    return null;
368            }
369    
370            public boolean isClassMention(SimpleInstance mention) {
371                    if (mention == null)
372                            return false;
373                    // return mention.getDirectType().equals(kpu.classMentionCls);
374                    return mention.hasType(kpu.classMentionCls);
375            }
376    
377            public boolean isInstanceMention(SimpleInstance mention) {
378                    if (mention == null)
379                            return false;
380                    // return mention.getDirectType().equals(kpu.instanceMentionCls);
381                    return mention.hasType(kpu.instanceMentionCls);
382    
383            }
384    
385            public boolean isMention(SimpleInstance mention) {
386                    if (mention == null)
387                            return false;
388                    return mention.hasType(kpu.mentionCls);
389            }
390    
391            public boolean isSlotMention(SimpleInstance mention) {
392                    if (mention == null)
393                            return false;
394                    if (mention.hasType(kpu.slotMentionCls) || mention.hasType(kpu.complexSlotMentionCls)
395                                    || mention.hasType(kpu.booleanSlotMentionCls) || mention.hasType(kpu.floatSlotMentionCls)
396                                    || mention.hasType(kpu.integerSlotMentionCls) || mention.hasType(kpu.stringSlotMentionCls))
397                            return true;
398    
399                    return false;
400            }
401    
402            public boolean isBooleanSlotMention(SimpleInstance mention) {
403                    if (mention == null)
404                            return false;
405                    if (mention.hasType(kpu.booleanSlotMentionCls))
406                            return true;
407                    return false;
408            }
409    
410            public boolean isFloatSlotMention(SimpleInstance mention) {
411                    if (mention == null)
412                            return false;
413                    if (mention.hasType(kpu.floatSlotMentionCls))
414                            return true;
415                    return false;
416            }
417    
418            public boolean isIntegerSlotMention(SimpleInstance mention) {
419                    if (mention == null)
420                            return false;
421                    if (mention.hasType(kpu.integerSlotMentionCls))
422                            return true;
423                    return false;
424            }
425    
426            public boolean isStringSlotMention(SimpleInstance mention) {
427                    if (mention == null)
428                            return false;
429                    if (mention.hasType(kpu.stringSlotMentionCls))
430                            return true;
431                    return false;
432            }
433    
434            public boolean isSimpleSlotMention(SimpleInstance mention) {
435                    if (mention == null)
436                            return false;
437                    if (isStringSlotMention(mention) || isIntegerSlotMention(mention) || isFloatSlotMention(mention)
438                                    || isBooleanSlotMention(mention))
439                            return true;
440                    else
441                            return false;
442            }
443    
444            /**
445             * Determines whether an instance is a complex slot mention. Please refer to
446             * the knowtator model in knowtator.pprj and look at the class definition
447             * for "knowtator complex slot mention". If the instance is of type
448             * "knowtator complex slot mention" of one of its descendants, then true is
449             * returned.
450             * 
451             * @return true if the instance is of type "knowtator complex slot mention".
452             */
453    
454            public boolean isComplexSlotMention(SimpleInstance mention) {
455                    if (mention == null)
456                            return false;
457                    Cls mentionType = mention.getDirectType();
458                    if (mentionType == null)
459                            return false;
460                    if (mentionType.equals(kpu.complexSlotMentionCls) || mentionType.hasSuperclass(kpu.complexSlotMentionCls)) {
461                            return true;
462                    }
463                    return false;
464            }
465    
466            /**
467             * This method gathers all the mentions (e.g. slot mentions, class mentions
468             * and instance mentions) that are connected to the passed in mention.
469             * Connections are directed and start from the passed in mention and are
470             * found recursively via slot mentions. For example, if a class mention is
471             * passed in, then its slot mentions, the mention values of the slot
472             * mentions, and their slot mentions (and so on) will all be in the returned
473             * set. The returned set does not parallel the structure of the
474             * relationships between the mentions - it simply gathers them up and dumps
475             * in the returned set. The returned set contains the mention that is passed
476             * to the method.
477             * 
478             * 
479             * @param mention
480             *            should be a Protege instance of mention.
481             * @return if mention is not a Protege instance of mention, then an empty
482             *         set will be returned. Otherwise, the set will contain the passed
483             *         in mention and all mentions (class, instance, and slot) that it
484             *         is connected to (see above.)
485             */
486            public Set<SimpleInstance> getAllConnectedMentions(SimpleInstance mention) {
487                    Set<SimpleInstance> mentions = new HashSet<SimpleInstance>();
488                    if (isMention(mention)) {
489                            mentions.add(mention);
490                            _getAllConnectedMentions(mention, mentions);
491                    }
492                    return mentions;
493            }
494    
495            private void _getAllConnectedMentions(SimpleInstance mention, Set<SimpleInstance> mentions) {
496                    if (isClassMention(mention) || isInstanceMention(mention)) {
497                            List<SimpleInstance> slotMentions = getSlotMentions(mention);
498                            for (SimpleInstance slotMention : slotMentions) {
499                                    if (!mentions.contains(slotMention)) {
500                                            mentions.add(slotMention);
501                                            _getAllConnectedMentions(slotMention, mentions);
502                                    }
503                            }
504                    }
505                    if (isSlotMention(mention)) {
506                            List<Object> slotValues = getSlotMentionValues(mention);
507                            for (Object slotValue : slotValues) {
508                                    if (slotValue instanceof SimpleInstance) {
509                                            if (isMention((SimpleInstance) slotValue)) {
510                                                    if (!mentions.contains(slotValue)) {
511                                                            mentions.add((SimpleInstance) slotValue);
512                                                            _getAllConnectedMentions((SimpleInstance) slotValue, mentions);
513                                                    }
514                                            }
515                                    }
516                            }
517                    }
518            }
519    
520            /**
521             * This method returns all class mentions or instance mentions related to
522             * the passed in mention via slot mentions.
523             * 
524             * This method returns all of the complex slot mention values for a class
525             * mention or instance mention. Please refer to the knowtator model in
526             * knowtator.pprj and look at the class definition for "knowtator class
527             * mention" or "knowtator instance mention". The values of the slot
528             * "knowtator_slot_mention" may be of type "knowtator complex slot mention".
529             * Values of the slot "knowtator_mention_slot_value" for values of the
530             * passed in mentions values of the slot "knowtator_slot_mention" are
531             * returned.
532             * 
533             * @param mention
534             *            should be of type 'knowtator class mention' or 'knowtator
535             *            instance mention'.
536             * @return the slot mention values of the mention's slot mentions. All
537             *         values in the returned list should be of type 'knowtator class
538             *         mention' or 'knowtator instance mention'. This method will return
539             *         an empty list if there are no related mentions or if the mention
540             *         is not a class mention or instance mention.
541             */
542            public List<SimpleInstance> getRelatedMentions(SimpleInstance mention) {
543                    List<SimpleInstance> returnValues = new ArrayList<SimpleInstance>();
544    
545                    if (isClassMention(mention) || isInstanceMention(mention)) {
546                            List<SimpleInstance> complexSlotMentions = getComplexSlotMentions(mention);
547                            for (SimpleInstance complexSlotMention : complexSlotMentions) {
548                                    Collection<SimpleInstance> mentionSlotValues = (Collection<SimpleInstance>) complexSlotMention
549                                                    .getOwnSlotValues(kpu.getMentionSlotValueSlot());
550                                    if (mentionSlotValues != null)
551                                            returnValues.addAll(mentionSlotValues);
552                            }
553                    }
554                    return returnValues;
555            }
556    
557            /**
558             * This method returns all class mentions or instance mentions related to
559             * the passed in mention via slot mentions whose mentioned slot is the
560             * passed in slot.
561             * 
562             * Please refer to the knowtator model in knowtator.pprj and look at the
563             * class definition for "knowtator class mention" or "knowtator instance
564             * mention". The values of the slot "knowtator_slot_mention" may be of type
565             * "knowtator complex slot mention". Values of the slot
566             * "knowtator_mention_slot_value" for values of the passed in mention's
567             * values of the slot "knowtator_slot_mention" are returned if the slot
568             * mention's "knowtator_mention_slot" is the same as the passed in slot.
569             * 
570             * @param mention
571             *            should be of type 'knowtator class mention' or 'knowtator
572             *            instance mention'.
573             * @param slot
574             *            a slot corresponding to a knowtator_mention_slot of a
575             *            'knowtator complex slot mention'
576             * 
577             * @return All values in the returned list should be of type 'knowtator
578             *         class mention' or 'knowtator instance mention'. This method will
579             *         return an empty list if there are no related mentions or if the
580             *         mention is not a class mention or instance mention.
581             */
582            public List<SimpleInstance> getRelatedMentions(SimpleInstance mention, Slot slot) {
583                    List<SimpleInstance> returnValues = new ArrayList<SimpleInstance>();
584                    if (isClassMention(mention) || isInstanceMention(mention)) {
585                            SimpleInstance slotMention = getSlotMention(mention, slot);
586                            if (isComplexSlotMention(slotMention)) {
587                                    Collection<SimpleInstance> values = (Collection<SimpleInstance>) slotMention.getOwnSlotValues(kpu
588                                                    .getMentionSlotValueSlot());
589                                    returnValues.addAll(values);
590                            }
591                    }
592                    return returnValues;
593            }
594    
595            public Frame getMentionFrame(SimpleInstance mention) {
596                    if (mention == null)
597                            return null;
598                    if (isClassMention(mention)) {
599                            return (Cls) mention.getOwnSlotValue(kpu.mentionClassSlot);
600                    } else if (isInstanceMention(mention)) {
601                            return (Instance) mention.getOwnSlotValue(kpu.mentionInstanceSlot);
602                    }
603                    return null;
604            }
605    
606            /**
607             * If the mention is a "class mention" then the Cls corresponding to the
608             * mentioned class is returned. If the mention is a "instance mention" then
609             * the Cls corresponding to the direct type of the mentioned instance is
610             * returned.
611             * 
612             * @return the class of a class mention, or the direct type of the instance
613             *         of an instance mention or null if the class or instance no longer
614             *         exists
615             */
616    
617            public Cls getMentionCls(SimpleInstance mention) {
618                    if (isClassMention(mention)) {
619                            return (Cls) mention.getOwnSlotValue(kpu.mentionClassSlot);
620                    } else if (isInstanceMention(mention)) {
621                            Instance mentionInstance = (Instance) mention.getOwnSlotValue(kpu.mentionInstanceSlot);
622                            if (mentionInstance != null)
623                                    return mentionInstance.getDirectType();
624                    }
625                    return null;
626            }
627    
628            /**
629             * This method sets the cls that is mentioned by a class mention. Please
630             * refer to the knowtator model in knowtator.pprj and look at the class
631             * definition for "knowtator class mention". This method sets the value for
632             * the slot "knowtator_mention_class".
633             * 
634             * @param clsMention
635             *            the mention must be a class mention or this method does
636             *            nothing
637             * @param mentionCls
638             *            the class that is mentioned by the instance mention
639             */
640            public void setMentionCls(SimpleInstance clsMention, Cls mentionCls) {
641                    if (isClassMention(clsMention)) {
642                            clsMention.setDirectOwnSlotValue(kpu.getMentionClassSlot(), mentionCls);
643                    }
644            }
645    
646            /**
647             * This method sets the instance that is mentioned by an instance mention.
648             * Please refer to the knowtator model in knowtator.pprj and look at the
649             * class definition for "knowtator instance mention". This method sets the
650             * value for the slot "knowtator_mention_instance".
651             * 
652             * @param instanceMention
653             *            the mention must be an instance mention or this method does
654             *            nothing
655             * @param mentionInstance
656             *            the instance that is mentioned by the instance mention
657             */
658            public void setMentionInstance(SimpleInstance instanceMention, SimpleInstance mentionInstance) {
659                    if (isInstanceMention(instanceMention)) {
660                            instanceMention.setDirectOwnSlotValue(kpu.getMentionInstanceSlot(), mentionInstance);
661                    }
662            }
663    
664            /**
665             * This method sets the slot that is mentioned by a slot mention. Please
666             * refer to the knowtator model in knowtator.pprj and look at the class
667             * definition for "knowtator slot mention". This method sets the value for
668             * the slot "knowtator_mention_slot".
669             * 
670             * @param slotMention
671             *            the mention must be a slot mention or this method does nothing
672             * @param mentionSlot
673             *            the slot that is mentioned by the slot mention
674             */
675            public void setMentionSlot(SimpleInstance slotMention, Slot mentionSlot) {
676                    if (isSlotMention(slotMention)) {
677                            slotMention.setDirectOwnSlotValue(kpu.getMentionSlotSlot(), mentionSlot);
678                    }
679            }
680    
681            public SimpleInstance getMentionInstance(SimpleInstance instanceMention) {
682                    if (isInstanceMention(instanceMention)) {
683                            return (SimpleInstance) instanceMention.getOwnSlotValue(kpu.mentionInstanceSlot);
684                    }
685                    return null;
686            }
687    
688            /**
689             * This method gets the slot mentions of a class mention or instance
690             * mention. Please refer to the knowtator model in knowtator.pprj and look
691             * at the class definition for "knowtator class mention" or "knowtator
692             * instance mention". This method returns the values of the slot
693             * "knowtator_slot_mention".
694             * 
695             * @param mention
696             *            must be a class mention or instance mention otherwise an empty
697             *            list will be returned
698             * @return all slot mentions for the mention. If none exist, then an empty
699             *         list will be returned.
700             */
701            public List<SimpleInstance> getSlotMentions(SimpleInstance mention) {
702                    List<SimpleInstance> returnValues = new ArrayList<SimpleInstance>();
703                    if (isClassMention(mention) || isInstanceMention(mention)) {
704                            Collection<SimpleInstance> slotMentions = (Collection<SimpleInstance>) mention.getDirectOwnSlotValues(kpu
705                                            .getSlotMentionSlot());
706                            if (slotMentions != null) {
707                                    returnValues.addAll(slotMentions);
708                            }
709                    }
710                    return returnValues;
711            }
712    
713            /**
714             * This method gets the complex slot mentions of a class mention or instance
715             * mention. Please refer to the knowtator model in knowtator.pprj and look
716             * at the class definition for "knowtator class mention" or "knowtator
717             * instance mention". This method returns the values of the slot
718             * "knowtator_slot_mention" that are of type "knowtator complex slot
719             * mention".
720             * 
721             * @param mention
722             *            should be a class mention or instance mention;
723             * @return all complex slot mentions for the mention. If none exist, then an
724             *         empty list will be returned.
725             */
726            public List<SimpleInstance> getComplexSlotMentions(SimpleInstance mention) {
727                    List<SimpleInstance> returnValues = new ArrayList<SimpleInstance>();
728                    if (isClassMention(mention) || isInstanceMention(mention)) {
729                            List<SimpleInstance> allSlotMentions = getSlotMentions(mention);
730                            for (SimpleInstance slotMention : allSlotMentions) {
731                                    if (isComplexSlotMention(slotMention)) {
732                                            returnValues.add(slotMention);
733                                    }
734                            }
735                    }
736                    return returnValues;
737            }
738    
739            public List<Slot> getMentionSlots(SimpleInstance mention) {
740                    Collection<Slot> slots = null;
741                    if (isClassMention(mention)) {
742                            Cls mentionCls = getMentionCls(mention);
743                            if (mentionCls != null)
744                                    slots = (Collection<Slot>) mentionCls.getTemplateSlots();
745                    } else if (isInstanceMention(mention)) {
746                            Instance mentionInstance = getMentionInstance(mention);
747                            if (mentionInstance != null) {
748                                    slots = mentionInstance.getOwnSlots();
749                                    slots.remove(kb.getSlot(":DIRECT-TYPE"));
750                                    slots.remove(kb.getSlot(":NAME"));
751                            }
752                    }
753                    if (slots != null) {
754                            return new ArrayList<Slot>(slots);
755                    } else
756                            return new ArrayList<Slot>();
757            }
758    
759            /**
760             * gets a slot mention for the given slot of a class mention or instance
761             * mention. Please refer to the knowtator model in knowtator.pprj and look
762             * at the class definition for "knowtator class mention" or "knowtator
763             * instance mention". This method returns the values of the slot
764             * "knowtator_slot_mention" that correspond to the passed in slot.
765             * 
766             * @param mention
767             *            must be a class mention or instance mention otherwise null
768             *            will be returned.
769             * @param mentionSlot
770             *            the "knowtator_mention_slot" of the slot mention.
771             * @return an instance of 'knowtator slot mention' or one of its subtypes or
772             *         null if none exist.
773             */
774    
775            // what if there are two slot mentions with the same slot? editor does not
776            // allow it but
777            // knowtator model does.
778            public SimpleInstance getSlotMention(SimpleInstance mention, Slot mentionSlot) {
779                    if (mentionSlot == null)
780                            return null;
781                    List<SimpleInstance> slotMentions = getSlotMentions(mention);
782                    for (SimpleInstance slotMention : slotMentions) {
783                            if (mentionSlot.equals(getSlotMentionSlot(slotMention))) {
784                                    return slotMention;
785                            }
786                    }
787                    return null;
788            }
789    
790            public boolean hasSlotMention(SimpleInstance mention, Slot mentionSlot) {
791                    SimpleInstance slotMention = getSlotMention(mention, mentionSlot);
792                    if (slotMention != null)
793                            return true;
794                    return false;
795            }
796    
797            public boolean hasSlotValue(SimpleInstance slotMention) {
798                    if (isSlotMention(slotMention)) {
799                            Object value = slotMention.getOwnSlotValue(kpu.mentionSlotValueSlot);
800                            if (value != null) {
801                                    return true;
802                            }
803                    }
804                    return false;
805            }
806    
807            /**
808             * this method takes a mention and initializes slot mentions for slots that
809             * do not yet have a slotMention for the mention.
810             */
811    
812            public void initializeSlotMentions(SimpleInstance mention) {
813                    List<Slot> mentionSlots = getMentionSlots(mention);
814                    List<SimpleInstance> slotMentions = new ArrayList<SimpleInstance>(getSlotMentions(mention));
815                    for (Slot mentionSlot : mentionSlots) {
816                            if (!hasSlotMention(mention, mentionSlot)) {
817                                    slotMentions.add(createSlotMention(mentionSlot));
818                            }
819                    }
820                    if (slotMentions.size() > 0) {
821                            mention.setOwnSlotValues(kpu.slotMentionSlot, slotMentions);
822                    }
823            }
824    
825            public void removeEmptySlotMentions(SimpleInstance mention) {
826                    List<SimpleInstance> slotMentions = new ArrayList(getSlotMentions(mention));
827                    List<SimpleInstance> deletedMentions = new ArrayList<SimpleInstance>();
828                    for (SimpleInstance slotMention : slotMentions) {
829                            Object value = slotMention.getOwnSlotValue(kpu.mentionSlotValueSlot);
830                            if (value == null) {
831                                    deletedMentions.add(slotMention);
832                            }
833                    }
834                    slotMentions.removeAll(deletedMentions);
835                    mention.setOwnSlotValues(kpu.slotMentionSlot, slotMentions);
836                    for (Instance slotMention : deletedMentions) {
837                            kb.deleteInstance(slotMention);
838                    }
839            }
840    
841            public void deleteMention(SimpleInstance mention) {
842                    List<SimpleInstance> slotMentions = getSlotMentions(mention);
843                    for (SimpleInstance slotMention : slotMentions) {
844                            kb.deleteInstance(slotMention);
845                    }
846                    kb.deleteInstance(mention);
847    
848            }
849    
850            public SimpleInstance getMentionAnnotation(SimpleInstance mention) {
851                    SimpleInstance mentionAnnotation = (SimpleInstance) mention.getOwnSlotValue(kpu.getMentionAnnotationSlot());
852                    return mentionAnnotation;
853            }
854    
855            public void setMentionAnnotations(SimpleInstance mention, Collection<SimpleInstance> annotations) {
856                    mention.setOwnSlotValues(kpu.mentionAnnotationSlot, annotations);
857            }
858    
859            public Slot getSlotMentionSlot(SimpleInstance mention) {
860                    if (isSlotMention(mention)) {
861                            return (Slot) mention.getOwnSlotValue(kpu.mentionSlotSlot);
862                    } else
863                            return null;
864            }
865    
866            public List<Object> getSlotMentionValues(SimpleInstance slotMention) {
867                    List<Object> returnValues = new ArrayList<Object>();
868                    if (isSlotMention(slotMention)) {
869                            Collection<Object> values = (Collection<Object>) slotMention
870                                            .getOwnSlotValues(kpu.getMentionSlotValueSlot());
871                            if (values != null) {
872                                    returnValues.addAll(values);
873                            }
874                    }
875                    return returnValues;
876            }
877    
878            public void setSlotMentionValues(SimpleInstance slotMention, List<Object> values) {
879                    if (isSlotMention(slotMention)) {
880                            slotMention.setOwnSlotValues(kpu.getMentionSlotValueSlot(), values);
881                    }
882            }
883    
884            public SimpleInstance getMentionedBy(SimpleInstance slotMention) {
885                    if (isSlotMention(slotMention)) {
886                            return (SimpleInstance) slotMention.getOwnSlotValue(kpu.mentionedInSlot);
887                    }
888                    return null;
889            }
890    
891            /**
892             * This method was written and contributed by Angus Roberts.
893             * 
894             * This method takes a mention slot with a known value on an annotation
895             * mention, and adds an inverse slot on the value, with the annotation
896             * mentions as its valu. If the inverse slot does not exist, it is added.
897             * Given annotationMention--[mentionSlot]--mentionSlotValueMention, the
898             * method will add
899             * mentionSlotValueMention--[inverse_of_mentionSlot]--annotationMention
900             * 
901             * @param annotationMention
902             *            an annotation mention with a mention slot
903             * @param mentionSlot
904             *            a slot, the inverse of which will be added
905             * @param mentionSlotValueMention
906             *            the value of that will be added to mentionSlot
907             */
908    
909            public void addInverse(SimpleInstance annotationMention, Slot mentionSlot, SimpleInstance mentionSlotValueMention) {
910                    Slot inverse = mentionSlot.getInverseSlot();
911                    if (inverse != null) {
912                            SimpleInstance inverseSlotMention = getSlotMention(mentionSlotValueMention, inverse);
913                            if (inverseSlotMention != null) {
914                                    // The mentionSlotValueMention already has this inverse slot
915                                    addValueToSlotMention(inverseSlotMention, annotationMention);
916                            } else {
917                                    // It doesn't have this inverse slot, add it
918                                    inverseSlotMention = createSlotMention(inverse);
919                                    addValueToSlotMention(inverseSlotMention, annotationMention);
920                                    addSlotMention(mentionSlotValueMention, inverseSlotMention);
921                            } // end of else
922                    } // end of if ()
923            }
924    
925            /**
926             * This method was written and contributed by Angus Roberts.
927             * 
928             * This method takes a mention slot with a known value on an annotation
929             * mention, and checks for an inverse slot on the value. If the inverse
930             * exists, it is removed. Given
931             * annotationMention--[mentionSlot]--mentionSlotValueMention, the method
932             * will remove
933             * mentionSlotValueMention--[inverse_of_mentionSlot]--annotationMention
934             * 
935             * @param annotationMention
936             *            an annotation mention with a mention slot
937             * @param mentionSlot
938             *            a slot, the inverse of which will be removed
939             * @param mentionSlotValueMention
940             *            the value of mentionSlot
941             */
942    
943            public void removeInverse(SimpleInstance annotationMention, Slot mentionSlot, SimpleInstance mentionSlotValueMention) {
944                    Slot inverse = mentionSlot.getInverseSlot();
945                    if (inverse != null) {
946                            SimpleInstance inverseSlotMention = getSlotMention(mentionSlotValueMention, inverse);
947                            if (inverseSlotMention != null)
948                                    removeValueFromSlotMention(inverseSlotMention, annotationMention);
949                    } // end of if ()
950            }
951    
952            public List<SimpleInstance> getSlotFillerCandidates(SimpleInstance mention, Slot slot,
953                            List<SimpleInstance> annotations) {
954                    Set<SimpleInstance> currentSlotValues = new HashSet<SimpleInstance>(getRelatedMentions(mention, slot));
955    
956                    List<SimpleInstance> returnValues = new ArrayList<SimpleInstance>();
957    
958                    Cls mentionCls = getMentionCls(mention);
959                    if (mentionCls == null)
960                            return returnValues;
961    
962                    HashSet<Cls> allowedClses = new HashSet<Cls>((Collection<Cls>) mentionCls.getTemplateSlotAllowedClses(slot));
963    
964                    for (SimpleInstance annotation : annotations) {
965                            if (annotation.isDeleted())
966                                    continue;
967    
968                            SimpleInstance annotationMention = annotationUtil.getMention(annotation);
969                            if (currentSlotValues.contains(annotationMention))
970                                    continue;
971    
972                            if (isInstanceMention(annotationMention)) {
973                                    SimpleInstance annotatedInstance = getMentionInstance(annotationMention);
974                                    if (mentionCls.isValidOwnSlotValue(slot, annotatedInstance)) {
975                                            returnValues.add(annotation);
976                                    }
977                            } else if (isClassMention(annotationMention)) {
978                                    Cls annotatedCls = getMentionCls(annotationMention);
979    
980                                    if (slot.getValueType().equals(ValueType.INSTANCE)) {
981                                            HashSet<Cls> annotatedClsAncestors = new HashSet<Cls>((Collection<Cls>) annotatedCls
982                                                            .getSuperclasses());
983                                            annotatedClsAncestors.add(annotatedCls);
984    
985                                            annotatedClsAncestors.retainAll(allowedClses);
986                                            if (annotatedClsAncestors.size() > 0) {
987                                                    returnValues.add(annotation);
988                                            }
989                                    }
990                                    if (slot.getValueType().equals(ValueType.CLS)) {
991                                            HashSet annotatedClsAncestors = new HashSet(annotatedCls.getSuperclasses());
992                                            allowedClses.retainAll(annotatedClsAncestors);
993                                            if (allowedClses.size() > 0) {
994                                                    returnValues.add(annotation);
995                                            }
996                                    }
997                            }
998                    }
999                    return returnValues;
1000            }
1001    
1002            public void adjustSlotMentionForCardinality(Cls cls, Slot slot, SimpleInstance mention) {
1003                    int maxCardinality = cls.getTemplateSlotMaximumCardinality(slot);
1004                    if (maxCardinality > 0) {
1005                            SimpleInstance slotMention = getSlotMention(mention, slot);
1006                            if (slotMention != null) {
1007                                    List<Object> slotValues = getSlotMentionValues(slotMention);
1008                                    List<Object> newValues = new ArrayList<Object>();
1009                                    for (int i = slotValues.size() - 1, j = 0; i >= 0 && j < maxCardinality; i--) {
1010                                            newValues.add(slotValues.get(i));
1011                                            j++;
1012                                    }
1013                                    setSlotMentionValues(slotMention, newValues);
1014                            }
1015                    }
1016            }
1017    
1018    }