package zemberek.corpus;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.regex.Pattern;
import zemberek.core.text.Regexps;
import zemberek.core.text.TextUtil;

public class WebDocument {

  static Pattern sourcePattern = Pattern.compile("(source=\")(.+?)(\")");
  static Pattern urlPattern = Pattern.compile("(id=\")(.+?)(\")");
  static Pattern crawlDatePattern = Pattern.compile("(crawl-date=\")(.+?)(\")");
  static Pattern labelPattern = Pattern.compile("(labels=\")(.+?)(\" category)");
  static Pattern categoryPattern = Pattern.compile("(category=\")(.+?)(\" crawl)");
  static Pattern titlePattern = Pattern.compile("(title=\")(.+?)(\" labels)");
  String source;
  String id;
  String url;
  String crawlDate;
  String labelString;
  String category;
  String title;
  long hash;
  List<String> lines;

  public WebDocument(String source,
      String id,
      String title,
      List<String> lines,
      String url,
      String crawlDate,
      String labels,
      String category) {
    this.source = source;
    this.id = id;
    this.lines = lines;
    this.url = url;
    this.crawlDate = crawlDate;
    this.labelString = labels;
    this.category = category;
    this.title = title;
    this.hash = contentHash();
  }

  public static WebDocument fromText(String meta, List<String> pageData) {

    String url = Regexps.firstMatch(urlPattern, meta, 2);
    String id = url.replaceAll("http://|https://", "");
    String source = Regexps.firstMatch(sourcePattern, meta, 2);
    String crawlDate = Regexps.firstMatch(crawlDatePattern, meta, 2);
    String labels = getAttribute(labelPattern, meta);
    String category = getAttribute(categoryPattern, meta);
    String title = getAttribute(titlePattern, meta);

    int i = source.lastIndexOf("/");
    if (i >= 0 && i < source.length()) {
      source = source.substring(i + 1);
    }
    return new WebDocument(source, id, title, pageData, url, crawlDate, labels, category);
  }

  private static String getAttribute(Pattern pattern, String content) {
    String str = Regexps.firstMatch(pattern, content, 2);
    str = str == null ? "" : str.replace('\"', ' ').trim();
    return TextUtil.convertAmpersandStrings(str);
  }

  public int contentLength() {
    int total = 0;
    for (String line : lines) {
      total += line.length();
    }
    return total;
  }

  public void removeDuplicateLines() {
    lines = new ArrayList<>(new LinkedHashSet<>(lines));
    contentHash();
  }

  public String getDocumentHeader() {
    return "<doc id=\"" + id + "\" source=\"" + source + "\" title=\"" + title +
        "\" labels=\"" + labelString + "\" category=\"" + category+ "\" crawl-date=\""
        + crawlDate + "\">";
  }

  public WebDocument emptyContent() {
    return new WebDocument(
        this.source,
        this.id,
        "",
        Collections.emptyList(),
        this.url,
        "", "", "");
  }

  public String getLabelString() {
    return labelString;
  }

  public String getCategory() {
    return category;
  }

  public List<String> getLabels() {
    return Splitter.on(",").omitEmptyStrings().trimResults().splitToList(labelString);
  }

  public String getTitle() {
    return title;
  }

  private long contentHash() {
    String contentNoSpaces = String.join(" ", lines).replaceAll("\\s+", "");
    return com.google.common.hash.Hashing.murmur3_128().hashUnencodedChars(contentNoSpaces)
        .asLong();
  }

  public long getHash() {
    return hash;
  }

  public String getContentAsString() {
    return Joiner.on("\n").join(lines);
  }

  public List<String> getLines() {
    return lines;
  }

  public void setContent(List<String> lines) {
    this.lines = lines;
    this.hash = contentHash();
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    WebDocument page = (WebDocument) o;

    return page.contentHash() == this.contentHash();
  }

  public String getSource() {
    return source;
  }

  public String getId() {
    return id;
  }

  public String getUrl() {
    return url;
  }

  @Override
  public int hashCode() {
    long h = contentHash();
    return (int) ((h & 0xffffffffL) ^ (h >> 32));
  }

}
