/* BdfServer- Copyright (c) 2009-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 fr.exemole.bdfserver.tools.ficheform.builders;

import fr.exemole.bdfserver.api.configuration.LangConfiguration;
import fr.exemole.bdfserver.api.ficheform.FicheFormParameters;
import fr.exemole.bdfserver.api.ficheform.LangFieldElement;
import fr.exemole.bdfserver.api.ui.FieldUi;
import fr.exemole.bdfserver.tools.L10nUtils;
import java.util.LinkedHashSet;
import java.util.Set;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.corpus.metadata.CorpusField;
import net.fichotheque.pointeurs.FichePointeur;
import net.mapeadores.util.attr.AttributeUtils;
import net.mapeadores.util.attr.Attributes;
import net.mapeadores.util.exceptions.SwitchException;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.Langs;
import net.fichotheque.corpus.metadata.FieldOptionConstants;


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

    private final CorpusField corpusField;
    private final Set<Lang> langSet = new LinkedHashSet<Lang>();
    private String label = "";
    private boolean mandatory = false;
    private Lang lang;
    private Attributes attributes = AttributeUtils.EMPTY_ATTRIBUTES;


    public LangFieldElementBuilder(CorpusField corpusField) {
        this.corpusField = corpusField;
    }

    public LangFieldElementBuilder setLabel(String label) {
        if (label == null) {
            throw new IllegalArgumentException("label is null");
        }
        this.label = label;
        return this;
    }

    public LangFieldElementBuilder setMandatory(boolean mandatory) {
        this.mandatory = mandatory;
        return this;
    }

    public LangFieldElementBuilder setAttributes(Attributes attributes) {
        if (attributes == null) {
            this.attributes = AttributeUtils.EMPTY_ATTRIBUTES;
        } else {
            this.attributes = attributes;
        }
        return this;
    }

    public LangFieldElementBuilder setLang(Lang lang) {
        this.lang = lang;
        return this;
    }

    public LangFieldElementBuilder addAvailableLang(Lang lang) {
        if (lang == null) {
            throw new IllegalArgumentException("lang is null");
        }
        langSet.add(lang);
        return this;
    }

    public LangFieldElement toLangFieldElement() {
        Lang[] availableLangArray = null;
        int size = langSet.size();
        if (size > 0) {
            availableLangArray = langSet.toArray(new Lang[size]);
        }
        return new InternalLangFieldElement(corpusField, label, mandatory, attributes, lang, availableLangArray);
    }

    private void initAllLang(FichePointeur fichePointeur, FicheFormParameters ficheFormParameters) {
        if (fichePointeur.isEmpty()) {
            setLang(ficheFormParameters.getWorkingLang());
        } else {
            setLang(((FicheMeta) fichePointeur.getCurrentSubsetItem()).getLang());
        }
    }

    private void initLangConfiguration(FichePointeur fichePointeur, FicheFormParameters ficheFormParameters, LangConfiguration langConfiguration) {
        Lang workingLang = ficheFormParameters.getWorkingLang();
        Langs workingLangs = langConfiguration.getWorkingLangs();
        Langs supplementaryLangs = langConfiguration.getSupplementaryLangs();
        boolean here = false;
        for (Lang currentLang : workingLangs) {
            if (workingLang.equals(currentLang)) {
                here = true;
            }
            addAvailableLang(currentLang);
        }
        for (Lang currentLang : supplementaryLangs) {
            if (workingLang.equals(currentLang)) {
                here = true;
            }
            addAvailableLang(currentLang);
        }
        if (fichePointeur.isEmpty()) {
            if (here) {
                setLang(workingLang);
            } else {
                setLang(workingLangs.get(0));
            }
        } else {
            setLang(((FicheMeta) fichePointeur.getCurrentSubsetItem()).getLang());
        }
    }

    private void initLangs(FichePointeur fichePointeur, FicheFormParameters ficheFormParameters, Langs langs) {
        Lang workingLang = ficheFormParameters.getWorkingLang();
        boolean here = false;
        for (Lang currentLang : langs) {
            if (workingLang.equals(currentLang)) {
                here = true;
            }
            addAvailableLang(currentLang);
        }
        if (fichePointeur.isEmpty()) {
            if (here) {
                setLang(workingLang);
            } else {
                setLang(langs.get(0));
            }
        } else {
            setLang(((FicheMeta) fichePointeur.getCurrentSubsetItem()).getLang());
        }
    }

    public static LangFieldElementBuilder build(FichePointeur fichePointeur, FicheFormParameters ficheFormParameters, CorpusField corpusField, FieldUi fieldUi) {
        LangFieldElementBuilder builder = new LangFieldElementBuilder(corpusField);
        switch (corpusField.getLangScope()) {
            case FieldOptionConstants.ALL_SCOPE:
                builder.initAllLang(fichePointeur, ficheFormParameters);
                break;
            case FieldOptionConstants.CONFIG_SCOPE:
                LangConfiguration langConfiguration = ficheFormParameters.getBdfServer().getLangConfiguration();
                if (langConfiguration.isAllLanguages()) {
                    builder.initAllLang(fichePointeur, ficheFormParameters);
                } else {
                    builder.initLangConfiguration(fichePointeur, ficheFormParameters, langConfiguration);
                }
                break;
            case FieldOptionConstants.LIST_SCOPE:
                builder.initLangs(fichePointeur, ficheFormParameters, corpusField.getLangs());
                break;
            default:
                throw new SwitchException("Unknown langScope: " + corpusField.getLangScope());
        }
        return builder
                .setAttributes(fieldUi.getAttributes())
                .setLabel(L10nUtils.toLabelString(ficheFormParameters, corpusField));
    }

    public static LangFieldElementBuilder init(CorpusField corpusField) {
        return new LangFieldElementBuilder(corpusField);
    }


    private static class InternalLangFieldElement implements LangFieldElement {

        private final CorpusField corpusField;
        private final String label;
        private final boolean mandatory;
        private final Attributes attributes;
        private final Lang lang;
        private final Lang[] availableLangArray;

        private InternalLangFieldElement(CorpusField corpusField, String label, boolean mandatory, Attributes attributes, Lang lang, Lang[] availableLangArray) {
            this.corpusField = corpusField;
            this.label = label;
            this.mandatory = mandatory;
            this.attributes = attributes;
            this.lang = lang;
            this.availableLangArray = availableLangArray;
        }

        @Override
        public CorpusField getCorpusField() {
            return corpusField;
        }

        @Override
        public String getLabel() {
            return label;
        }

        @Override
        public boolean isMandatory() {
            return mandatory;
        }

        @Override
        public Attributes getAttributes() {
            return attributes;
        }

        @Override
        public Lang getLang() {
            return lang;
        }

        @Override
        public Lang[] getAvailableLangArray() {
            return availableLangArray;
        }

    }

}
