package grammar.model.verbs;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import grammar.input.refdata.InsufficientReferenceDataException;
import grammar.model.Form;
import grammar.model.Language;
import grammar.model.MatchType;
import grammar.model.ReferenceData;
import grammar.model.ReferenceDataCategory;
import grammar.model.WordMatcher;
import grammar.model.Form.FormCategory;
import grammar.model.factory.ModelVerbFactory;
import grammar.util.Utilities;
/**
* <p>A means of conjugating a particular set of infinitives. ModelVerb instances
* define (via the matches() method) what infinitives this model can be used for,
* and provide a facility for retrieving segments of a conjugation using the
* getForm() method. ModelVerb instances are created on load using XML definition
* files, which specify what rules should be used for conjugation, and what
* infinitives are applicable.</p>
*
* <h1>The Model Verb Hierarchy</h1>
*
* <p>Every model verb except one (per language) must be a <i>child</i> of one
* or more other model verbs. As such, each language has a model verb hierarchy,
* against which infinitives are matched. For more on the matching process, see
* ModelVerbFactory. Once a matching model verb has been selected, one creates a
* ConjugatedVerb instance against the model. That ConjugatedVerb then relies
* upon its enclosing model's rules and inheritance relationships to determine
* how to inflect the infinitive at hand for a particular tense and pronoun or
* form. In the following example, taken from the packaged model verbs for
* French, we see how the first person plural (i.e. 'nous') form of the present
* tense is conjugated for the infinitive 'manger', which matches model verb
* 'Ger' (so named because it matches infinitives with the suffix -ger).</p>
*
* <p><img src="doc-files/example-1-mangeons.png"/></p>
*
* <p>Conjugated forms consist of up to three segments: a stem, infix and suffix.
* Concatonating these three (one or more segments may be the empty string) provides
* the required form. Different Segments can be sourced from different parts of the
* model verb hierarchy: in the preceding example, the infix is found in model 'Ger',
* while the stem and suffix are sourced from 'Root'.</p>
*
* <p>To reduce redundancy, another form of rule is supported: the reference. To take
* the example of the provided French model again, 'Root' states that the stem, infix
* and suffix of the imperative present tense can be found by refering to the present
* tense. Hence, to conjugate the imperative present in French, we might traverse the
* tree looking for applicable rules until we come to 'Root', whereupon finding no
* actual segment definitions for this tense, the reference to the present tense is
* found and followed. It's important to note that after following a reference, flow
* returns down the tree to the matched model verb - only this time, looking for
* rules applicable to the referenced tense (the present in the example given).</p>
*
* <p><img src="doc-files/example-2-viens.png"/></p>
*
* <p>Some tenses are <em>composites</em> - that is, they require a secondary
* <em>auxiliary</em> verb as part of the conjugated form. For instance, the
* French past perfect tense is formed by taking the present tense of the
* appropriate auxiliary verb, and adding on the past participle of the verb
* being conjugated. An example of how this is handled follows, using the
* regular er verb 'aimer':</p>
*
* <p><img src="doc-files/example-3-as-aime.png"/></p>
*
* <p>In this example, the verb 'aimer' matches the model Er. Finding no rules
* for the perfect tense in Er, flow moves to Er's parent, Root. In Root, there
* are two relevant rules: a reference, such as the one described in the previous
* example, only this one indicates that the relevant form to use is the past
* participle. Following this reference, flow returns to Er, where a suffix is
* found for the past participle. No rules are found for the stem or infix, and
* so we return to Root, only this time looking for rules for the present tense
* rather than the perfect tense. Applicable rules are identified, and the main
* verb's conjugation is completed.</p>
*
* <p>However, as the perfect tense is a composite, we also have to conjugate
* the auxiliary verb. Flow begins in the model auxiliary verb - in this instance,
* Avoir. Finding no rules for the perfect in Avoir or its parent Auxiliary, we
* move to Root. However, while we are searching for rules for the perfect,
* as we are trying to conjugate an auxiliary, normal references (such as the
* one followed from the perfect to the past participle) are not applicable.
* Instead, we find and use an <em>auxiliary reference</em>. For the perfect
* tense, Root defines an auxiliary reference to the present tense. Hence, we
* return to Avoir, but now searching for present tense rules. The suffix is found
* in Avoir; the stem and infix, in Root.</p>
*
* <p>Multiple inheritance is supported between model verbs. Where multiple parents
* exist, each parent is searched in order for relevant rules. The search does not
* end when a match is found; rather, it continues to search the other parents, in
* case a <em>more specific</em> rule is found. A given rule R, belonging to model
* verb M, is considered to be 'more specific' than some other rule S belonging
* to model verb N if M is an ancestor of N. If two equally relevant rules are
* found, the first is used. It is recommended that in order to develop maintainable
* model verb trees, where multiple inheritance is used, most parents should be
* lightweight in terms of rules and their place in the inheritance hierarchy.
* This helps minimise difficult-to-diagnose specificity issues.</p>
*
* <h1>Conjugation Rules</h1>
*
* <p>There are three supported types of conjugation rule.</p>
*
* <table border="1">
* <tr><th>Type</th> <th>Description</th> </tr>
* <tr><td>Segment definitions</td> <td>Defines stems, infixes and suffixes.</td> </tr>
* <tr><td>References</td> <td>Defines links between tenses and forms.</td> </tr>
* <tr><td>Auxiliary references</td> <td>Defines links between tenses and forms for auxiliaries.</td></tr>
* </table>
*
* <h2>Segment Definitions</h2>
*
* <p>The simplest segment definitions are plain text strings, indicating the inflection to be used. However,
* there are three sorts of 'marker' that can be included, all of which are resolved
* by this class when conjugating a verb.</p>
*
* <table border="1">
* <tr><th>Marker</th> <th>Description</th> </tr>
* <tr><td><parent/></td><td>Replaced with a parent's form.</td> </tr>
* <tr><td>\<em>X</em></td> <td>Replaced with capture group <em>X</em> if the infinitive was matched using a regular expression.</td> </tr>
* <tr><td>[-+]<em>N</em></td> <td>Replaced with the last <em>N</em> characters of the infinitive, if negative; or the first <em>N</em>, if positive. 0 refers to the entire infinitive.</td> </tr>
* </table>
*
* <p><parent/> markers are useful where a model needs to append or prepend
* some text on to an inherited form. For instance, the French model verb Cer defines
* the singular forms of the historic tense as '�<parent/>' - a single common rule,
* to avoid repeating the form found in the parent, Er ('a'). In this instance, the
* resultant text would be '�a'.</p>
*
* <p>Regular expression capture group markers
* allow one to cover a wider array of infinitives in a single model verb, often
* using fewer rule definitions. For instance, using these markers, the English
* verbs 'buy', 'bring' and 'think' can be covered by a single model: their preterite
* forms (bought, brought and thought, respectively) can be expressed using the
* expression '\1ought', if the infinitives are matched with capture groups
* around the initial consonants of the infinitive.</p>
*
* <p>Finally, substring references are a heavily used mechanism that allows one to
* cover a wider range of infinitives in a single model: if the Root node defines the stem
* of a verb as all but the last two letters of the infinitive ('-2'), this will avoids
* individually stating the stem for each infinitive.</p>
*
* <p><strong>Notes</strong>:
* <ul>
* <li>Segment definition rules take precedence over references: if a model verb
* contains both for a given tense and form, the definition rule is followed.</li>
* <li>The pronoun text itself is not determined using the model verb tree - it
* is included in the diagrams for context only.</li>
* <li>A fourth segment is available - the prefix. This is excluded from the discussion
* above for simplicity as it is rarely used.</li>
* </ul>
*
* @author Duncan Roberts
*/
public class ModelVerb implements ReferenceData<ModelVerb> {
private static final Map<Language, Map<String, ModelVerb>> INSTANCES = new HashMap<Language, Map<String, ModelVerb>>();
private final Map<String, ConjugatedVerb> conjugatedVerbs = new HashMap<String, ConjugatedVerb>();
private String name;
private final List<ModelVerb> parents = new ArrayList<ModelVerb>();
private final List<WordMatcher> infinitiveMatchers;
private Map<Tense, Map<FormCategory, Map<Segment, String>>> tenseMap =
new HashMap<Tense, Map<FormCategory, Map<Segment, String>>>();
private Map<Tense, Map<FormCategory, Map<Segment, Tense>>> refTenseMap =
new HashMap<Tense, Map<FormCategory, Map<Segment, Tense>>>();
private Map<Tense, Map<FormCategory, Map<Segment, FormCategory>>> refPronounMap =
new HashMap<Tense, Map<FormCategory, Map<Segment, FormCategory>>>();
private Map<Tense, Map<FormCategory, Map<Segment, Tense>>> auxiliaryRefTenseMap =
new HashMap<Tense, Map<FormCategory, Map<Segment, Tense>>>();
private Map<Tense, Map<FormCategory, Map<Segment, FormCategory>>> auxiliaryRefPronounMap =
new HashMap<Tense, Map<FormCategory, Map<Segment, FormCategory>>>();
private String summary;
private Language language;
public ModelVerb(Language language, String name, List<ModelVerb> parents,
List<WordMatcher> infinitiveMatchers,
Map<Tense, Map<FormCategory, Map<Segment, String>>> tenseMap,
Map<Tense, Map<FormCategory, Map<Segment, Tense>>> refTenseMap,
Map<Tense, Map<FormCategory, Map<Segment, FormCategory>>> refPronounMap,
Map<Tense, Map<FormCategory, Map<Segment, Tense>>> auxiliaryRefTenseMap,
Map<Tense, Map<FormCategory, Map<Segment, FormCategory>>> auxiliaryRefPronounMap,
String summary) {
this.name = name;
this.language = language;
this.parents.addAll(parents);
this.infinitiveMatchers = infinitiveMatchers;
this.tenseMap = tenseMap;
this.refTenseMap = refTenseMap;
this.refPronounMap = refPronounMap;
this.auxiliaryRefTenseMap = auxiliaryRefTenseMap;
this.auxiliaryRefPronounMap = auxiliaryRefPronounMap;
this.summary = summary;
Map<String, ModelVerb> insts = Utilities.initialiseIfReqd(language, INSTANCES);
insts.put(Utilities.asConstantName(name), this);
}
public static ModelVerb[] values(Language language) {
try {
ReferenceDataCategory.MODEL_VERB.load(language);
}
catch (IOException ioe) {
throw new RuntimeException(ioe);
}
return INSTANCES.get(language).values().toArray(new ModelVerb[] {});
}
public static ModelVerb valueOf(Language language, String name) {
try {
ReferenceDataCategory.MODEL_VERB.load(language);
}
catch (IOException ioe) {
throw new RuntimeException(ioe);
}
ModelVerb mv = INSTANCES.get(language).get(Utilities.asConstantName(name));
if (mv == null)
throw new IllegalArgumentException("No ModelVerb with name '"+name+"'.");
return mv;
}
public int ordinal() {
return name.hashCode(); // TODO replace with sensible implementation
}
public int compareTo(ModelVerb mv) {
return ordinal() - mv.ordinal();
}
public List<ModelVerb> getParents() {
return Collections.unmodifiableList(parents);
}
public int getDepth() {
if (parents.size() == 0)
return 0;
return parents.get(0).getDepth()+1;
}
public Language getLanguage() {
return language;
}
public boolean matches(String infinitive, boolean reflexive) {
try {
getInfinitiveMatcher(infinitive, reflexive);
return true;
}
catch (IllegalArgumentException e) {
return false;
}
}
public List<WordMatcher> getInfinitiveMatchers() {
return infinitiveMatchers;
}
public WordMatcher getInfinitiveMatcher(String infinitive, boolean reflexive) {
//System.err.println("ModelVerb.getInfinitiveMatcher(S,b):"+new Date());
// System.out.println("ModelVerb.getInfinitiveMatcher(): "+infinitive);
for (WordMatcher im : infinitiveMatchers) {
MatchType matchType = im.getMatchType();
switch (matchType) {
case FULL_NAME:
if (infinitive.equalsIgnoreCase(im.getMatchString()))
return im;
break;
case SUFFIX:
if (infinitive.endsWith(im.getMatchString()))
return im;
break;
case PATTERN:
if (infinitive.matches(im.getMatchString()))
return im;
break;
case ALL:
return im;
case NONE:
return im;
default:
throw new Error("Invalid match type: "+im.getMatchType());
}
}
throw new IllegalArgumentException(infinitive+" does not match model verb "+name);
}
private int getMatchStringPointsValue(WordMatcher infinitiveMatcher) {
if (infinitiveMatcher.getMatchType() == MatchType.PATTERN) {
String points = infinitiveMatcher.getMatchString().replaceAll("\\[.+\\]", "[");
points = points.replaceAll("\\(\\.\\*\\)", "");
points = points.replaceAll("[()+*]", "");
return points.length();
}
else if (infinitiveMatcher.getMatchType() == MatchType.SUFFIX) {
return infinitiveMatcher.getMatchString().length();
}
else throw new Error();
}
public boolean isCloserMatch(String infinitive, boolean reflexive, ModelVerb other) {
//System.err.println("ModelVerb.isCloserMatch():"+new Date());
if (isDescendantOf(other))
return true;
WordMatcher infinitiveMatcher;
try {
infinitiveMatcher = getInfinitiveMatcher(infinitive, reflexive);
}
catch (IllegalArgumentException iae) {
return false;
}
WordMatcher otherMatcher;
try {
otherMatcher = other.getInfinitiveMatcher(infinitive, reflexive);
}
catch (IllegalArgumentException iae) {
return true;
}
if ((infinitiveMatcher.getMatchType() == MatchType.PATTERN || infinitiveMatcher.getMatchType() == MatchType.SUFFIX) &&
(otherMatcher.getMatchType() == MatchType.PATTERN || otherMatcher.getMatchType() == MatchType.SUFFIX)) {
return getMatchStringPointsValue(infinitiveMatcher) >
getMatchStringPointsValue(otherMatcher);
}
if (infinitiveMatcher.getMatchType() != otherMatcher.getMatchType())
return infinitiveMatcher.getMatchType().ordinal() > otherMatcher.getMatchType().ordinal();
return false;
}
private boolean isDescendantOf(ModelVerb other) {
//System.err.println("ModelVerb.isDescendantOf():"+new Date());
for (ModelVerb p : parents) {
//if (p == null || getName().equals(other.getName()))
// return false;
if (p.getName().equals(other.getName()))
return true;
if (p.isDescendantOf(other))
return true;
}
return false;
}
public FormCategory[] getForms(Tense tense) {
Map<FormCategory, Map<Segment, Tense>> m = refTenseMap.get(tense);
if (m != null)
return new TreeSet<FormCategory>(m.keySet()).toArray(new FormCategory[]{});
for (ModelVerb parent : parents) {
FormCategory[] s = parent.getForms(tense);
if (s != null)
return s;
}
return new TreeSet<FormCategory>().toArray(new FormCategory[]{});
}
// State variables used internally by getText() only.
private transient static ModelVerb sourceModelVerb = null;
private transient static ModelVerb sourceRedirectionModelVerb = null;
private transient static ModelVerb invokedModelVerb = null;
/**
* Retrieves the appropriate text for the specified segment of a given tense
* of a verb.
*
* @param tense
* @param conjugatedVerb
* @param pronounCategory
* @param segment
* @param auxiliary
* @return
*/
public String getText(Tense tense, ConjugatedVerb conjugatedVerb, FormCategory pronounCategory, Segment segment, boolean auxiliary) {
invokedModelVerb = this;
String processedSegmentText = getRawSegmentText(tense, pronounCategory, segment, this, auxiliary);
if (processedSegmentText == null)
return processedSegmentText;
String verb = conjugatedVerb.getVerb();
boolean reflexive = conjugatedVerb.isReflexive();
if (getInfinitiveMatcher(verb, reflexive).getMatchType() == MatchType.PATTERN) {
String regex = getInfinitiveMatcher(verb, reflexive).getMatchString();
// processedSegmentText = getText(tense, conjugatedVerb, pronounCategory, Segment.STEM, auxiliary);
Pattern p2 = Pattern.compile(regex);
Matcher m2 = p2.matcher(verb);
if (!m2.matches())
throw new IllegalArgumentException("Infinitive doesn't match model verb pattern!");
for (int i = 1; i <= m2.groupCount(); i++) {
String g = m2.group(i);
processedSegmentText = processedSegmentText.replace("\\"+i, g);
}
}
Pattern p1 = Pattern.compile(".*?(-?[0-9]+).*");
Matcher m1 = p1.matcher(processedSegmentText);
if (m1.matches()) {
String infinitiveSegment = m1.group(1);
int stemSize = Integer.parseInt(infinitiveSegment);
String replacement;
if (stemSize > 0)
replacement = verb.substring(0, stemSize);
else if (stemSize < 0)
replacement = verb.substring(0, verb.length()+stemSize);
else // stemSize == 0
replacement = verb;
processedSegmentText = processedSegmentText.replace(infinitiveSegment, replacement);
}
return processedSegmentText;
}
/**
* Traverses the model verb hierarchy to find the appropriate segment text,
* without resolving regular expression capture group references or substring
* markers. Inheritance markers (<parent/>) are, however, resolved.
*
* @param tense The tense to look for rules for.
* @param pronounCategory The class of the form that the segment is being retrieved for.
* @param segment The segment to be resolved.
* @param modelVerb The model verb to derive rules for.
* @param auxiliary If true, auxiliary reference rules will be followed
* rather than standard reference rules.
* @return The segment's raw text.
*/
private static String getRawSegmentText(Tense tense, FormCategory pronounCategory, Segment segment, ModelVerb modelVerb, boolean auxiliary) {
String form = null;
if (!auxiliary) {
try { // 1. Check for rule for this tense.
form = modelVerb.tenseMap.get(tense).get(pronounCategory).get(segment); // will throw NullPointerException if no rule in this model verb
if (form != null)
sourceModelVerb = modelVerb;
if (form.contains("<parent />")) {
for (ModelVerb parentModelVerb : modelVerb.parents) {
ModelVerb mv = sourceModelVerb; // 'backup' variable
String inheritedForm = getRawSegmentText(tense, pronounCategory, segment, parentModelVerb, false);
sourceModelVerb = mv; // restore value as it's this form (containing <parent/>) that we're interested in.
if (inheritedForm != null) {
form = form.replace("<parent />", inheritedForm);
break;
}
}
form = form.replace("<parent />", ""); // if there's nothing to inherit, remove this flag
}
return form;
}
catch (NullPointerException npe) {
// Legitimate; query other sources (references to other tenses; parents) for rule instead.
}
}
if (form == null) { // 2. Check for links to other tenses.
try {
Map<Tense, Map<FormCategory, Map<Segment, Tense>>> tm =
auxiliary ? modelVerb.auxiliaryRefTenseMap : modelVerb.refTenseMap;
Map<Tense, Map<FormCategory, Map<Segment, FormCategory>>> pm =
auxiliary ? modelVerb.auxiliaryRefPronounMap : modelVerb.refPronounMap;
Tense targetTense = tm.get(tense).get(pronounCategory).get(segment);
FormCategory targetPronounCategory = pm.get(tense).get(pronounCategory).get(segment);
if (targetTense == null)
targetTense = getTargetTense(modelVerb, tense, pronounCategory, segment);
if (targetPronounCategory == null)
targetPronounCategory = getTargetPronounCategory(modelVerb, tense, pronounCategory, segment);
if (targetTense != tense || targetPronounCategory != pronounCategory) {
sourceRedirectionModelVerb = modelVerb;
form = getRawSegmentText(targetTense, targetPronounCategory, segment, invokedModelVerb, false);
}
}
catch (NullPointerException npe) {
// Legitimate
}
}
if (form == null) { // 3. Recursively check parents for rules.
ModelVerb closestMatch = null;
ModelVerb closestRedirectionMatch = null;
for (ModelVerb parentModelVerb : modelVerb.parents) {
String formTmp = getRawSegmentText(tense, pronounCategory, segment, parentModelVerb, auxiliary);
if (formTmp != null) {
boolean closer = false;
if (sourceModelVerb == null) {
closer = true;
}
else if (closestMatch == null) {
closer = true;
}
else if (sourceRedirectionModelVerb != null) {
if (closestRedirectionMatch != null) {
if (sourceRedirectionModelVerb.isDescendantOf(closestRedirectionMatch)) {
closer = true;
}
else if (sourceRedirectionModelVerb.equals(closestRedirectionMatch)) {
if (sourceModelVerb.isDescendantOf(closestMatch))
closer = true;
}
}
else {
closer = true;
}
}
else {
if (closestRedirectionMatch != null) {
closer = true;
}
else {
if (sourceModelVerb.isDescendantOf(closestMatch))
closer = true;
}
}
if (closer) {
closestRedirectionMatch = sourceRedirectionModelVerb;
closestMatch = sourceModelVerb;
form = formTmp;
}
}
}
}
return form;
}
private static FormCategory getTargetPronounCategory(
ModelVerb modelVerb, Tense tense, FormCategory pronounCategory,
Segment segment) {
try {
FormCategory targetPronounCategory = modelVerb.refPronounMap.get(tense).get(pronounCategory).get(segment);
if (targetPronounCategory != null)
return targetPronounCategory;
}
catch (NullPointerException npe) {
// Legitimate
}
for (ModelVerb parent : modelVerb.parents) {
FormCategory targetPronounCategory =
getTargetPronounCategory(parent, tense, pronounCategory, segment);
if (targetPronounCategory != null)
return targetPronounCategory;
}
return null;
}
private static Tense getTargetTense(
ModelVerb modelVerb, Tense tense, FormCategory pronounCategory,
Segment segment) {
try {
Tense targetTense = modelVerb.refTenseMap.get(tense).get(pronounCategory).get(segment);
if (targetTense != null)
return targetTense;
}
catch (NullPointerException npe) {
// Legitimate
}
for (ModelVerb parent : modelVerb.parents) {
Tense targetTense = getTargetTense(parent, tense, pronounCategory, segment);
if (targetTense != null)
return targetTense;
}
return null;
}
public ConjugatedVerb getConjugatedVerb(String infinitive) {
/*try {
ReferenceDataCategory.VERB.load(language);
}
catch (IOException ioe) {
throw new RuntimeException(ioe);
}*/
//System.err.println("ModelVerb.getConjugatedVerb():"+new Date());
if (conjugatedVerbs.containsKey(infinitive))
return conjugatedVerbs.get(infinitive);
ConjugatedVerb c = new ConjugatedVerb(infinitive, this);
// int l1 = conjugatedVerbs.size();
conjugatedVerbs.put(infinitive, c);
// int l2 = conjugatedVerbs.size();
//System.err.println("ModelVerb.getConjugatedVerb() #2 ("+l1+","+l2+","+(l1==l2)+"):"+new Date());
return c;
}
public ConjugatedVerb getConjugatedVerb(String infinitive, Set<VerbTag> classifications) {
try {
ReferenceDataCategory.VERB.load(language);
}
catch (IOException ioe) {
throw new RuntimeException(ioe);
}
ConjugatedVerb c = new ConjugatedVerb(infinitive, this, classifications);
conjugatedVerbs.put(infinitive, c);
return c;
}
public Set<ConjugatedVerb> getConjugatedVerbs(boolean includeInherited, boolean includeSelf) {
try {
ReferenceDataCategory.VERB.load(language);
}
catch (IOException ioe) {
throw new RuntimeException(ioe);
}
Set<ConjugatedVerb> s = new HashSet<ConjugatedVerb>();
if (includeInherited) {
// TODO doesn't look recursive - surely this doesn't include 'grandchildren'?
for (ModelVerb mv : INSTANCES.get(language).values()) {
if (mv.isDescendantOf(this)) {
s.addAll(mv.conjugatedVerbs.values());
}
}
}
if (includeSelf) {
s.addAll(conjugatedVerbs.values());
}
return s;
}
public Set<ConjugatedVerb> getConjugatedVerbs() {
return getConjugatedVerbs(false, true);
}
public static class ConjugatedVerb implements Comparable<ConjugatedVerb> {
private static final Map<Language, Map<String, ConjugatedVerb>> INSTANCES =
new HashMap<Language, Map<String, ConjugatedVerb>>();
private final String infinitive;
private final String verb;
private final ModelVerb modelVerb;
private final AuxiliaryVerb auxiliary;
private final Set<VerbTag> classifications;
private boolean reflexive;
private ConjugatedVerb(String infinitive, ModelVerb modelVerb) {
this(infinitive, modelVerb, new HashSet<VerbTag>());
}
private ConjugatedVerb(String infinitive, ModelVerb modelVerb, Set<VerbTag> classifications) {
//System.err.println("new ConjugatedVerb(S,MV,Svt):"+new Date());
this.modelVerb = modelVerb;
reflexive = modelVerb.getLanguage().isReflexive(infinitive);
auxiliary = ModelVerbFactory.getInstance(modelVerb.getLanguage()).getModelAuxiliaryVerb(infinitive, reflexive);
this.classifications = classifications;
this.infinitive = infinitive;
this.verb = reflexive ? modelVerb.getLanguage().stripReflexiveMarker(infinitive) : infinitive;
// if (!DataManager.getInstance(modelVerb.getLanguage()).isLoaded()) {
Utilities.initialiseIfReqd(modelVerb.getLanguage(), INSTANCES).put(infinitive, this);
// }
}
public String getVerb() {
return verb;
}
public Set<VerbTag> getClassifications() {
return classifications;
}
public static ConjugatedVerb[] values(Language language) {
try {
ReferenceDataCategory.VERB.load(language);
}
catch (IOException ioe) {
throw new RuntimeException(ioe);
}
if (INSTANCES.get(language) == null)
throw new InsufficientReferenceDataException(
language, ReferenceDataCategory.VERB, 1, 0);
return INSTANCES.get(language).values().toArray(new ConjugatedVerb[] {});
}
public static ConjugatedVerb valueOf(Language language, String name) {
try {
ReferenceDataCategory.VERB.load(language);
}
catch (IOException ioe) {
throw new RuntimeException(ioe);
}
ConjugatedVerb mv = INSTANCES.get(language).get(name);
if (mv == null)
throw new IllegalArgumentException("No conjugated verb with name '"+name+"'.");
return mv;
}
public String getForm(Tense tense, Form form) {
//System.err.println("ConjugatedVerb.getForm():"+new Date());
return new Conjugation(tense, form, this, false).inflect();
}
public AuxiliaryVerb getAuxiliary() {
return auxiliary;
}
public String toString() {
return infinitive;
}
public ModelVerb getModelVerb() {
return modelVerb;
}
public String getInfinitive() {
return infinitive;
}
@Override
public int hashCode() {
return infinitive.toUpperCase().hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ModelVerb))
return false;
return infinitive.equalsIgnoreCase(((ConjugatedVerb) obj).infinitive);
}
@Override
public int compareTo(ConjugatedVerb o) {
return infinitive.compareTo(o.infinitive);
}
public boolean isReflexive() {
return reflexive;
}
}
public boolean equals(ModelVerb mv) {
return this.name.equals(mv.name);
}
public String getName() {
return name;
}
public String toString() {
return name;
}
public String getSummary() {
return summary;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((language == null) ? 0 : language.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof ModelVerb))
return false;
final ModelVerb other = (ModelVerb) obj;
if (language == null) {
if (other.language != null)
return false;
} else if (!language.equals(other.language))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}