/* 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.CorpusIncludeElement;
import fr.exemole.bdfserver.api.ficheform.FormElement;
import fr.exemole.bdfserver.api.ficheform.GeopointPropSubfieldsElement;
import fr.exemole.bdfserver.api.ficheform.HiddenFieldElement;
import fr.exemole.bdfserver.api.ficheform.ImagePropSubfieldsElement;
import fr.exemole.bdfserver.api.ficheform.ItemFieldElement;
import fr.exemole.bdfserver.api.ficheform.LangFieldElement;
import fr.exemole.bdfserver.api.ficheform.PersonnePropSubfieldsElement;
import fr.exemole.bdfserver.api.ficheform.TextFieldElement;
import fr.exemole.bdfserver.api.ficheform.ThesaurusIncludeElement;
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.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;
import fr.exemole.bdfserver.api.ficheform.AmountInfoSubfieldsElement;
import fr.exemole.bdfserver.api.ficheform.AmountPropSubfieldsElement;


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

    private final PermissionSummary permissionSummary;
    private final FicheMeta ficheMeta;
    private final List<FormElement> formElementList;
    private final Lang lang;

    public FicheFormJsonProperty(PermissionSummary permissionSummary, FicheMeta ficheMeta, List<FormElement> formElementList, Lang lang) {
        this.ficheMeta = ficheMeta;
        this.permissionSummary = permissionSummary;
        this.formElementList = formElementList;
        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 (FormElement formElement : formElementList) {
                if (formElement instanceof FormElement.Field) {
                    write(jw, (FormElement.Field) formElement);
                } else if (formElement instanceof FormElement.Include) {
                    write(jw, (FormElement.Include) formElement);
                }
            }
            jw.endObject();
        }
        jw.endObject();
    }

    private void write(JSONWriter jw, FormElement.Field formElement) throws IOException {
        jw.key(formElement.getCorpusField().getFieldString());
        jw.object();
        jw.key("category")
                .value("field");
        if (formElement instanceof TextFieldElement) {
            writeTextField(jw, (TextFieldElement) formElement);
        } else if (formElement instanceof LangFieldElement) {
            writeLangField(jw, (LangFieldElement) formElement);
        } else if (formElement instanceof PersonnePropSubfieldsElement) {
            writePersonPropSubfields(jw, (PersonnePropSubfieldsElement) formElement);
        } else if (formElement instanceof GeopointPropSubfieldsElement) {
            writeGeopointPropSubfields(jw, (GeopointPropSubfieldsElement) formElement);
        } else if (formElement instanceof AmountPropSubfieldsElement) {
            writeAmountPropSubfields(jw, (AmountPropSubfieldsElement) formElement);
        } else if (formElement instanceof AmountInfoSubfieldsElement) {
            writeAmountInfoSubfields(jw, (AmountInfoSubfieldsElement) formElement);
        } else if (formElement instanceof ItemFieldElement) {
            writeItemField(jw, (ItemFieldElement) formElement);
        } else if (formElement instanceof HiddenFieldElement) {
            writeHiddenField(jw, (HiddenFieldElement) formElement);
        } else if (formElement instanceof ImagePropSubfieldsElement) {
            writeImagePropSubfields(jw, (ImagePropSubfieldsElement) formElement);
        }
        jw.endObject();
    }

    private void write(JSONWriter jw, FormElement.Include formElement) throws IOException {
        jw.key(formElement.getIncludeName());
        jw.object();
        jw.key("category")
                .value("include");
        if (formElement instanceof CorpusIncludeElement) {
            writeCorpusInclude(jw, (CorpusIncludeElement) formElement);
        } else if (formElement instanceof ThesaurusIncludeElement) {
            writeThesaurusInclude(jw, (ThesaurusIncludeElement) formElement);
        }
        jw.endObject();
    }

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

    private void writeLangField(JSONWriter jw, LangFieldElement langFieldElement) throws IOException {
        jw.key("type")
                .value("lang");
        Lang lang = langFieldElement.getLang();
        if (lang != null) {
            jw.key("lang")
                    .value(lang.toString());
        }
        Lang[] array = langFieldElement.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, PersonnePropSubfieldsElement formElement) throws IOException {
        jw.key("type")
                .value("person");
        PersonCore person = formElement.getPersonCore();
        boolean withNonlatin = formElement.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 ((!formElement.isWithoutSurnameFirst()) || (person.isSurnameFirst())) {
            jw.key("surnamefirst")
                    .value(person.isSurnameFirst());
        }
    }

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

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

    }

    private void writeAmountInfoSubfields(JSONWriter jw, AmountInfoSubfieldsElement formElement) throws IOException {
        jw.key("type")
                .value("amounts");
        jw.key("amounts");
        jw.array();
        for (AmountInfoSubfieldsElement.Entry entry : formElement.getEntryList()) {
            jw.object();
            jw.key("num")
                    .value(entry.getAmountValue());
            jw.key("cur")
                    .value(entry.getCurrency().getCurrencyCode());
            jw.endObject();
        }
        jw.endArray();
        jw.key("others")
                .value(formElement.getOthersValue());

    }

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

    }

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

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

    private void writeCorpusInclude(JSONWriter jw, CorpusIncludeElement formElement) throws IOException {
        jw.key("type")
                .value("corpus");
        jw.key("fiches");
        jw.array();
        for (CorpusIncludeElement.Entry entry : formElement.getEntryList()) {
            jw.object();
            {
                jw.key("value")
                        .value(entry.getValue());
                AccessJson.properties(jw, entry.getFicheMeta());
            }
            jw.endObject();
        }
        jw.endArray();
    }

    private void writeThesaurusInclude(JSONWriter jw, ThesaurusIncludeElement formElement) throws IOException {
        jw.key("type")
                .value("thesaurus");
        jw.key("motcles");
        jw.array();
        for (ThesaurusIncludeElement.Entry entry : formElement.getEntryList()) {
            jw.object();
            {
                jw.key("value")
                        .value(entry.getValue());
                AccessJson.properties(jw, entry.getMotcle(), lang);
            }
            jw.endObject();
        }
        jw.endArray();
    }


}
