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     */
028    package edu.uchsc.ccp.iaa.matcher;
029    
030    import java.util.Collection;
031    import java.util.HashSet;
032    import java.util.Set;
033    
034    import edu.uchsc.ccp.iaa.Annotation;
035    import edu.uchsc.ccp.iaa.IAA;
036    
037    /**
038     * This matcher is very similar to ClassMatcher.
039     * 
040     * @author Compaq_Owner
041     * 
042     */
043    
044    public class SubclassMatcher implements Matcher {
045    
046            String className;
047    
048            Set<String> subclassNames;
049    
050            ClassHierarchy hierarchy;
051    
052            public SubclassMatcher(ClassHierarchy hierarchy) {
053                    this.hierarchy = hierarchy;
054            }
055    
056            /**
057             * This method will return a match from ClassMatcher. If one does not exist,
058             * then match for
059             * 
060             * 
061             * 
062             * Otherwise, null is returned.
063             * 
064             * @param annotation
065             * @param compareSetName
066             * @param excludeAnnotations
067             * @param iaa
068             * @param matchResult
069             *            will be set to NONTRIVIAL_MATCH, NONTRIVIAL_NONMATCH, or
070             *            TRIVIAL_NONMATCH. Trivial non-matches occur when the
071             *            annotation is not of the class specified by setIAAClass or a
072             *            subclass of it. Trivial non-matches should be ignored and not
073             *            counted in any IAA metrics.
074             * @see edu.uchsc.ccp.iaa.matcher.Matcher#match(Annotation, String, Set,
075             *      IAA, MatchResult)
076             * @see edu.uchsc.ccp.iaa.matcher.MatchResult#NONTRIVIAL_MATCH
077             * @see edu.uchsc.ccp.iaa.matcher.MatchResult#NONTRIVIAL_NONMATCH
078             * @see edu.uchsc.ccp.iaa.matcher.MatchResult#TRIVIAL_NONMATCH
079             * @see edu.uchsc.ccp.iaa.Annotation#getShortestAnnotation(Collection)
080             * @see #setIAAClass(String)
081             */
082            public Annotation match(Annotation annotation, String compareSetName, Set<Annotation> excludeAnnotations, IAA iaa,
083                            MatchResult matchResult) {
084    
085                    String annotationClassName = annotation.getAnnotationClass();
086                    if (!subclassNames.contains(annotationClassName)) {
087                            matchResult.setResult(MatchResult.TRIVIAL_NONMATCH);
088                            return null;
089                    }
090    
091                    Annotation classMatch = ClassMatcher.match(annotation, compareSetName, iaa, excludeAnnotations);
092                    if (classMatch != null) {
093                            matchResult.setResult(MatchResult.NONTRIVIAL_MATCH);
094                            return classMatch;
095                    }
096    
097                    Set<Annotation> candidateAnnotations = new HashSet<Annotation>();
098                    for (String subclassName : subclassNames) {
099                            candidateAnnotations.addAll(iaa.getAnnotationsOfClass(subclassName, compareSetName));
100                    }
101    
102                    Set<Annotation> exactlyOverlappingAnnotations = new HashSet<Annotation>(iaa.getExactlyOverlappingAnnotations(
103                                    annotation, compareSetName));
104                    exactlyOverlappingAnnotations.retainAll(candidateAnnotations);
105                    exactlyOverlappingAnnotations.removeAll(excludeAnnotations);
106                    if (exactlyOverlappingAnnotations.size() > 0) {
107                            matchResult.setResult(MatchResult.NONTRIVIAL_MATCH);
108                            return exactlyOverlappingAnnotations.iterator().next();
109                    }
110    
111                    Set<Annotation> overlappingAnnotations = new HashSet<Annotation>(iaa.getOverlappingAnnotations(annotation,
112                                    compareSetName));
113                    overlappingAnnotations.retainAll(candidateAnnotations);
114                    overlappingAnnotations.removeAll(excludeAnnotations);
115                    if (overlappingAnnotations.size() > 0) {
116                            matchResult.setResult(MatchResult.NONTRIVIAL_MATCH);
117                            if (overlappingAnnotations.size() == 1)
118                                    return overlappingAnnotations.iterator().next();
119                            return Annotation.getShortestAnnotation(overlappingAnnotations);
120                    }
121    
122                    matchResult.setResult(MatchResult.NONTRIVIAL_NONMATCH);
123                    return null;
124            }
125    
126            /**
127             * Sets the class of the
128             * 
129             * @param className
130             */
131            public void setIAAClass(String className) {
132                    this.className = className;
133                    subclassNames = hierarchy.getSubclasses(className);
134            }
135    
136            public String getIAAClass() {
137                    return className;
138            }
139    
140            public String getName() {
141                    return "Subclass matcher for class '" + className + "'";
142            }
143    
144            public String getDescription() {
145                    return "Two annotations match if their class assignments are equal to '" + className + "' or a subclass of '"
146                                    + className + "' and their spans overlap.";
147            }
148    
149            public boolean returnsTrivials() {
150                    return true;
151            }
152    
153            public Set<String> getSubclasses() {
154                    return hierarchy.getSubclasses(className);
155            }
156    }