/* FichothequeLib_Tools - Copyright (c) 2012-2023 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.fichotheque.tools.format.tokenizers;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.fichotheque.Fichotheque;
import net.fichotheque.format.SubsetPathKey;
import net.fichotheque.format.Tokenizer;
import net.fichotheque.utils.FormatterUtils;
import net.mapeadores.util.localisation.Lang;


/**
 *
 * @author Vincent Calame
 */
public abstract class TokenizerProvider {

    public final static TokenizerProvider NULL = new SimpleTokenizerProvider(FormatterUtils.EMPTY_TOKENIZER);

    public abstract Tokenizer getTokenizer(String name);

    public static TokenizerProvider simple(Tokenizer sourceTokenizer) {
        return new SimpleTokenizerProvider(sourceTokenizer);
    }

    public static TokenizerProvider prefix(String prefix, Map<String, Tokenizer> sourceTokenizerMap) {
        return new MapTokenizerProvider(prefix, sourceTokenizerMap);
    }

    public static TokenizerProvider subsetPath(Fichotheque fichotheque, SubsetPathKey subsetPathKey, TokenizerProvider sourceTokenizerProvider, boolean globalSelect) {
        return new SubsetPathTokenizerProvider(fichotheque, subsetPathKey, sourceTokenizerProvider, globalSelect);
    }


    public static ByLang toByLangProvider(List<TokenizerProvider> tokenizerProviderList) {
        int size = tokenizerProviderList.size();
        Tokenizer[] array = new Tokenizer[size];
        boolean done = true;
        for (int i = 0; i < size; i++) {
            TokenizerProvider tokenizerProvider = tokenizerProviderList.get(i);
            if (tokenizerProvider instanceof SimpleTokenizerProvider) {
                array[i] = ((SimpleTokenizerProvider) tokenizerProvider).getTokenizer();
            } else if ((tokenizerProvider instanceof SubsetPathTokenizerProvider) && (((SubsetPathTokenizerProvider) tokenizerProvider).isSimple())) {
                array[i] = tokenizerProvider.getTokenizer(null);
            } else {
                done = false;
                break;
            }
        }
        if (done) {
            List<Tokenizer> tokenizerList = FormatterUtils.wrap(array);
            return new SimpleByLang(tokenizerList);
        } else {
            return new MapByLang(tokenizerProviderList);
        }
    }


    public static abstract class ByLang {

        public abstract List<Tokenizer> getTokenizerList(Lang lang);

    }


    private static class SimpleByLang extends ByLang {

        private final List<Tokenizer> tokenizerList;

        private SimpleByLang(List<Tokenizer> tokenizerList) {
            this.tokenizerList = tokenizerList;
        }

        @Override
        public List<Tokenizer> getTokenizerList(Lang lang) {
            return tokenizerList;
        }

    }


    private static class MapByLang extends ByLang {

        private final Map<Lang, List<Tokenizer>> tokenizerListMap = new HashMap<Lang, List<Tokenizer>>();
        private final List<TokenizerProvider> tokenizerProviderList;

        private MapByLang(List<TokenizerProvider> tokenizerProviderList) {
            this.tokenizerProviderList = tokenizerProviderList;
        }

        @Override
        public List<Tokenizer> getTokenizerList(Lang lang) {
            List<Tokenizer> tokenizerList = tokenizerListMap.get(lang);
            if (tokenizerList == null) {
                int size = tokenizerProviderList.size();
                String name;
                if (lang == null) {
                    name = "";
                } else {
                    name = lang.toString();
                }
                Tokenizer[] array = new Tokenizer[size];
                for (int i = 0; i < size; i++) {
                    TokenizerProvider provider = tokenizerProviderList.get(i);
                    array[i] = provider.getTokenizer(name);
                }
                tokenizerList = FormatterUtils.wrap(array);
                tokenizerListMap.put(lang, tokenizerList);
            }
            return tokenizerList;
        }

    }


    private static class SimpleTokenizerProvider extends TokenizerProvider {

        private final Tokenizer tokenizer;

        private SimpleTokenizerProvider(Tokenizer tokenizer) {
            this.tokenizer = tokenizer;
        }

        @Override
        public Tokenizer getTokenizer(String name) {
            return tokenizer;
        }

        private Tokenizer getTokenizer() {
            return tokenizer;
        }

    }


    private static class MapTokenizerProvider extends TokenizerProvider {

        private final String prefix;
        private final Map<String, Tokenizer> map;

        MapTokenizerProvider(String prefix, Map<String, Tokenizer> sourceTokenizerMap) {
            this.prefix = prefix;
            this.map = sourceTokenizerMap;
        }

        @Override
        public Tokenizer getTokenizer(String name) {
            Tokenizer tokenizer = map.get(name);
            if (tokenizer == null) {
                tokenizer = map.get("");
            }
            if (tokenizer == null) {
                tokenizer = (Tokenizer) map.values().iterator().next();
            }
            return tokenizer;
        }

    }


    private static class SubsetPathTokenizerProvider extends TokenizerProvider {

        private final Fichotheque fichotheque;
        private final SubsetPathKey subsetPathKey;
        private final TokenizerProvider finalTokenizerProvider;
        private final boolean globalSelect;

        SubsetPathTokenizerProvider(Fichotheque fichotheque, SubsetPathKey subsetPathKey, TokenizerProvider sourceTokenizerProvider, boolean globalSelect) {
            this.fichotheque = fichotheque;
            this.subsetPathKey = subsetPathKey;
            this.finalTokenizerProvider = sourceTokenizerProvider;
            this.globalSelect = globalSelect;
        }

        @Override
        public Tokenizer getTokenizer(String name) {
            Tokenizer finalTokenizer = finalTokenizerProvider.getTokenizer(name);
            return new SubsetPathSourceTokenizer(fichotheque, subsetPathKey, finalTokenizer, globalSelect);
        }

        boolean isSimple() {
            return (finalTokenizerProvider instanceof SimpleTokenizerProvider);
        }

        TokenizerProvider getFinalTokenizerProvider() {
            return finalTokenizerProvider;
        }


    }

}
