/* UtilLib - Copyright (c) 2006-2018 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.util.localisation;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import net.mapeadores.util.text.lexie.LexieFilter;


/**
 *
 * @author Vincent Calame
 */
public class LocalisationLexieFilters {

    static final DefaultWordFilter defaultWordFilter = new DefaultWordFilter();
    static final Map<Lang, LexieFilter> currentFilter = new HashMap<Lang, LexieFilter>();

    private LocalisationLexieFilters() {
    }

    public static LexieFilter getLexieFilter(Lang lang) {
        LexieFilter wordFilter = currentFilter.get(lang);
        if (wordFilter == null) {
            wordFilter = init(lang);
            currentFilter.put(lang, wordFilter);
        }
        return wordFilter;
    }

    private static LexieFilter init(Lang lang) {
        Class currentClass = LocalisationLexieFilters.class;
        String langString = lang.toString();
        InputStream propertiesStream = currentClass.getResourceAsStream("resources/wordfilter_" + langString + ".properties");
        InputStream forbiddenStream = currentClass.getResourceAsStream("resources/forbiddenwords_" + langString + ".txt");
        try {
            LexieFilter wordFilter = init(lang, propertiesStream, forbiddenStream);
            if (wordFilter == null) {
                wordFilter = defaultWordFilter;
            }
            return wordFilter;
        } catch (IOException ioe) {
            return defaultWordFilter;
        }
    }

    private static LexieFilter init(Lang lang, InputStream propertiesStream, InputStream forbiddenStream) throws IOException {
        if (propertiesStream == null) {
            return null;
        }
        if (forbiddenStream == null) {
            return null;
        }
        Properties properties = new Properties();
        properties.load(propertiesStream);
        propertiesStream.close();
        List<String> forbiddenList = new ArrayList<String>();
        BufferedReader reader = new BufferedReader(new InputStreamReader(forbiddenStream, "UTF-8"));
        String ligne;
        while ((ligne = reader.readLine()) != null) {
            ligne = ligne.trim();
            if ((ligne.length() > 0) && (ligne.charAt(0) != '#')) {
                forbiddenList.add(ligne);
            }
        }
        reader.close();
        LocalisationWordFilter wordFilter = new LocalisationWordFilter(lang, properties, forbiddenList);
        return wordFilter;
    }


    private static class DefaultWordFilter implements LexieFilter {

        private DefaultWordFilter() {

        }

        @Override
        public boolean acceptLexie(String word) {
            switch (word.length()) {
                case 0:
                    return false;
                case 1:
                    return Character.isIdeographic(word.charAt(0));
                case 2:
                    return false;
                default:
                    return true;
            }
        }

    }


    private static class LocalisationWordFilter implements LexieFilter {

        private final Locale locale;
        private final Set<String> forbiddenWordSet;
        private int minlength = 3;
        private int minpartlength = 2;
        private int maxForbiddenWordLength = 0;


        private LocalisationWordFilter(Lang lang, Properties properties, List<String> forbiddenList) {
            String minlengthString = properties.getProperty("minlength");
            if (minlengthString != null) {
                try {
                    minlength = Integer.parseInt(minlengthString);
                } catch (NumberFormatException nfe) {
                }
            }
            String minpartlengthString = properties.getProperty("minpartlength");
            if (minpartlengthString != null) {
                try {
                    minpartlength = Integer.parseInt(minpartlengthString);
                } catch (NumberFormatException nfe) {
                }
            }
            locale = lang.toLocale();
            if (forbiddenList.size() > 0) {
                forbiddenWordSet = new HashSet<String>();
                for (String s : forbiddenList) {
                    s = s.toLowerCase(locale);
                    forbiddenWordSet.add(s);
                    maxForbiddenWordLength = Math.max(maxForbiddenWordLength, s.length());
                }
            } else {
                forbiddenWordSet = null;
            }
        }

        @Override
        public boolean acceptLexie(String word) {
            int length = word.length();
            if (length == 1) {
                if (Character.isIdeographic(word.charAt(0))) {
                    return true;
                }
            }
            if (length < minlength) {
                if (length > 1) {
                    try {
                        Integer.parseInt(word);
                        return true;
                    } catch (NumberFormatException nfe) {
                    }
                }
                return false;
            }
            if (length > maxForbiddenWordLength) {
                return true;
            }
            if (forbiddenWordSet == null) {
                return true;
            }
            return !forbiddenWordSet.contains(word.toLowerCase(locale));
        }

    }

}
