Package grammar.model.verbs

Source Code of grammar.model.verbs.ModelVerb$ConjugatedVerb

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>&lt;parent/&gt;</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>&lt;parent/&gt; 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;
  }
}
TOP

Related Classes of grammar.model.verbs.ModelVerb$ConjugatedVerb

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.