code: package caevo.sieves;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.List;
  
  import caevo.SieveDocument;
  import caevo.SieveDocuments;
  import caevo.SieveSentence;
  import caevo.TextEvent;
  import caevo.tlink.EventEventLink;
  import caevo.tlink.TLink;
  import caevo.util.CaevoProperties;
  import caevo.util.TimebankUtil;
  import caevo.util.TreeOperator;
  import edu.stanford.nlp.trees.Tree;
  import edu.stanford.nlp.trees.TypedDependency;
  
  /**
   * This sieve deals with event pairs in various dependency relationships. It
   * looks for two events where a single dependency relation connects them.
   * Various methods handle the different relations: xcomp, ccomp, nsubj, dep,
   * etc.
   * 
   * CURRENT STATUS outputs information: for each event pair where one governs the
   * other via xcomp, print out stats. TODO double check that the printout has
   * correct relation direction for all cases TODO change so taht all dependencies
   * are detected, and the label is just part of the printout TODO tweak features
   * that are printed out; e.g. at least print out the lemma of the word anything
   * else?
   * 
   * 
   * 07/15/2013 train: XCompDepSieve p=0.68 111 of 164 Non-VAGUE: p=0.80 111 of
   * 138 dev: XCompDepSieve p=0.70 21 of 30 Non-VAGUE: p=0.78 21 of 27
   * 
   * 07/16/2013 (after the // is after adding the case "else --> AFTER" for ccomp
   * train: XCompDepSieve p=0.71 127 of 180 Non-VAGUE: p=0.84 127 of 152 //
   * XCompDepSieve p=0.59 148 of 249 Non-VAGUE: p=0.74 148 of 200 dev:
   * XCompDepSieve p=0.59 17 of 29 Non-VAGUE: p=0.68 17 of 25 // XCompDepSieve
   * p=0.68 36 of 53 Non-VAGUE: p=0.80 36 of 45
   * 
   * parameter useExtendedTense onyl applies to ccomp right now.
   * 
   * 07/23/2013 train p=0.68 163 of 241 Non-VAGUE: p=0.79 163 of 206 dev p=0.63 34
   * of 54 Non-VAGUE: p=0.77 34 of 44
   * 
   * 07/24/2013 train: extended future: XCompDepSieve p=0.67 209 of 311 Non-VAGUE:
   * p=0.81 209 of 259 without: p=0.68 199 of 294 Non-VAGUE: p=0.81 199 of 247
   * dev: extended future: XCompDepSieve p=0.63 37 of 59 Non-VAGUE: p=0.76 37 of
   * 49 without: p=0.63 37 of 59 Non-VAGUE: p=0.76 37 of 49
   * 
   * 
   * 
   * @author cassidy
   */
  public class XCompDepSieve implements Sieve {
    public boolean debug = false;
    private boolean useExtendedTense = true;
  
    /**
     * The main function. All sieves must have this.
     */
    public List<TLink> annotate(SieveDocument doc, List<TLink> currentTLinks) {
      try {
        useExtendedTense = CaevoProperties
            .getBoolean("XCompDepSieve.useExtendedTense", true);
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      // End properties code
  
      // Sieve Code
  
      // Fill this with our new proposed TLinks.
      List<TLink> proposed = new ArrayList<TLink>();
  
      // Get the list of sentences and parse trees for the document
      List<SieveSentence> sents = doc.getSentences();
      List<Tree> trees = doc.getAllParseTrees();
  
      // For each sentence, send its events and dependencies to applySieve, which
      // finds pairs of events where one event governs the other, and checks them
      // against
      // criteria in terms of additional properties of both events as well as
      // their dependency relation.
      for (SieveSentence sent : sents) {
        // Get the list of events and list of deps for the sentence
        List<TextEvent> events = sent.events();
        List<TypedDependency> deps = sent.getDeps();
        // Iterate over event pairs and determine if one governs the other;
        // if so, try to classify the pair.
        for (int xx = 0; xx < events.size(); xx++) {
          TextEvent e1 = events.get(xx);
          for (int yy = xx + 1; yy < events.size(); yy++) {
            TextEvent e2 = events.get(yy);
            // check if the two events are in a dependency relation and label them
            // accordingly.
            for (TypedDependency td : deps) {
              // if e1 governs e2 (or vice versa)
              TextEvent eGov = null;
              TextEvent eDep = null;
              // Does e1 govern e1?
              if (e1.getIndex() == td.gov().index()
                  && e2.getIndex() == td.dep().index()) {
                eGov = e1;
                eDep = e2;
              }
              // Does e2 govern e1?
              else if (e2.getIndex() == td.gov().index()
                  && e1.getIndex() == td.dep().index()) {
                eGov = e2;
                eDep = e1;
              }
              // If neither event governs the other, keep iterating.
              else {
                continue;
              }
  
              // Get rel type for the dependency, and apply rules accordingly.
              String relType = td.reln().toString();
  
              EventEventLink tlink = null;
  
              if (relType.equals("xcomp")) {
                // p=0.69 69 of 100 Non-VAGUE: p=0.87 69 of 79
                tlink = classifyEventPair_xcomp(eGov, eDep, sent);
              }
              if (relType.equals("ccomp")) {
                // p=0.71 70 of 99 Non-VAGUE: p=0.85 70 of 82
                tlink = classifyEventPair_ccomp(eGov, eDep, sent, deps);
              }
              if (relType.equals("conj_and")) {
                // p=0.69 24 of 35 Non-VAGUE: p=0.69 24 of 35
                tlink = classifyEventPair_conj_and(eGov, eDep, sent);
              }
              if (relType.equals("nsubj")) {
                // p=0.52 13 of 25 Non-VAGUE: p=0.62 13 of 21
                tlink = classifyEventPair_nsubj(eGov, eDep, sent);
              }
              if (relType.equals("advcl")) {
                // p=0.65 15 of 23 Non-VAGUE: p=0.71 15 of 21
                tlink = classifyEventPair_advcl(eGov, eDep, sent, deps);
              }
              if (relType.equals("conj_but")) {
                // p=0.50 7 of 14 Non-VAGUE: p=0.78 7 of 9
                tlink = classifyEventPair_conj_but(eGov, eDep, sent, deps);
              }
              if (relType.equals("conj_or")) {
                // p=0.67 2 of 3 Non-VAGUE: p=0.67 2 of 3
                tlink = classifyEventPair_conj_or(eGov, eDep, sent, deps);
              }
              if (relType.equals("dobj")) {
                // p=0.75 9 of 12 Non-VAGUE: p=1.00 9 of 9
                tlink = classifyEventPair_dobj(eGov, eDep, sent, deps);
              }
  
              if (tlink != null) {
                // boolean success = true;
                // try {
                // checkTLink(tlink, proposed);
                // }
                // catch (IllegalStateException E) {
                // success = false;
                // if (debug) {
                // System.out.printf("Tried to add tlink for pair: (%s[%s],
                // %s[%s]), but link is already proposed",
                // eGov.getId(), eGov.getEiid(), eDep.getId(), eDep.getEiid() );
                // }
                // }
                // finally {
                // if (success)
  
                proposed.add(tlink);
                // }
              }
            }
          }
        }
      }
  
      if (debug == true) {
        System.out.println("TLINKS: " + proposed);
      }
      return proposed;
    }
  
    private EventEventLink classifyEventPair_conj_or(TextEvent eGov,
        TextEvent eDep, SieveSentence sent, List<TypedDependency> deps) {
      return new EventEventLink(eGov.getEiid(), eDep.getEiid(), TLink.Type.VAGUE);
    }
  
    private EventEventLink classifyEventPair_dobj(TextEvent eGov, TextEvent eDep,
        SieveSentence sent, List<TypedDependency> deps) {
      TextEvent.Class eGovClass = eGov.getTheClass();
      TextEvent.Tense eDepTense = eDep.getTense();
      TextEvent.Aspect eDepAspect = eDep.getAspect();
  
      if (eGovClass == TextEvent.Class.ASPECTUAL) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.IS_INCLUDED);
      } else if (eDepTense == TextEvent.Tense.NONE
          && eDepAspect == TextEvent.Aspect.NONE) {
        for (TypedDependency td : deps) {
          if (td.gov().index() == eDep.getIndex()
              && td.reln().toString().toLowerCase().equals("det")) {
            if (td.dep().toString("value").toLowerCase().equals("a")) {
              return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
                  TLink.Type.BEFORE);
            }
            // if (td.dep().toString("value").toLowerCase().equals("the")) { //
            // how can we differentiate between AFTER and IS_INCLUDED?
            // return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            // TLink.Type.AFTER);
            // }
          }
        }
      } else {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.VAGUE);
      }
      return null;
    }
  
    private EventEventLink classifyEventPair_conj_but(TextEvent eGov,
        TextEvent eDep, SieveSentence sent, List<TypedDependency> deps) {
      return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
          TLink.Type.BEFORE);
    }
  
    private EventEventLink classifyEventPair_advcl(TextEvent eGov, TextEvent eDep,
        SieveSentence sent, List<TypedDependency> deps) {
      // Find the "marker" (i.e. the word that introduces the adverbial clause
      // complement (i.e. the dependent)).
      String mark = null;
      for (TypedDependency td : deps) {
        String rel = td.reln().toString();
        if (td.gov().index() == eDep.getIndex()) {
          if (rel.equals("mark")) { // sometimes advmod plays role of mark
            mark = td.dep().toString("value");
            if (debug)
              System.out.printf("\ngov:%s dep:%s mark:%s\n%s\n", eGov.getString(),
                  eDep.getString(), mark, sent.sentence());
          }
        }
      }
      if (mark == null) {
        for (TypedDependency td : deps) {
          String rel = td.reln().toString();
          if (td.gov().index() == eDep.getIndex()) {
            if (rel.equals("advmod")) { // sometimes advmod plays role of mark
              mark = td.dep().toString("value");
              if (debug)
                System.out.printf("\ngov:%s dep:%s mark:%s\n%s\n",
                    eGov.getString(), eDep.getString(), mark, sent.sentence());
            }
          }
        }
      }
  
      // Apply rules
  
      if (mark != null && mark.toLowerCase().equals("until")) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.BEFORE);
      }
      if (mark != null && mark.toLowerCase().equals("once")) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.AFTER);
      }
      if (mark != null && mark.toLowerCase().equals("after")) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.AFTER);
      }
      if (mark != null && mark.toLowerCase().equals("before")) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.BEFORE);
      }
      if (mark != null && mark.toLowerCase().equals("since")) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.AFTER);
      }
      if (mark != null && mark.toLowerCase().equals("when")) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.VAGUE);
      }
      if (mark != null && mark.toLowerCase().equals("as")) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.SIMULTANEOUS);
      }
      if (mark != null && mark.toLowerCase().equals("because")) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.BEFORE);
      } else {
        // return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
        // TLink.Type.VAGUE);
        return null;
      }
    }
  
    private EventEventLink classifyEventPair_nsubj(TextEvent eGov, TextEvent eDep,
        SieveSentence sent) {
      TextEvent.Class eGovClass = eGov.getTheClass();
      if (eGovClass == TextEvent.Class.ASPECTUAL) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.IS_INCLUDED);
      }
      return new EventEventLink(eGov.getEiid(), eDep.getEiid(), TLink.Type.VAGUE);
    }
  
    private EventEventLink classifyEventPair_conj_and(TextEvent eGov,
        TextEvent eDep, SieveSentence sent) {
      return new EventEventLink(eGov.getEiid(), eDep.getEiid(), TLink.Type.VAGUE);
    }
  
    private EventEventLink classifyEventPair_xcomp(TextEvent eGov, TextEvent eDep,
        SieveSentence sent) {
      TextEvent.Tense eGovTense = eGov.getTense();
      TextEvent.Tense eDepTense = eDep.getTense();
      TextEvent.Class eDepClass = eDep.getTheClass();
      TextEvent.Class eGovClass = eGov.getTheClass();
      TextEvent.Aspect eDepAspect = eDep.getAspect();
      String govStr = eGov.getString();
      String depStr = eDep.getString();
  
      if (eDepTense == TextEvent.Tense.PRESPART)
        if (eGovClass == TextEvent.Class.OCCURRENCE) {
          return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
              TLink.Type.SIMULTANEOUS);
        } else {
          return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
              TLink.Type.IS_INCLUDED);
        }
      else if (eGovClass == TextEvent.Class.ASPECTUAL) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.IS_INCLUDED);
      } else
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.BEFORE);
  
    }
  
    private EventEventLink classifyEventPair_ccomp(TextEvent eGov, TextEvent eDep,
        SieveSentence sent, List<TypedDependency> deps) {
      TextEvent.Tense eDepTense = null;
      TextEvent.Tense eGovTense = null;
      if (useExtendedTense == true) {
        eGovTense = TimebankUtil.pseudoTense(sent, deps, eGov);
        eDepTense = TimebankUtil.pseudoTense(sent, deps, eDep);
      } else {
        eGovTense = eGov.getTense();
        eDepTense = eDep.getTense();
      }
      TextEvent.Class eDepClass = eDep.getTheClass();
      TextEvent.Class eGovClass = eGov.getTheClass();
      TextEvent.Aspect eDepAspect = eDep.getAspect();
      TextEvent.Aspect eGovAspect = eGov.getAspect();
      String govStr = eGov.getString();
      String depStr = eDep.getString();
  
      if (eDepTense == TextEvent.Tense.FUTURE) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.BEFORE);
      } else if (eDepAspect == TextEvent.Aspect.PERFECTIVE) {
        if (eGovAspect == TextEvent.Aspect.NONE)
          return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
              TLink.Type.AFTER);
        else if (eGovTense == TextEvent.Tense.PAST)
          return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
              TLink.Type.AFTER);
        else if (eGovClass == TextEvent.Class.REPORTING)
          return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
              TLink.Type.AFTER);
        else if (eDepClass == TextEvent.Class.OCCURRENCE)
          return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
              TLink.Type.AFTER);
      } else if (eGovAspect == TextEvent.Aspect.PERFECTIVE) {
        return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
            TLink.Type.VAGUE);
      } else if (eDepTense == TextEvent.Tense.PAST) {
        if (eGovTense == TextEvent.Tense.PAST) {
          if (eGovAspect == TextEvent.Aspect.NONE
              && eDepAspect == TextEvent.Aspect.NONE) {
            return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
                TLink.Type.AFTER);
          }
        }
      } else if (eDepTense == TextEvent.Tense.PRESENT) {
        if (eGovClass == TextEvent.Class.REPORTING) {
          return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
              TLink.Type.IS_INCLUDED);
        } else if ((eDepClass == TextEvent.Class.STATE
            || eDepClass == TextEvent.Class.I_STATE)
            && (eGovTense == TextEvent.Tense.PRESENT
                && eGovAspect == TextEvent.Aspect.PROGRESSIVE)) {
          return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
              TLink.Type.IS_INCLUDED);
        } else
          return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
              TLink.Type.VAGUE);
      }
      return null;
      // return new EventEventLink(eGov.getEiid(), eDep.getEiid(),
      // TLink.Type.AFTER);
      // else //commenting this out is great for the train set and terrible for
      // the dev set!
      // proposed.add(new EventEventLink(eGov.getEiid(), eDep.getEiid(),
      // TLink.Type.AFTER));
  
      // if (eGovTense == TextEvent.Tense.PAST && eGovAspect ==
      // TextEvent.Aspect.NONE &&
      // eDepTense == TextEvent.Tense.PAST && eDepAspect == TextEvent.Aspect.NONE
      // // || eDepAspect == TextEvent.Aspect.PERFECTIVE
      // && eDepClass == TextEvent.Class.OCCURRENCE) {
      // proposed.add(new EventEventLink(eGov.getEiid(), eDep.getEiid(),
      // TLink.Type.AFTER));
      // }
      // if (eGovTense == TextEvent.Tense.PAST && eGovAspect ==
      // TextEvent.Aspect.NONE &&
      // eDepTense == TextEvent.Tense.NONE && eDepAspect == TextEvent.Aspect.NONE
      // &&
      // eDepClass == TextEvent.Class.OCCURRENCE) {
      // proposed.add(new EventEventLink(eGov.getEiid(), eDep.getEiid(),
      // TLink.Type.BEFORE));
      //
      // }
      // else
      // proposed.add(new EventEventLink(eGov.getEiid(), eDep.getEiid(),
      // TLink.Type.AFTER)); // 32/114 = 28%
    }
  
    private String posTagFromTree(Tree sentParseTree, int tokenIndex) {
      String posTag = TreeOperator.indexToPOSTag(sentParseTree, tokenIndex);
      return posTag;
    }
  
    public void checkTLink(TLink tlink, List<TLink> proposed)
        throws IllegalStateException {
      int numTLinks = proposed.size();
      for (int t = 0; t < numTLinks; t++) {
        if (tlink.coversSamePair(proposed.get(t))) {
          throw new IllegalStateException(
              "Cannot add a tlink between a pair of events for which there is already a tlink in proposed");
        }
      }
    }
  
    /**
     * No training. Just rule-based.
     */
    public void train(SieveDocuments trainingInfo) {
      // no training
    }
  
  }
  