001 // This file is part of the Attempto Java Packages. 002 // Copyright 2008-2009, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch). 003 // 004 // The Attempto Java Packages is free software: you can redistribute it and/or modify it under the 005 // terms of the GNU Lesser General Public License as published by the Free Software Foundation, 006 // either version 3 of the License, or (at your option) any later version. 007 // 008 // The Attempto Java Packages is distributed in the hope that it will be useful, but WITHOUT ANY 009 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 010 // PURPOSE. See the GNU Lesser General Public License for more details. 011 // 012 // You should have received a copy of the GNU Lesser General Public License along with the Attempto 013 // Java Packages. If not, see http://www.gnu.org/licenses/. 014 015 package ch.uzh.ifi.attempto.acewiki.core.ontology; 016 017 import java.util.ArrayList; 018 import java.util.List; 019 020 import ch.uzh.ifi.attempto.ape.Gender; 021 import ch.uzh.ifi.attempto.ape.LexiconEntry; 022 023 /** 024 * This class represents an individual (in logic called "constant"). AceWiki supports only 025 * proper names to represent individuals (and no extensions are planned in this respect). 026 * For that reason, this class is proper name specific. 027 *<p> 028 * Proper names can be used either with a definite article (e.g. "the United Nations") or without 029 * (e.g. "Switzerland"). Furthermore, proper names can have an abbreviation that is a shorter 030 * name with exactly the same meaning. This abbreviation can aswell be used either with a definite 031 * article (e.g. "the UN") or without (e.g. "ACE"). 032 *<p> 033 * Proper names have four word forms. The first one is the proper name with the definite 034 * article or just the proper name if no definite article is used for this proper name. The second 035 * one is in each case just the bare proper name. The third form is the abbreviation with the 036 * definite article if there is one. The fourth form, finally, is just the bare abbreviation. If 037 * there is no abbreviation then the third and fourth form are identical to the first and second 038 * form, respectively. For proper names that do not use a definite article and that have no 039 * abbreviation, all four forms are identical. 040 *<p> 041 * 0: proper name, preceded by "the" if used with definite article. 042 * 1: bare proper name. 043 * 2: abbreviation, preceded by "the" if used with definite article; or the same as 0 if there is 044 * no abbreviation. 045 * 3: bare abbreviation; or the same as 1 if there is no abbreviation. 046 *<p> 047 * Examples: ["the United Nations", "United Nations", "the UN", "UN"]; 048 * ["the Nile", "Nile", "Nile", "Nile]; 049 * ["Switzerland", "Switzerland", "Switzerland", "Switzerland"]; 050 * ["Attempto Controlled English", "Attempto Controlled English", "ACE", "ACE"]. 051 * 052 * @author Tobias Kuhn 053 */ 054 public class Individual extends OntologyElement { 055 056 private String word, abbrev; 057 private boolean wordDefArt, abbrevDefArt; 058 059 private List<Concept> conceptsCache; 060 private long conceptsCacheStateID = -1; 061 062 /** 063 * Creates a new individual that has no name yet and is not registered to an ontology. 064 */ 065 public Individual() { 066 this.word = ""; 067 this.abbrev = null; 068 this.wordDefArt = false; 069 this.abbrevDefArt = false; 070 } 071 072 public String[] getWords() { 073 if (abbrev == null) { 074 if (wordDefArt) { 075 return new String[] {"the " + word, word, "the " + word, word}; 076 } else { 077 return new String[] {word, word, word, word}; 078 } 079 } else { 080 if (wordDefArt) { 081 if (abbrevDefArt) { 082 return new String[] {"the " + word, word, "the " + abbrev, abbrev}; 083 } else { 084 return new String[] {"the " + word, word, abbrev, abbrev}; 085 } 086 } else { 087 if (abbrevDefArt) { 088 return new String[] {word, word, "the " + abbrev, abbrev}; 089 } else { 090 return new String[] {word, word, abbrev, abbrev}; 091 } 092 } 093 } 094 } 095 096 public String getHeadword() { 097 if (abbrev == null) { 098 return getPrettyWord(1); 099 } else { 100 return getPrettyWord(1) + " (" + getPrettyWord(3) + ")"; 101 } 102 } 103 104 public String[] getIndexEntries() { 105 return new String[] {getHeadword(), getPrettyWord(3)}; 106 } 107 108 protected void changeWords(String... words) { 109 if (words.length == 1) { 110 word = words[0]; 111 wordDefArt = false; 112 abbrev = null; 113 abbrevDefArt = false; 114 } else if (words.length == 2) { 115 word = words[1]; 116 wordDefArt = words[0].startsWith("the "); 117 abbrev = null; 118 abbrevDefArt = false; 119 } else if (words[2] == null || words[0].equals(words[2])) { 120 word = words[1]; 121 wordDefArt = words[0].startsWith("the "); 122 abbrev = null; 123 abbrevDefArt = false; 124 } else { 125 word = words[1]; 126 wordDefArt = words[0].startsWith("the "); 127 abbrev = words[3]; 128 abbrevDefArt = words[2].startsWith("the "); 129 } 130 } 131 132 List<LexiconEntry> getLexiconEntries() { 133 List<LexiconEntry> entries = new ArrayList<LexiconEntry>(); 134 if (wordDefArt) { 135 entries.add(LexiconEntry.createPropernameDefSgEntry(word, word, Gender.NEUTRAL)); 136 } else { 137 entries.add(LexiconEntry.createPropernameSgEntry(word, word, Gender.NEUTRAL)); 138 } 139 if (abbrev != null) { 140 if (abbrevDefArt) { 141 entries.add(LexiconEntry.createPropernameDefSgEntry(abbrev, word, Gender.NEUTRAL)); 142 } else { 143 entries.add(LexiconEntry.createPropernameSgEntry(abbrev, word, Gender.NEUTRAL)); 144 } 145 } 146 return entries; 147 } 148 149 public String getType() { 150 return "Proper Name"; 151 } 152 153 public String getInternalType() { 154 return "propername"; 155 } 156 157 /** 158 * Returns true if the proper name has to be used with the definite article "the". 159 * 160 * @return true if the definite article "the" has to be used. 161 */ 162 public boolean hasDefiniteArticle() { 163 return wordDefArt; 164 } 165 166 /** 167 * Returns true if the given word form uses the definite article "the". This returns 168 * always false for 1 and 3. 169 * 170 * @param wordNumber the word number 171 * @return true if the definite article "the" is used for the word form of the 172 * given word number 173 */ 174 public boolean hasDefiniteArticle(int wordNumber) { 175 if (wordNumber == 0) { 176 return wordDefArt; 177 } else if (wordNumber == 2) { 178 return abbrevDefArt; 179 } else { 180 return false; 181 } 182 } 183 184 /** 185 * Returns the abbreviation (without definite article) or null if there is no abbreviation. 186 * 187 * @return the abbreviation 188 */ 189 public String getAbbreviation() { 190 if (abbrev == null) return null; 191 return abbrev.replace("_", " "); 192 } 193 194 public String getURISuffix() { 195 return "#" + word; 196 } 197 198 /** 199 * Calculates all concepts this individual belongs to. 200 * 201 * @return A list of all concepts of this individual. 202 * @see Ontology#getConcepts(Individual) 203 */ 204 public synchronized List<Concept> getConcepts() { 205 Ontology o = getOntology(); 206 if (conceptsCacheStateID != o.getStateID()) { 207 conceptsCache = o.getConcepts(this); 208 conceptsCacheStateID = o.getStateID(); 209 } 210 return new ArrayList<Concept>(conceptsCache); 211 } 212 213 /** 214 * Returns the cached concepts or null if there are no cached concepts. The returned 215 * concepts might not be up-to-date. 216 * 217 * @return A list of the cached concepts of this individual. 218 */ 219 public List<Concept> getCachedConcepts() { 220 if (conceptsCache == null) return null; 221 return new ArrayList<Concept>(conceptsCache); 222 } 223 224 /** 225 * Returns true if the concepts of this individual are cached and up-to-date and thus 226 * do not have to be recalculated. 227 * 228 * @return true if the concepts are cached. 229 */ 230 public boolean areConceptsCached() { 231 return conceptsCacheStateID == getOntology().getStateID(); 232 } 233 234 }