package caevo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 * Timebank Corpus file that stores in an easier to read format, all the
 * sentences and docs from the TimeBank corpus, as well as event information on
 * a per-sentence basis.
 * 
 * @author chambers
 */
public class SieveDocuments {
  private List<SieveDocument> documents;
  private Map<String, SieveDocument> nameToDocument;

  // XML Constants
  public static String INFO_NS = "http://chambers.com/corpusinfo";
  public static String SENT_ELEM = "sentence";
  public static String TOKENS_ELEM = "tokens";
  public static String TOKEN_ELEM = "t";
  public static String PARSE_ELEM = "parse";
  public static String DEPS_ELEM = "deps";
  public static String ENTRY_ELEM = "entry";
  public static String EVENTS_ELEM = "events";
  public static String TIMEXES_ELEM = "timexes";
  public static String SID_ELEM = "sid";
  public static String FILE_ELEM = "file";
  public static String FILENAME_ELEM = "name";

  public SieveDocuments() {
  }

  public SieveDocuments(String filepath) {
    readFromXML(filepath);
  }

  /**
   * @return A Vector of String file names
   */
  public Set<String> getFileNames() {
    if (nameToDocument != null)
      return nameToDocument.keySet();
    else
      return null;
  }

  public List<SieveDocument> getDocuments() {
    return documents;
  }

  public SieveDocument getDocument(String docname) {
    if (nameToDocument != null)
      return nameToDocument.get(docname);
    else
      return null;
  }

  public void addDocument(SieveDocument doc) {
    if (documents == null)
      documents = new ArrayList<SieveDocument>();
    if (nameToDocument == null)
      nameToDocument = new HashMap<String, SieveDocument>();
    documents.add(doc);
    nameToDocument.put(doc.getDocname(), doc);
  }

  public void readFromXML(String path) {
    readFromXML(new File(path));
  }

  public void readFromXML(File file) {
    // Reset the documents list.
    if (documents == null)
      documents = new ArrayList<SieveDocument>();
    else
      documents.clear();
    if (nameToDocument == null)
      nameToDocument = new HashMap<String, SieveDocument>();
    else
      nameToDocument.clear();

    // Read the XML file.
    SAXBuilder builder = new SAXBuilder();
    try {
      Namespace ns = Namespace.getNamespace(INFO_NS);
      Document jdomDoc = builder.build(file);

      Element root = jdomDoc.getRootElement();
      List children = root.getChildren(FILE_ELEM, ns);
      System.out.println("Got " + children.size() + " file elements.");
      for (Object obj : children) {
        SieveDocument doc = SieveDocument.fromXML((Element) obj);
        documents.add(doc);
        nameToDocument.put(doc.getDocname(), doc);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Clear out all TLinks in all of the documents.
   */
  public void removeAllTLinks() {
    if (documents != null)
      for (SieveDocument doc : documents)
        doc.removeTlinks();
  }

  /**
   * Create an XML Document out of the sieve documents.
   * 
   * @return An XML Document
   */
  public Document toXML() {
    Namespace ns = Namespace.getNamespace(INFO_NS);
    Document jdomDoc = new Document();
    Element root = new Element("root", ns);
    jdomDoc.setRootElement(root);

    for (SieveDocument doc : documents)
      root.addContent(doc.toXML());

    return jdomDoc;
  }

  public void writeToXML(String path) {
    writeToXML(new File(path));
  }

  public void writeToXML(File file) {
    try {
      FileOutputStream out = new FileOutputStream(file);
      XMLOutputter op = new XMLOutputter(Format.getPrettyFormat());
      Document jdomDoc = toXML();
      op.output(jdomDoc, out);
      out.flush();
      out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  public void outputMarkedUp(String dirpath) {
    // Create the directory.
    try {
      System.out.println("Creating directory: " + dirpath);
      File dir = new File(dirpath);
      dir.mkdir();
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    if (documents != null)
      for (SieveDocument doc : documents)
        doc.outputMarkedUp(dirpath);
  }

  /**
   * Debugging and statistics use only.
   */
  private int numPossiblePairs(int num1) {
    int num = 0;
    for (int x = num1 - 1; x > 0; x--) {
      num += x;
    }
    return num;
  }

  public void countEventPairLinks() {
    int total2 = 0;
    int total3 = 0;
    int docs = 0;
    for (String docname : getFileNames()) {
      SieveDocument doc = nameToDocument.get(docname);
      List<SieveSentence> sentences = doc.getSentences();
      for (int sid = 0; sid < sentences.size() - 1; sid++) {
        SieveSentence sent = sentences.get(sid);
        int num = numPossiblePairs(sent.events().size());
        int num2 = sent.events().size()
            * sentences.get(sid + 1).events().size();
        int num3 = 0;
        if (sid < sentences.size() - 2)
          num3 = sent.events().size() * sentences.get(sid + 2).events().size();
        total2 += num + num2;
        total3 += num + num2 + num3;
      }
      docs++;
    }
    System.out.println("checked " + docs + " docs.");
    System.out.println("total event pairs between 2 sentences: " + total2);
    System.out.println("total event pairs between 3 sentences: " + total3);
  }

  /**
   * This main function is only here to print out automatic time-time links!
   */
  public static void main(String[] args) {
    if (args.length < 1) {
      System.err.println("InfoFile <infopath> <markup-out-dir> markup");
    }

    else if (args[args.length - 1].equals("markup")) {
      SieveDocuments docs = new SieveDocuments();
      docs.readFromXML(args[0]);
      docs.outputMarkedUp(args[1]);
    }

    else if (args[args.length - 1].equals("inout")) {
      SieveDocuments docs = new SieveDocuments();
      docs.readFromXML(args[0]);
      docs.writeToXML(args[1]);
    }

    // InfoFile <info> count
    else if (args[args.length - 1].equals("count")) {
      SieveDocuments docs = new SieveDocuments();
      docs.readFromXML(args[0]);
      // info.countEventDCTLinks();
      docs.countEventPairLinks();
    }
  }

}
