/* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * !# */ package net.ontopia.topicmaps.utils; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import net.ontopia.topicmaps.core.ScopedIF; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.utils.LexicalComparator; /** * INTERNAL: Comparator that compares ScopedIF objects based on their * applicability in the specified scope.</p> * * This comparator may only be used with objects that are * implementations of ScopedIF. The default subcomparator is * LexicalComparator.CASE_SENSITIVE.</p> * * <b>Technique:</b></p> * * <ol> * <li>Compare the number of matching themes for each of the objects. The * more matching themes, the higher ranked.</li> * <li>Compare by number of themes specified on objects. The fewer * themes, the higher ranked. </li> * <li>If subcomparator doesn't exist they're ranked equally.</li> * <li>Use subcomparator to compare them.</li> * </ol> */ public class ScopedIFComparator<T extends ScopedIF> implements Comparator<T> { protected TopicIF[] scope; protected Comparator<? super T> subcomparator; public ScopedIFComparator() { this(Collections.<TopicIF>emptySet()); } public ScopedIFComparator(Collection<TopicIF> scope) { this(scope, LexicalComparator.CASE_SENSITIVE); } public ScopedIFComparator(Collection<TopicIF> scope, Comparator<? super T> subcomparator) { this.scope = new TopicIF[scope.size()]; scope.toArray(this.scope); this.subcomparator = subcomparator; } /** * INTERNAL: Compares the two ScopedIF objects for their applicability * in the scope specified in the constructor. * * @param obj1 An object implementing ScopedIF. * @param obj2 An object implementing ScopedIF. * @return See {@link java.util.Comparator#compare(Object,Object)} */ public int compare(T obj1, T obj2) { // Collect the scope of both objects Collection<TopicIF> scope1 = obj1.getScope(); Collection<TopicIF> scope2 = obj2.getScope(); // Count number of matching themes int matches = 0; for (int i=0; i < scope.length; i++) { if (scope1.contains(scope[i])) matches = matches + 1; if (scope2.contains(scope[i])) matches = matches - 1; } // Rank by matched themes if (matches > 0) return -1; else if (matches < 0) return 1; // Rank by lesser scope if ((scope1.isEmpty() && !scope2.isEmpty()) || (scope1.size() < scope2.size())) return -1; else if ((scope2.isEmpty() && !scope1.isEmpty()) || (scope2.size() < scope1.size())) return 1; // System.out.println("1:" + obj1 + scope1.size() + " 2:" + obj2 + scope2.size()); if (subcomparator == null) return 0; // Use subcomparator when equally ranked return subcomparator.compare(obj1, obj2); } }