package eu.fbk.dh.tint.readability.it;

import com.google.common.collect.HashMultimap;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import eu.fbk.dh.tint.readability.GlossarioEntry;
import eu.fbk.dh.tint.readability.Readability;
import eu.fbk.utils.core.PropertiesUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;

/**
 * Created by alessio on 26/09/16.
 */
public class ItalianReadabilityModel {

    private static final Logger LOGGER = LoggerFactory.getLogger(ItalianReadabilityModel.class);
    private static ItalianReadabilityModel ourInstance = null;
    private HashMap<String, GlossarioEntry> glossario = new HashMap<>();
    private HashMap<Integer, HashMultimap<String, String>> easyWords = new HashMap<>();

    public static ItalianReadabilityModel getInstance(Properties globalProperties, Properties localProperties) {
        if (ourInstance == null) {
            boolean useGlossario = PropertiesUtils.getBoolean(localProperties.getProperty("glossario.use"), false);
            String easyWordsFileName = localProperties.getProperty("easyWords");

            Gson gson = new Gson();

            // Loading simple words

            EasyLanguage easyLanguage = new EasyLanguage();
            LOGGER.info("Loading easy lemmas");
            try {
                InputStream stream = Readability.getStream(easyWordsFileName, "/models/easy-output.json");
//                InputStream stream = Readability.getStream(easyWordsFileName, "/models/demauro.json");
                JsonReader reader = new JsonReader(new InputStreamReader(stream));
                easyLanguage = gson.fromJson(reader, EasyLanguage.class);
            } catch (Exception e) {
                LOGGER.warn("Unable to load easyWords file: {}", e.getMessage());
            }

            HashMap<Integer, HashMultimap<String, String>> easyWords = new HashMap<>();

            easyWords.put(1, HashMultimap.create());
            easyWords.get(1).putAll("S", Arrays.asList(easyLanguage.level1.n));
//        easyWords.get(1).putAll("A", Arrays.asList(easyLanguage.level1.a));
//        easyWords.get(1).putAll("B", Arrays.asList(easyLanguage.level1.r));
            easyWords.get(1).putAll("V", Arrays.asList(easyLanguage.level1.v));
            easyWords.put(2, HashMultimap.create());
            easyWords.get(2).putAll("S", Arrays.asList(easyLanguage.level2.n));
            easyWords.get(2).putAll("A", Arrays.asList(easyLanguage.level2.a));
            easyWords.get(2).putAll("B", Arrays.asList(easyLanguage.level2.r));
            easyWords.get(2).putAll("V", Arrays.asList(easyLanguage.level2.v));
            easyWords.put(3, HashMultimap.create());
            easyWords.get(3).putAll("S", Arrays.asList(easyLanguage.level3.n));
            easyWords.get(3).putAll("A", Arrays.asList(easyLanguage.level3.a));
            easyWords.get(3).putAll("B", Arrays.asList(easyLanguage.level3.r));
            easyWords.get(3).putAll("V", Arrays.asList(easyLanguage.level3.v));

            // Loading glossario

            HashMap<String, GlossarioEntry> glossario = new HashMap<>();

            if (useGlossario) {
                Properties stanfordProperties = PropertiesUtils
                        .dotConvertedProperties(localProperties, "glossario.stanford");
                for (String key : globalProperties.stringPropertyNames()) {
                    if (stanfordProperties.getProperty(key) == null) {
                        stanfordProperties.setProperty(key, globalProperties.getProperty(key));
                    }
                }

                String glossarioFileName = localProperties.getProperty("glossario");

                Boolean parseGlossario = PropertiesUtils
                        .getBoolean(localProperties.getProperty("glossario.parse", "true"), true);

                StanfordCoreNLP pipeline = new StanfordCoreNLP(stanfordProperties);
                LOGGER.info("Loading glossario");
                try {
                    InputStream stream = Readability
                            .getStream(glossarioFileName, "/models/glossario-parsed-edited.json");
                    JsonReader reader = new JsonReader(new InputStreamReader(stream));
                    GlossarioEntry[] entries = gson.fromJson(reader, GlossarioEntry[].class);
                    for (GlossarioEntry entry : entries) {
                        for (String form : entry.getForms()) {
//                            if (!form.equals("nido d'infanzia")) {
//                                continue;
//                            }

                            if (parseGlossario) {
                                Annotation annotation = new Annotation(form);
                                pipeline.annotate(annotation);

                                StringBuffer lemmaBuffer = new StringBuffer();
                                StringBuffer tokenBuffer = new StringBuffer();

                                List<CoreLabel> tokens = annotation.get(CoreAnnotations.TokensAnnotation.class);
                                for (CoreLabel token : tokens) {
                                    lemmaBuffer.append(token.get(CoreAnnotations.LemmaAnnotation.class)).append(" ");
                                    tokenBuffer.append(token.get(CoreAnnotations.TextAnnotation.class)).append(" ");
                                }

                                String pos = entry.getPos();
                                String annotatedPos = tokens.get(0).get(CoreAnnotations.PartOfSpeechAnnotation.class);
                                if (pos == null || annotatedPos.substring(0, 1).equals("S")) {
                                    glossario.put(lemmaBuffer.toString().trim(), entry);
                                }
                                glossario.put(tokenBuffer.toString().trim(), entry);
                            } else {
                                // todo: check this, it was outside the "if"
                                glossario.put(form, entry);
                            }
                        }
                    }

                } catch (Exception e) {
                    LOGGER.warn("Unable to load glossario file: {}", e.getMessage());
                }
            }

            ourInstance = new ItalianReadabilityModel(glossario, easyWords);
        } else {
            LOGGER.info("Readability model already loaded");
        }
        return ourInstance;
    }

    private ItalianReadabilityModel(
            HashMap<String, GlossarioEntry> glossario,
            HashMap<Integer, HashMultimap<String, String>> easyWords) {
        this.glossario = glossario;
        this.easyWords = easyWords;
    }

    public HashMap<String, GlossarioEntry> getGlossario() {
        return glossario;
    }

    public HashMap<Integer, HashMultimap<String, String>> getEasyWords() {
        return easyWords;
    }
}
