001 // This file is part of the Attempto Java Packages.
002 // Copyright 2008, 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 * Returns 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 true if the concepts of this individual are cached and do not have
215 * to be recalculated.
216 *
217 * @return true if the concepts are cached.
218 */
219 public boolean areConceptsCached() {
220 return conceptsCacheStateID == getOntology().getStateID();
221 }
222
223 }