/* BdfServer_JsonProducers - Copyright (c) 2024-2025 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.jsonproducers.corpus;

import fr.exemole.bdfserver.api.ficheform.FormEntry;
import fr.exemole.bdfserver.api.ficheform.field.AmountInfoEntry;
import fr.exemole.bdfserver.api.ficheform.field.AmountPropEntry;
import fr.exemole.bdfserver.api.ficheform.field.GeopointPropEntry;
import fr.exemole.bdfserver.api.ficheform.field.HiddenFieldEntry;
import fr.exemole.bdfserver.api.ficheform.field.ImagePropEntry;
import fr.exemole.bdfserver.api.ficheform.field.ItemFieldEntry;
import fr.exemole.bdfserver.api.ficheform.field.LangFieldEntry;
import fr.exemole.bdfserver.api.ficheform.field.PersonnePropEntry;
import fr.exemole.bdfserver.api.ficheform.field.TextFieldEntry;
import fr.exemole.bdfserver.api.ficheform.include.CorpusEntry;
import fr.exemole.bdfserver.api.ficheform.include.LiageEntry;
import fr.exemole.bdfserver.api.ficheform.include.SubsetItemValue;
import fr.exemole.bdfserver.api.ficheform.include.ThesaurusEntry;
import fr.exemole.bdfserver.json.AccessJson;
import java.io.IOException;
import java.util.List;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.permission.PermissionSummary;
import net.fichotheque.thesaurus.Motcle;
import net.mapeadores.util.json.JSONWriter;
import net.mapeadores.util.json.JsonProperty;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.models.PersonCore;
import net.mapeadores.util.text.MultiStringable;


/**
 *
 * @author Vincent Calame
 */
public class FicheFormJsonProperty implements JsonProperty {

    private final PermissionSummary permissionSummary;
    private final FicheMeta ficheMeta;
    private final List<FormEntry> formEntryList;
    private final Lang lang;

    public FicheFormJsonProperty(PermissionSummary permissionSummary, FicheMeta ficheMeta, List<FormEntry> formEntryList, Lang lang) {
        this.ficheMeta = ficheMeta;
        this.permissionSummary = permissionSummary;
        this.formEntryList = formEntryList;
        this.lang = lang;
    }

    @Override
    public String getName() {
        return "fiche";
    }

    @Override
    public void writeValue(JSONWriter jw) throws IOException {
        jw.object();
        {
            AccessJson.properties(jw, ficheMeta, permissionSummary);
            jw.key("properties");
            jw.object();
            for (FormEntry formEntry : formEntryList) {
                if (formEntry instanceof FormEntry.Field) {
                    write(jw, (FormEntry.Field) formEntry);
                } else if (formEntry instanceof FormEntry.Include) {
                    write(jw, (FormEntry.Include) formEntry);
                }
            }
            jw.endObject();
        }
        jw.endObject();
    }

    private void write(JSONWriter jw, FormEntry.Field formEntry) throws IOException {
        jw.key(formEntry.getCorpusField().getFieldString());
        jw.object();
        jw.key("category")
                .value("field");
        if (formEntry instanceof TextFieldEntry) {
            writeTextField(jw, (TextFieldEntry) formEntry);
        } else if (formEntry instanceof LangFieldEntry) {
            writeLangField(jw, (LangFieldEntry) formEntry);
        } else if (formEntry instanceof PersonnePropEntry) {
            writePersonPropSubfields(jw, (PersonnePropEntry) formEntry);
        } else if (formEntry instanceof GeopointPropEntry) {
            writeGeopointPropSubfields(jw, (GeopointPropEntry) formEntry);
        } else if (formEntry instanceof AmountPropEntry) {
            writeAmountPropSubfields(jw, (AmountPropEntry) formEntry);
        } else if (formEntry instanceof AmountInfoEntry) {
            writeAmountInfoSubfields(jw, (AmountInfoEntry) formEntry);
        } else if (formEntry instanceof ItemFieldEntry) {
            writeItemField(jw, (ItemFieldEntry) formEntry);
        } else if (formEntry instanceof HiddenFieldEntry) {
            writeHiddenField(jw, (HiddenFieldEntry) formEntry);
        } else if (formEntry instanceof ImagePropEntry) {
            writeImagePropSubfields(jw, (ImagePropEntry) formEntry);
        }
        jw.endObject();
    }

    private void write(JSONWriter jw, FormEntry.Include formEntry) throws IOException {
        jw.key(formEntry.getIncludeName());
        jw.object();
        jw.key("category")
                .value("include");
        if (formEntry instanceof CorpusEntry) {
            writeCorpusInclude(jw, (CorpusEntry) formEntry);
        } else if (formEntry instanceof ThesaurusEntry) {
            writeThesaurusInclude(jw, (ThesaurusEntry) formEntry);
        } else if (formEntry instanceof LiageEntry) {
            writeLiage(jw, (LiageEntry) formEntry);
        }
        jw.endObject();
    }

    private void writeTextField(JSONWriter jw, TextFieldEntry formEntry) throws IOException {
        jw.key("type")
                .value("text");
        jw.key("text")
                .value(formEntry.getFormattedText());
        jw.key("rows")
                .value(formEntry.getRows());
    }

