package caevo.sieves;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import caevo.SieveDocument;
import caevo.SieveDocuments;
import caevo.TextEvent;
import caevo.Timex;
import caevo.tlink.EventTimeLink;
import caevo.tlink.TLink;
import caevo.util.CaevoProperties;

/**
 * This sieve returns IS_INCLUDED for an event/timex pair of the form
 * (class=REPORTING, val=DCT') DCT' is DCT, truncated to the day granularity
 * (e.g. 1998-01-08T03:00 --> 1998-01-08)
 *
 *
 * 07/23/2013 There was a major bug here before; the many correct labels were
 * repeated. Recall is significantly lower now. train: includePresentRef = false
 * RepCreationDay p=0.84 16 of 19 Non-VAGUE: p=0.89 16 of 18 (consider tense and
 * aspect) RepCreationDay p=0.81 17 of 21 Non-VAGUE: p=0.89 17 of 19 (don't
 * consider tense and aspect) includePresentRef = true RepCreationDay p=0.79 19
 * of 24 Non-VAGUE: p=0.90 19 of 21 (consider tense and aspect) RepCreationDay
 * p=0.77 20 of 26 Non-VAGUE: p=0.91 20 of 22 (don't consider tense and aspect)
 * dev: (includePresentRef true or false) RepCreationDay p=1.00 1 of 1
 * Non-VAGUE: p=1.00 1 of 1
 *
 * 
 * @author cassidy
 */
public class RepCreationDay implements Sieve {
  public boolean debug = false;
  private int leftSentWindow = 0;
  private int rightSentWindow = 0;
  private boolean considerTA = true;
  private boolean includePresentRef = false;
  private static String creationTimeRegex = "(\\d{4}-\\d{2}-\\d{2}).*";
  private static Pattern creationTimePattern = Pattern
      .compile(creationTimeRegex);

  /**
   * The main function. All sieves must have this.
   */
  public List<TLink> annotate(SieveDocument doc, List<TLink> currentTLinks) {
    try {
      leftSentWindow = CaevoProperties.getInt("RepCreationDay.leftSentWindow",
          0);
      rightSentWindow = CaevoProperties.getInt("RepCreationDay.rightSentWindow",
          0);
      considerTA = CaevoProperties.getBoolean("RepCreationDay.considerTA",
          true);
      includePresentRef = CaevoProperties
          .getBoolean("RepCreationDay.includePresentRef", false);
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    // Sieve Code

    // Get list of events and timexes by sid; list of sentences
    List<List<TextEvent>> allEvents = doc.getEventsBySentence();
    List<List<Timex>> allTimexes = doc.getTimexesBySentence();

    // Fill this with our new proposed TLinks.
    List<TLink> proposed = new ArrayList<TLink>();

    // get list of DCT timexes - normally 1, sometimes < > 1
    List<Timex> dctTimexes = doc.getDocstamp();
    Timex dctTimex;
    if (dctTimexes != null && dctTimexes.size() == 1) {
      dctTimex = dctTimexes.get(0);
    }

    // if we don't know the DCT the sieve won't work!
    // we could use the most common date...
    else if (dctTimexes == null || dctTimexes.size() == 0) {
      return proposed;
    }

    // if there is more than one DCT, how do we choose?
    // a better solution may be to go with whichever is mentioned the most,
    // followed by whichever appears first in the document, or vice versa
    else {
      // for now just use the first one in the list
      dctTimex = dctTimexes.get(0);
    }

    // extract the date of the document creation time
    String dcd = getDocCreationDate(dctTimex);
    if (debug == true) {
      System.out.println("INFO:" + doc.getDocname() + ":" + dcd);
    }

    // check timexes/event pairs in each sentence against sieve criteria.
    int numSents = allTimexes.size();
    for (int sid = 0; sid < numSents; sid++) {
      for (Timex timex : allTimexes.get(sid)) {
        // only proceed if timex is valid (according to parameters)
        if (!validateTimex(timex, dcd))
          continue;
        // Look at events in sentences whose sid are within the sent window
        // (according to parameters)
        for (int sid2 = Math.max((sid - this.leftSentWindow),
            0); sid2 < numSents
                && sid2 <= (sid + this.rightSentWindow); sid2++) {
          for (TextEvent event : allEvents.get(sid2)) {
            // only proceed if event is valid (according to parameters)
            if (!validateEvent(event))
              continue;
            // label the event as included in the dcd timex
            TLink.Type label = TLink.Type.IS_INCLUDED;
            proposed
                .add(new EventTimeLink(event.getEiid(), timex.getTid(), label));
          }
        }
      }
    }

    if (debug == true) {
      System.out.println("TLINKS: " + proposed);
    }
    return proposed;
  }

  private String getDocCreationDate(Timex dctTimex) {
    String value = dctTimex.getValue();
    Matcher matcher = creationTimePattern.matcher(value);
    if (matcher.matches()) {
      String dcd = matcher.group(1);
      return dcd;
    }
    return null;
  }

  private Boolean validateTimex(Timex timex, String dcd) {
    String value = timex.getValue();
    // Always validate timex whose val is the document creation day
    if (value.equals(dcd))
      return true;
    // If includePresentRef is set, then validate such timexes as well.
    else if (value.equals("PRESENT_REF") && this.includePresentRef == true)
      return true;
    else
      return false;
  }

  private Boolean validateEvent(TextEvent event) {
    // Only consider reporting events
    if (event.getTheClass() == TextEvent.Class.REPORTING)
      // If considerTA is set, then don't include past perfective verbs.
      // Note that there are some instances of reporting verbs in the AP
      // documents labeled
      // as past perfective that lack "had"
      if (!considerTA)
      return true;
      else if (!(event.getTense() == TextEvent.Tense.PAST && event.getAspect() == TextEvent.Aspect.PERFECTIVE))
      return true;
      else
      return false;
    else
      return false;
  }

  /**
   * No training. Just rule-based.
   */
  public void train(SieveDocuments trainingInfo) {
    // no training
  }

}
