/* BdfServer - Copyright (c) 2008-2024 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.xml.ui;

import fr.exemole.bdfserver.api.BdfServerConstants;
import fr.exemole.bdfserver.api.ui.CommentUi;
import fr.exemole.bdfserver.api.ui.DataUi;
import fr.exemole.bdfserver.api.ui.FieldUi;
import fr.exemole.bdfserver.api.ui.IncludeUi;
import fr.exemole.bdfserver.api.ui.SpecialIncludeUi;
import fr.exemole.bdfserver.api.ui.SubsetIncludeUi;
import fr.exemole.bdfserver.api.ui.UiComponent;
import fr.exemole.bdfserver.api.ui.UiComponents;
import fr.exemole.bdfserver.tools.ui.UiUtils;
import java.io.IOException;
import java.util.List;
import net.fichotheque.externalsource.ExternalSourceDef;
import net.fichotheque.include.ExtendedIncludeKey;
import net.mapeadores.util.attr.AttributeUtils;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.text.LabelUtils;
import net.mapeadores.util.text.Labels;
import net.mapeadores.util.text.MultiStringable;
import net.mapeadores.util.text.StringUtils;
import net.mapeadores.util.xml.XMLPart;
import net.mapeadores.util.xml.XMLWriter;


/**
 *
 * @author Vincent Calame
 */
public class UiComponentsXMLPart extends XMLPart {

    public UiComponentsXMLPart(XMLWriter xmlWriter) {
        super(xmlWriter);
    }

    public void appendUiComponents(UiComponents uiComponents) throws IOException {
        openTag("ui-components");
        openTag("metadata");
        appendCommentDef(uiComponents);
        closeTag("metadata");
        for (UiComponent uiComponent : uiComponents.getUiComponentList()) {
            if (uiComponent instanceof CommentUi) {
                CommentUi commentUi = (CommentUi) uiComponent;
                startOpenTag("comment");
                addAttribute("name", commentUi.getCommentName());
                closeEmptyTag();
            } else if (uiComponent instanceof FieldUi) {
                appendFieldUi((FieldUi) uiComponent);
            } else if (uiComponent instanceof SpecialIncludeUi) {
                appendSpecialIncludeUi((SpecialIncludeUi) uiComponent);
            } else if (uiComponent instanceof SubsetIncludeUi) {
                appendSubsetIncludeUi((SubsetIncludeUi) uiComponent);
            } else if (uiComponent instanceof DataUi) {
                appendDataUi((DataUi) uiComponent);
            }
        }
        closeTag("ui-components");
    }

    private void appendCommentDef(UiComponents uiComponents) throws IOException {
        List<CommentUi> list = UiUtils.getCommentUiList(uiComponents);
        for (CommentUi commentUi : list) {
            startOpenTag("comment-def");
            addAttribute("name", commentUi.getCommentName());
            addAttribute("location", UiUtils.maskToString(commentUi.getLocation()));
            endOpenTag();
            appendStatus(commentUi);
            for (Lang lang : commentUi.getLangs()) {
                startOpenTag("html");
                addAttribute("xml:lang", lang.toString());
                endOpenTag();
                addCData(commentUi.getHtmlByLang(lang));
                closeTag("html", false);
            }
            appendOptions(commentUi);
            appendAttributes(commentUi);
            closeTag("comment-def");
        }
    }

    private void appendFieldUi(FieldUi fieldUi) throws IOException {
        startOpenTag("field-ui");
        addAttribute("field-key", fieldUi.getName());
        endOpenTag();
        appendStatus(fieldUi);
        appendOptions(fieldUi);
        appendAttributes(fieldUi);
        closeTag("field-ui");
    }

    private void appendSpecialIncludeUi(SpecialIncludeUi includeUi) throws IOException {
        startOpenTag("special-ui");
        addAttribute("name", includeUi.getName());
        endOpenTag();
        appendStatus(includeUi);
        appendCustomLabels(includeUi);
        appendOptions(includeUi);
        appendAttributes(includeUi);
        closeTag("special-ui");
    }

    private void appendSubsetIncludeUi(SubsetIncludeUi includeUi) throws IOException {
        ExtendedIncludeKey includeKey = includeUi.getExtendedIncludeKey();
        openTag("subset-ui");
        if (includeKey.isMaster()) {
            addEmptyElement("master");
        }
        addSimpleElement("subset", includeKey.getSubsetKey().getKeyString());
        String mode = includeKey.getMode();
        if (mode.length() > 0) {
            addSimpleElement("mode", mode);
        }
        int weightFilter = includeKey.getWeightFilter();
        if (weightFilter != -1) {
            addSimpleElement("weight", String.valueOf(weightFilter));
        }
        appendStatus(includeUi);
        appendCustomLabels(includeUi);
        appendOptions(includeUi);
        appendAttributes(includeUi);
        closeTag("subset-ui");
    }

    private void appendDataUi(DataUi dataUi) throws IOException {
        ExternalSourceDef externalSourceDef = dataUi.getExternalSourceDef();
        startOpenTag("data-ui");
        addAttribute("name", dataUi.getDataName());
        addAttribute("type", externalSourceDef.getType());
        endOpenTag();
        for (String paramName : externalSourceDef.getParamNameSet()) {
            startOpenTag("param");
            addAttribute("name", paramName);
            endOpenTag();
            addText(externalSourceDef.getParam(paramName));
            closeTag("param", false);
        }
        appendStatus(dataUi);
        LabelUtils.addLabels(this, dataUi.getLabels());
        appendOptions(dataUi);
        appendAttributes(dataUi);
        closeTag("data-ui");
    }

    private void appendOptions(UiComponent uiComponent) throws IOException {
        for (String name : uiComponent.getOptionNameSet()) {
            Object obj = uiComponent.getOption(name);
            if (obj instanceof String) {
                String value = (String) obj;
                if (StringUtils.isCleanString(value)) {
                    appendCleanOption(name, value);
                } else {
                    appendRawOption(name, value);
                }
            } else if (obj instanceof MultiStringable) {
                appendOption(name, (MultiStringable) obj);
            }
        }
    }

    private void appendCleanOption(String name, String value) throws IOException {
        startOpenTag("option")
                .addAttribute("name", name)
                .addAttribute("value", value)
                .closeEmptyTag();
    }

    private void appendRawOption(String name, String value) throws IOException {
        startOpenTag("option")
                .addAttribute("name", name)
                .endOpenTag();
        openTag("raw");
        addCData(value);
        closeTag("raw", false);
        closeTag("option");
    }

    private void appendOption(String name, MultiStringable multiStringable) throws IOException {
        startOpenTag("option")
                .addAttribute("name", name)
                .endOpenTag();
        for (String value : multiStringable.toStringArray()) {
            openTag("value");
            addText(value);
            closeTag("value", false);
        }
        closeTag("option");
    }

    private void appendCustomLabels(IncludeUi includeUi) throws IOException {
        Labels labels = includeUi.getCustomLabels();
        if (labels == null) {
            return;
        }
        openTag("custom");
        LabelUtils.addLabels(this, labels);
        closeTag("custom");
    }

    private void appendAttributes(UiComponent uiComponent) throws IOException {
        AttributeUtils.addAttributes(this, uiComponent.getAttributes());
    }

    private void appendStatus(UiComponent uiComponent) throws IOException {
        String status = uiComponent.getStatus();
        if (!status.equals(BdfServerConstants.DEFAULT_STATUS)) {
            addSimpleElement("status", status);
        }
    }

}