    private void writeLangField(JSONWriter jw, LangFieldEntry formEntry) throws IOException {
        jw.key("type")
                .value("lang");
        Lang lang = formEntry.getLang();
        if (lang != null) {
            jw.key("lang")
                    .value(lang.toString());
        }
        Lang[] array = formEntry.getAvailableLangArray();
        if (array != null) {
            jw.key("available");
            jw.array();
            for (Lang availableLang : array) {
                jw.object();
                {
                    jw.key("lang")
                            .value(availableLang.toString());
                }
                jw.endObject();
            }
            jw.endArray();
        }
    }

    private void writePersonPropSubfields(JSONWriter jw, PersonnePropEntry formEntry) throws IOException {
        jw.key("type")
                .value("person");
        PersonCore person = formEntry.getPersonCore();
        boolean withNonlatin = formEntry.isWithNonlatin();
        if (person.getNonlatin().length() > 0) {
            withNonlatin = true;
        }
        jw.key("surname")
                .value(person.getSurname());
        jw.key("forename")
                .value(person.getForename());
        if (withNonlatin) {
            jw.key("nonlatin")
                    .value(person.getNonlatin());
        }
        if ((!formEntry.isWithoutSurnameFirst()) || (person.isSurnameFirst())) {
            jw.key("surnamefirst")
                    .value(person.isSurnameFirst());
        }
    }

    private void writeGeopointPropSubfields(JSONWriter jw, GeopointPropEntry formEntry) throws IOException {
        jw.key("type")
                .value("geopoint");
        jw.key("latitude")
                .value(formEntry.getLatitude());
        jw.key("longitude")
                .value(formEntry.getLongitude());
        MultiStringable multiStringable = formEntry.getAddressFieldNames();
        if (multiStringable != null) {
            jw.key("adressfields");
            jw.array();
            for (String field : multiStringable.toStringArray()) {
                jw.value(field);
            }
            jw.endArray();
        }
    }

    private void writeAmountPropSubfields(JSONWriter jw, AmountPropEntry formEntry) throws IOException {
        jw.key("type")
                .value("amount");
        jw.key("num")
                .value(formEntry.getNum());
        jw.key("cur")
                .value(formEntry.getCur());
        jw.key("unique")
                .value(formEntry.isUnique());
        jw.key("availablecurrencies");
        jw.array();
        for (String availableCur : formEntry.getCurrencies().toStringArray()) {
            jw.value(availableCur);
        }
        jw.endArray();

    }

    private void writeAmountInfoSubfields(JSONWriter jw, AmountInfoEntry formEntry) throws IOException {
        jw.key("type")
                .value("amounts");
        jw.key("amounts");
        jw.array();
        for (AmountInfoEntry.Value amountValue : formEntry.getValueList()) {
            jw.object();
            jw.key("num")
                    .value(amountValue.getAmountValue());
            jw.key("cur")
                    .value(amountValue.getCurrency().getCurrencyCode());
            jw.endObject();
        }
        jw.endArray();
        jw.key("others")
                .value(formEntry.getOthersValue());

    }

    private void writeItemField(JSONWriter jw, ItemFieldEntry formEntry) throws IOException {
        jw.key("type")
                .value("item");
        jw.key("value")
                .value(formEntry.getValue());
        jw.key("width")
                .value(formEntry.getWidthType());
        SubsetKey sphereKey = formEntry.getSphereKey();
        if (sphereKey != null) {
            jw.key("sphere")
                    .value(sphereKey.getSubsetName());
        }

    }

    private void writeHiddenField(JSONWriter jw, HiddenFieldEntry formEntry) throws IOException {
        jw.key("type")
                .value("hidden");
        jw.key("value")
                .value(formEntry.getValue());
    }

    private void writeImagePropSubfields(JSONWriter jw, ImagePropEntry formEntry) throws IOException {
        jw.key("type")
                .value("image");
        jw.key("src")
                .value(formEntry.getSrc());
        jw.key("alt")
                .value(formEntry.getAlt());
        jw.key("title")
                .value(formEntry.getTitle());
    }

    private void writeCorpusInclude(JSONWriter jw, CorpusEntry formEntry) throws IOException {
        jw.key("type")
                .value("corpus");
        jw.key("fiches");
        jw.array();
        for (SubsetItemValue subsetItemValue : formEntry.getValueList()) {
            jw.object();
            {
                jw.key("value")
                        .value(subsetItemValue.getValue());
                AccessJson.properties(jw, (FicheMeta) subsetItemValue.getSubsetItem());
            }
            jw.endObject();
        }
        jw.endArray();
    }

    private void writeLiage(JSONWriter jw, LiageEntry formEntry) throws IOException {
        jw.key("type")
                .value("liage");
        jw.key("fiches");
        jw.array();
        for (SubsetItemValue subsetItemValue : formEntry.getValueList()) {
            jw.object();
            {
                jw.key("value")
                        .value(subsetItemValue.getValue());
                AccessJson.properties(jw, (FicheMeta) subsetItemValue.getSubsetItem());
            }
            jw.endObject();
        }
        jw.endArray();
    }

    private void writeThesaurusInclude(JSONWriter jw, ThesaurusEntry formEntry) throws IOException {
        jw.key("type")
                .value("thesaurus");
        jw.key("motcles");
        jw.array();
        for (SubsetItemValue subsetItemValue : formEntry.getValueList()) {
            jw.object();
            {
                jw.key("value")
                        .value(subsetItemValue.getValue());
                AccessJson.properties(jw, (Motcle) subsetItemValue.getSubsetItem(), lang);
            }
            jw.endObject();
        }
        jw.endArray();
    }


}
