package org.RI.P1;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Collections;
import java.util.Map;
import java.util.Comparator;
import java.util.Set;
import java.util.AbstractMap;
import java.util.ArrayList;

import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
import org.apache.tika.language.detect.LanguageDetector;
import org.apache.tika.langdetect.OptimaizeLangDetector;
import org.apache.tika.language.detect.LanguageResult;
import org.apache.tika.metadata.*;
import org.apache.tika.parser.*;
import org.apache.tika.sax.BodyContentHandler;
import org.apache.tika.sax.LinkContentHandler;
import org.apache.tika.sax.TeeContentHandler;
import org.apache.tika.sax.ToHTMLContentHandler;
import org.apache.tika.parser.html.HtmlParser;
import org.xml.sax.SAXException;

public class FileData {
    private File file;
    private String filename;
    private String type;
    private String encoding;
    private LanguageResult language;
    private InputStream inputStream;
    private Metadata metadata;
    private BodyContentHandler contentHandler;
    private ParseContext parseContext;
    private AutoDetectParser parser;
    private LanguageDetector langIdentifier;
    private LinkContentHandler linkHandler;
    private TeeContentHandler teeHandler;
    private ToHTMLContentHandler toHTMLhandler;
    private HashMap<String, Integer> wordFrequency;
    private ArrayList<AbstractMap.SimpleEntry<String, Integer>> sortedWordFrequency;
    private Tika tika;

    FileData() {
    }

    FileData(File file) throws IOException, TikaException, SAXException {
        this.file = file;
        inputStream = new FileInputStream(file);
        metadata = new Metadata();
        parser = new AutoDetectParser();
        contentHandler = new BodyContentHandler(-1);
        parseContext = new ParseContext();
        langIdentifier = new OptimaizeLangDetector().loadModels();
        linkHandler = new LinkContentHandler();
        toHTMLhandler = new ToHTMLContentHandler();
        wordFrequency = new HashMap<>();
        sortedWordFrequency = new ArrayList<>();
        tika = new Tika();
        setMetadata();
    }

    private void setMetadata() throws IOException, TikaException, SAXException {
        parser.parse(inputStream, contentHandler, metadata, parseContext);
        filename = metadata.get(TikaCoreProperties.TITLE);
        type = metadata.get(Metadata.CONTENT_TYPE);
        encoding = metadata.get(Metadata.CONTENT_ENCODING);
        language = langIdentifier.detect(contentHandler.toString());
    }

    void getLinks() throws IOException, TikaException, SAXException {
        HtmlParser htmlParser = new HtmlParser();
        inputStream = new FileInputStream(file);
        teeHandler = new TeeContentHandler(linkHandler, contentHandler, toHTMLhandler);
        htmlParser.parse(inputStream, teeHandler, metadata, parseContext);
        System.out.println("Filename: " + filename);
        System.out.println("Links: " + linkHandler.getLinks());
    }

    private void tokenizeFile() throws FileNotFoundException, IOException, TikaException {
        String fileContent = tika.parseToString(file);
        fileContent = fileContent.toLowerCase();
        fileContent = fileContent.replaceAll("[\\(\\)¡!¿?→,.:;\\-—\"«»“”]", "");

        for (String token : fileContent.split("\\s+")) {
            wordFrequency.compute(token, (key, val) -> (val == null) ? 1 : val + 1);
        }
    }

    private void sortWords() {
        Set<Map.Entry<String, Integer>> entrySet = wordFrequency.entrySet();

        for (Map.Entry<String, Integer> item : entrySet) {
            sortedWordFrequency.add(new AbstractMap.SimpleEntry<String, Integer>(item.getKey(), item.getValue()));
        }

        Collections.sort(sortedWordFrequency, new Comparator<AbstractMap.SimpleEntry<String, Integer>>() {
            @Override
            public int compare(AbstractMap.SimpleEntry<String, Integer> m1,
                    AbstractMap.SimpleEntry<String, Integer> m2) {
                return (m1.getValue()).compareTo(m2.getValue());
            }
        });

        Collections.reverse(sortedWordFrequency);
    }

    private void saveWordFrequency() throws FileNotFoundException {
        FileOutputStream outputFile = new FileOutputStream("output/" + filename + ".dat");
        PrintStream output = new PrintStream(outputFile);
        System.setOut(output);

        for (Map.Entry<String, Integer> item : sortedWordFrequency) {
            System.out.println(item.getValue() + " " + item.getKey());
        }

    }

    void setWordOcurrences() throws FileNotFoundException, IOException, TikaException {
        tokenizeFile();
        sortWords();
        saveWordFrequency();
    }

    @Override
    public String toString() {
        return "Filename: " + filename + "\n" + "Type: " + type + "\n" + "Encoding: " + encoding + "\n" + "Language: "
                + language.getLanguage() + "\n";
    }

}
