package caevo.sieves;

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.SieveSentence;
import caevo.TextEvent;
import caevo.Timex;
import caevo.tlink.EventTimeLink;
import caevo.tlink.TLink;
import caevo.util.TreeOperator;
import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.trees.LabeledScoredTreeFactory;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.trees.TreeFactory;

/**
 * The idea is that when a quarter expression like first, second, third, fourth
 * quarter, appears directly after a reporting verb, it tends to be the case
 * that the expression is not a temporal argument but rather modifies one of the
 * verbs arguments. For example "company reported third quarter losses of $3
 * million...", "third quarter" modifies" losses, and "third quarter losses" is
 * itself an argument of "reported".
 * 
 * @author cassidy
 */
public class QuarterSieveReporting implements Sieve {
  public boolean debug = false;
  // Regex checks if timex value indicates a quarter
  private String valQuarterRegex = "\\d{4}-Q\\d";
  private Pattern valQuarter = Pattern.compile(valQuarterRegex);
  // Regex to ensure that the text looks like "Xth quarter"
  private String textQuarterRegex = "(first|second|third|fourth|1st|2nd|3rd|4th)(\\s|-)quarter";
  private Pattern textQuarter = Pattern.compile(textQuarterRegex);

  // create TreeFactory to convert a sentence to a tree
  private static TreeFactory tf = new LabeledScoredTreeFactory();

  /**
   * The main function. All sieves must have this.
   */
  public List<TLink> annotate(SieveDocument doc, List<TLink> currentTLinks) {
    // The size of the list is the number of sentences in the document.
    // The inner list is the events in textual order.
    List<List<TextEvent>> allEvents = doc.getEventsBySentence();
    List<List<Timex>> allTimexes = doc.getTimexesBySentence();
    // list of all parse strings for the document
    List<Tree> trees = doc.getAllParseTrees();

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

    // check timexes/event pairs in each sentence against sieve criteria.
    int sid = 0;
    for (SieveSentence sent : doc.getSentences()) {
      if (debug == true) {
        System.out.println("DEBUG: adding tlinks from " + doc.getDocname()
            + " sentence " + sent.sentence());
      }
      // get parse tree of sentence
      Tree sentParseTree = trees.get(sid);
      for (Timex timex : allTimexes.get(sid)) {
        // only proceed if timex is of form YYYY-QX
        if (!validateTimex(timex))
          continue;
        System.out.println("DEBUG: encountered QUARTER timex");
        for (TextEvent event : allEvents.get(sid)) {
          // only proceed if event is of type REPORTING
          if (!validateEvent(event))
            continue;
          // check if timex/event pair satisfy positional criteria
          // (ie that they occur within one word of one another)
          int timexIndex = timex.getTokenOffset();
          int eventIndex = event.getIndex();
          if (timexIndex - 1 == eventIndex) {
            TLink.Type label = TLink.Type.IS_INCLUDED;
            proposed
                .add(new EventTimeLink(event.getEiid(), timex.getTid(), label));
          } else if (timexIndex - 2 == event.getIndex()) {
            int interIndex = timexIndex - 1;
            String interWord = getTokenText(interIndex, sent);
            TLink.Type label = classifyInter(interWord);
            proposed
                .add(new EventTimeLink(event.getEiid(), timex.getTid(), label));
          }
        }
      }
      sid++;
    }

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

  private String getTokenText(int index, SieveSentence sent) {
    List<CoreLabel> tokens = sent.tokens();
    CoreLabel token = tokens.get(index);
    return token.originalText();
  }

  // returns the label appropriate for the word between the verb and quarter
  // timex
  // could be improved by checking to see if the quarter is to occur in the
  // future,
  // in which case BEFORE might be more appropriate
  private TLink.Type classifyInter(String interText) {
    if (interText == "in")
      return TLink.Type.IS_INCLUDED;
    else {
      return TLink.Type.AFTER;
    }
  }

  private Boolean validateEvent(TextEvent event) {
    if (event.getTheClass() == TextEvent.Class.REPORTING)
      return true;
    else
      return false;
  }

  /**
   * validateTime ensures that timex value is of a certain form one option is:
   * YYYY-MM-DD or YYYY-MM or YYYY The idea is that some time expressions are
   * modifiers of arguments of the verb, and not arguments themselves. For
   * example, "X said Tuesday that ..." vs. "X said Tuesday's earnings were ..."
   * In the latter case, 'said' may not be included_in Tuesday. A very common
   * example is when the time expression is a quarter, since the verb is almost
   * always after the quarter.
   */

  private Boolean validateTimex(Timex timex) {
    String val = timex.getValue();
    String text = timex.getText();
    // check if value represent a quarter
    Matcher matchVal = valQuarter.matcher(val);
    Matcher matchText = valQuarter.matcher(text);
    if (matchText.matches() && matchVal.matches())
      return true;
    else
      return false;
  }

  private String posTagFromTree(Tree sentParseTree, int tokenIndex) {
    String posTag = TreeOperator.indexToPOSTag(sentParseTree, tokenIndex);
    return posTag;
  }

  private Tree sidToTree(int sid, List<String> allParseStrings) {
    String sentParseString = allParseStrings.get(sid);
    Tree sentParseTree = TreeOperator.stringToTree(sentParseString, tf);
    return sentParseTree;
  }

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

}
