/* BdfServer_HtmlProducers - Copyright (c) 2011-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.htmlproducers.corpus;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.BdfServerConstants;
import fr.exemole.bdfserver.api.externalsource.ExternalSourceType;
import fr.exemole.bdfserver.api.namespaces.CommandSpace;
import fr.exemole.bdfserver.api.subsettree.GroupNode;
import fr.exemole.bdfserver.api.subsettree.JunctionSubsetNode;
import fr.exemole.bdfserver.api.subsettree.SubsetTree;
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.commands.corpus.AbstractCorpusCreationCommand;
import fr.exemole.bdfserver.commands.corpus.CloneCommand;
import fr.exemole.bdfserver.commands.corpus.CommentChangeCommand;
import fr.exemole.bdfserver.commands.corpus.CommentCreationCommand;
import fr.exemole.bdfserver.commands.corpus.CommentRemoveCommand;
import fr.exemole.bdfserver.commands.corpus.ConfChangeCommand;
import fr.exemole.bdfserver.commands.corpus.ConversionCommand;
import fr.exemole.bdfserver.commands.corpus.CorpusAttributeChangeCommand;
import fr.exemole.bdfserver.commands.corpus.CorpusCreationCommand;
import fr.exemole.bdfserver.commands.corpus.CorpusPhrasesCommand;
import fr.exemole.bdfserver.commands.corpus.CorpusRemoveCommand;
import fr.exemole.bdfserver.commands.corpus.DataChangeCommand;
import fr.exemole.bdfserver.commands.corpus.DataCreationCommand;
import fr.exemole.bdfserver.commands.corpus.DuplicationCommand;
import fr.exemole.bdfserver.commands.corpus.FicheAttributeChangeCommand;
import fr.exemole.bdfserver.commands.corpus.FicheDiscardCommand;
import fr.exemole.bdfserver.commands.corpus.FicheRemoveCommand;
import fr.exemole.bdfserver.commands.corpus.FicheRetrieveCommand;
import fr.exemole.bdfserver.commands.corpus.FieldCreationCommand;
import fr.exemole.bdfserver.commands.corpus.FieldRemoveCommand;
import fr.exemole.bdfserver.commands.corpus.ImageToIllustrationCommand;
import fr.exemole.bdfserver.commands.corpus.IncludeChangeCommand;
import fr.exemole.bdfserver.commands.corpus.IncludeRemoveCommand;
import fr.exemole.bdfserver.commands.corpus.JunctionCopyCommand;
import fr.exemole.bdfserver.commands.corpus.ReloadCommand;
import fr.exemole.bdfserver.commands.corpus.ReponderationCommand;
import fr.exemole.bdfserver.commands.corpus.SectionMergeCommand;
import fr.exemole.bdfserver.commands.corpus.SpecialIncludeAddCommand;
import fr.exemole.bdfserver.commands.corpus.SubsetIncludeCreationCommand;
import fr.exemole.bdfserver.commands.corpus.SubtitleActivationCommand;
import fr.exemole.bdfserver.commands.corpus.UiComponentAttributesCommand;
import fr.exemole.bdfserver.commands.corpus.UiComponentOptionsCommand;
import fr.exemole.bdfserver.commands.corpus.UiComponentPositionCommand;
import fr.exemole.bdfserver.html.BdfHtmlUtils;
import fr.exemole.bdfserver.html.consumers.AttributesText;
import fr.exemole.bdfserver.html.consumers.Common;
import fr.exemole.bdfserver.html.consumers.Grid;
import fr.exemole.bdfserver.html.consumers.JunctionSelection;
import fr.exemole.bdfserver.html.consumers.LangRows;
import fr.exemole.bdfserver.html.consumers.MetadataPhrases;
import fr.exemole.bdfserver.html.consumers.SelectOption;
import fr.exemole.bdfserver.html.consumers.SubsetTitle;
import fr.exemole.bdfserver.html.consumers.SubsetTreeOptions;
import fr.exemole.bdfserver.html.consumers.Tree;
import fr.exemole.bdfserver.html.consumers.attributes.Appelant;
import fr.exemole.bdfserver.html.consumers.attributes.Deploy;
import fr.exemole.bdfserver.html.consumers.attributes.InputPattern;
import fr.exemole.bdfserver.html.consumers.commandbox.Flag;
import static fr.exemole.bdfserver.htmlproducers.CommandBoxUtils.insert;
import fr.exemole.bdfserver.tools.L10nUtils;
import fr.exemole.bdfserver.tools.externalsource.ExternalSourceUtils;
import fr.exemole.bdfserver.tools.ficheform.FicheFormUtils;
import fr.exemole.bdfserver.tools.subsettree.TreeFilterEngine;
import fr.exemole.bdfserver.tools.subsettree.TreeUtils;
import fr.exemole.bdfserver.tools.ui.MetadataPhraseDefCatalog;
import fr.exemole.bdfserver.tools.ui.UiUtils;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.function.Consumer;
import net.fichotheque.FichothequeConstants;
import net.fichotheque.Subset;
import net.fichotheque.SubsetItem;
import net.fichotheque.SubsetKey;
import net.fichotheque.addenda.Document;
import net.fichotheque.album.Illustration;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.corpus.Fiches;
import net.fichotheque.corpus.metadata.CorpusField;
import net.fichotheque.corpus.metadata.CorpusMetadata;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.externalsource.ExternalSourceDef;
import net.fichotheque.junction.Junctions;
import net.fichotheque.namespaces.BdfSpace;
import net.fichotheque.tools.corpus.FichesBuilder;
import net.fichotheque.utils.AddendaUtils;
import net.fichotheque.utils.CorpusMetadataUtils;
import net.mapeadores.util.attr.Attribute;
import net.mapeadores.util.html.CommandBox;
import net.mapeadores.util.html.HA;
import net.mapeadores.util.html.HtmlAttributes;
import net.mapeadores.util.html.HtmlPrinter;
import net.mapeadores.util.html.HtmlWrapper;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.Langs;
import net.mapeadores.util.text.Labels;


/**
 *
 * @author Vincent Calame
 */
public final class CorpusCommandBoxUtils {

    private final static HtmlWrapper FICHES_TREE = Tree.tree("command-fiches-Tree");
    private final static SelectOption[] INPUTTYPE_OPTIONS = {
        SelectOption.init(BdfServerConstants.INPUT_TEXT).textL10nObject("_ label.corpus.inputtype_text"),
        SelectOption.init(BdfServerConstants.INPUT_SELECT).textL10nObject("_ label.corpus.inputtype_select"),
        SelectOption.init(BdfServerConstants.INPUT_CHECK).textL10nObject("_ label.corpus.inputtype_check"),
        SelectOption.init(BdfServerConstants.INPUT_RADIO).textL10nObject("_ label.corpus.inputtype_radio"),
        SelectOption.init(BdfServerConstants.INPUT_FICHESTYLE).textL10nObject("_ label.corpus.inputtype_fichestyle")
    };
    private final static SelectOption[] WIDTHTYPE_OPTIONS = {
        SelectOption.init(BdfServerConstants.WIDTH_SMALL).textL10nObject("_ label.corpus.size_small"),
        SelectOption.init(BdfServerConstants.WIDTH_MEDIUM).textL10nObject("_ label.corpus.size_medium"),
        SelectOption.init(BdfServerConstants.WIDTH_LARGE).textL10nObject("_ label.corpus.size_large")
    };
    private final static SelectOption[] STATUS_OPTIONS = {
        SelectOption.init(BdfServerConstants.DEFAULT_STATUS).text("---"),
        SelectOption.init(BdfServerConstants.MANDATORY_STATUS).textL10nObject("_ label.corpus.status_mandatory"),
        SelectOption.init(BdfServerConstants.OPTIONAL_STATUS).textL10nObject("_ label.corpus.status_optional"),
        SelectOption.init(BdfServerConstants.OBSOLETE_STATUS).textL10nObject("_ label.corpus.status_obsolete")
    };
    private final static SelectOption[] VARIANT_OPTIONS = {
        SelectOption.init("").text("---"),
        SelectOption.init("table").textL10nObject("_ label.corpus.variant_fichetable")
    };

    private CorpusCommandBoxUtils() {
    }

    public static boolean printCorpusCreationBox(HtmlPrinter hp, CommandBox commandBox, BdfServer bdfServer, Lang workingLang) {
        commandBox = commandBox.derive(CorpusCreationCommand.COMMANDNAME, CorpusCreationCommand.COMMANDKEY)
                .__(Flag.UPDATE_COLLECTIONS)
                .__(Flag.UPDATE_CORPUS_TREE)
                .actionCssClass("action-New")
                .submitLocKey("_ submit.corpus.corpuscreation");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.textInputRow("_ label.corpus.newcorpusname", hp.name(CorpusCreationCommand.NEWCORPUS_PARAMNAME).size("30").populate(InputPattern.TECHNICAL_STRICT).required(true)))
                .__(printSatelliteOpportunities(hp, bdfServer, workingLang))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printConfChangeBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus) {
        commandBox = commandBox.derive(ConfChangeCommand.COMMANDNAME, ConfChangeCommand.COMMANDKEY)
                .__(insert(corpus))
                .__(Flag.UPDATE_CORPUS_TREE)
                .actionCssClass("action-Edit")
                .submitLocKey("_ submit.corpus.confchange");
        hp
                .__start(commandBox)
                .P("global-SubTitle")
                .__localize("_ info.corpus.confchange")
                ._P()
                .TEXTAREA(HA.name(ConfChangeCommand.CONF_PARAM).cols(60).rows(20).attr("data-codemirror-mode", "properties").attr("data-codemirror-options", "numbers"))
                ._TEXTAREA()
                .__end(commandBox);
        return true;
    }

    public static boolean printCorpusPhrasesBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, BdfServer bdfServer, Lang lang) {
        Langs langs = bdfServer.getLangConfiguration().getWorkingLangs();
        CorpusMetadata corpusMetadata = corpus.getCorpusMetadata();
        MetadataPhrases metadataPhrases = MetadataPhrases.init(corpusMetadata, langs, "_ label.corpus.title")
                .addDef(MetadataPhraseDefCatalog.FICHE_PHRASEDEF)
                .addDef(MetadataPhraseDefCatalog.NEWFICHE_PHRASEDEF);
        if (corpus.getMasterSubset() != null) {
            metadataPhrases.addDef(MetadataPhraseDefCatalog.SATELLITE_PHRASEDEF);
        }
        metadataPhrases
                .populateFromAttributes(corpus)
                .addExtensionPhraseDefList(bdfServer);
        commandBox = commandBox.derive(CorpusPhrasesCommand.COMMANDNAME, CorpusPhrasesCommand.COMMANDKEY)
                .__(insert(corpus))
                .__(Flag.UPDATE_CORPUS_TREE)
                .actionCssClass("action-Labels")
                .submitLocKey("_ submit.corpus.corpusphrases");
        hp
                .__start(commandBox)
                .__(metadataPhrases)
                .__(printCorpusFieldList(hp, CorpusMetadataUtils.getSpecialCorpusFieldList(corpusMetadata, true), "_ title.corpus.labellist_special", langs, lang))
                .__(printCorpusFieldList(hp, corpusMetadata.getPropList(), "_ title.corpus.labellist_prop", langs, lang))
                .__(printCorpusFieldList(hp, corpusMetadata.getInfoList(), "_ title.corpus.labellist_info", langs, lang))
                .__(printCorpusFieldList(hp, corpusMetadata.getSectionList(), "_ title.corpus.labellist_section", langs, lang))
                .__end(commandBox);
        return true;
    }

    public static boolean printSubtitleActivationBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus) {
        commandBox = commandBox.derive(SubtitleActivationCommand.COMMANDNAME, SubtitleActivationCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-FieldCreate")
                .submitLocKey("_ submit.corpus.subtitleactivation");
        hp
                .__start(commandBox)
                .__end(commandBox);
        return true;
    }

    public static boolean printFieldCreationBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, short fieldCategory, Langs langs) {
        commandBox = commandBox.derive(FieldCreationCommand.COMMANDNAME, FieldCreationCommand.getCommandKey(fieldCategory))
                .__(insert(corpus))
                .hidden(FieldCreationCommand.CATEGORY_PARAMNAME, FieldKey.categoryToString(fieldCategory))
                .actionCssClass("action-FieldCreate")
                .submitLocKey("_ submit.corpus.fieldcreation");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.textInputRow("_ label.corpus.newfieldname", hp.name(FieldCreationCommand.NEWFIELDNAME_PARAMNAME).size("30").populate(InputPattern.TECHNICAL_STRICT).required(true)))
                .__(printFieldTypeSelectRow(hp, fieldCategory));
        if (langs.size() == 1) {
            hp
                    .__(Grid.textInputRow("_ label.corpus.fieldlabel", hp.name(FieldCreationCommand.NEWLABEL_PARAMPREFIX + langs.getStringValue(0)).size("30")));
        } else {
            hp
                    .__(Grid.choiceSetRow("_ label.corpus.fieldlabels", () -> {
                        hp
                                .__(Grid.START_SUBTABLE)
                                .__(LangRows.init(FieldCreationCommand.NEWLABEL_PARAMPREFIX, null, langs).cols(25))
                                .__(Grid.END_SUBTABLE);
                    }));
        }
        hp
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printFicheRemoveBox(HtmlPrinter hp, CommandBox commandBox, FicheMeta ficheMeta, Lang workingLang, Locale formatLocale) {
        commandBox = commandBox.derive(FicheRemoveCommand.COMMANDNAME, FicheRemoveCommand.COMMANDKEY)
                .__(insert(ficheMeta))
                .actionCssClass("action-Delete")
                .submitLocKey("_ submit.corpus.ficheremove");
        hp
                .__start(commandBox)
                .__(printSatelliteFicheWarning(hp, ficheMeta, "_ warning.corpus.satelliteremove", workingLang, formatLocale))
                .__(Grid.START)
                .__(Grid.textAreaBlockRow("_ label.corpus.discardtext_remove",
                        hp.name(FicheRemoveCommand.DISCARDTEXT_PARAMNAME).cols(60).rows(6).classes("command-LargeInput"),
                        new DiscardText(ficheMeta)))
                .__(Grid.END)
                .__(Common.REMOVE_CONFIRM_CHECK)
                .__end(commandBox);
        return true;
    }

    public static boolean printFicheDiscardBox(HtmlPrinter hp, CommandBox commandBox, FicheMeta ficheMeta, Lang workingLang, Locale formatLocale) {
        String textAreaId = hp.generateId();
        commandBox = commandBox.derive(FicheDiscardCommand.COMMANDNAME, FicheDiscardCommand.COMMANDKEY)
                .__(insert(ficheMeta))
                .actionCssClass("action-Discard")
                .submitLocKey("_ submit.corpus.fichediscard");
        hp
                .__start(commandBox)
                .__(printSatelliteFicheWarning(hp, ficheMeta, "_ warning.corpus.satellitediscard", workingLang, formatLocale))
                .__(Grid.START)
                .__(Grid.textAreaBlockRow("_ label.corpus.discardtext",
                        HA.name(FicheDiscardCommand.DISCARDTEXT_PARAMNAME).id(textAreaId).cols(60).rows(6).classes("command-LargeInput"),
                        new DiscardText(ficheMeta)))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printFicheRetrieveBox(HtmlPrinter hp, CommandBox commandBox, FicheMeta ficheMeta, Lang workingLang, Locale formatLocale) {
        String textAreaId = hp.generateId();
        commandBox = commandBox.derive(FicheRetrieveCommand.COMMANDNAME, FicheRetrieveCommand.COMMANDKEY)
                .__(insert(ficheMeta))
                .actionCssClass("action-Retrieve")
                .submitLocKey("_ submit.corpus.ficheretrieve");
        hp
                .__start(commandBox)
                .__(printSatelliteFicheWarning(hp, ficheMeta, "_ warning.corpus.satelliteretrieve", workingLang, formatLocale))
                .__(Grid.START)
                .__(Grid.textAreaBlockRow("_ label.corpus.discardtext",
                        HA.name("").id(textAreaId).disabled(true).cols(60).rows(6).classes("command-LargeInput"),
                        new DiscardText(ficheMeta)))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printJunctionCopyBox(HtmlPrinter hp, CommandBox commandBox, BdfServer bdfServer, FicheMeta ficheMeta, Lang workingLang, Locale formatLocale) {
        SubsetTree addendaTree = TreeFilterEngine.junction(ficheMeta, bdfServer.getTreeManager().getSubsetTree(SubsetKey.CATEGORY_ADDENDA));
        SubsetTree albumTree = TreeFilterEngine.junction(ficheMeta, bdfServer.getTreeManager().getSubsetTree(SubsetKey.CATEGORY_ALBUM));
        boolean withDocuments = !addendaTree.getNodeList().isEmpty();
        boolean withIllustrations = !albumTree.getNodeList().isEmpty();
        if (!withDocuments && !withIllustrations) {
            return false;
        }
        commandBox = commandBox.derive(JunctionCopyCommand.COMMANDNAME, JunctionCopyCommand.COMMANDKEY)
                .__(insert(ficheMeta))
                .actionCssClass("action-Duplicate")
                .submitLocKey("_ submit.corpus.junctioncopy");
        hp
                .__start(commandBox);
        if (withDocuments) {
            hp
                    .H2()
                    .__localize("_ title.global.addenda_collection")
                    ._H2()
                    .UL("global-JunctionList")
                    .__(printJunctionNodeList(hp, bdfServer, addendaTree.getNodeList(), workingLang, JunctionCopyCommand.DOCUMENTS_PARAMNAME))
                    ._UL();

        }
        if (withIllustrations) {
            hp
                    .H2()
                    .__localize("_ title.global.album_collection")
                    ._H2()
                    .UL("global-JunctionList")
                    .__(printJunctionNodeList(hp, bdfServer, albumTree.getNodeList(), workingLang, JunctionCopyCommand.ILLUSTRATIONS_PARAMNAME))
                    ._UL();
        }
        hp
                .H2()
                .__localize("_ title.corpus.destination")
                ._H2()
                .__(Grid.START)
                .__(Grid.textInputRow("_ label.corpus.destinatinonid", hp.name(JunctionCopyCommand.DESTINATION_PARAMNAME)
                        .size("20")
                        .populate(Appelant.fiche().limit(1))))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printFieldRemoveBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, Lang lang) {
        commandBox = commandBox.derive(FieldRemoveCommand.COMMANDNAME, FieldRemoveCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-FieldRemove")
                .submitLocKey("_ submit.corpus.fieldremove");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.selectRow("_ label.corpus.fieldtoremove", hp.name(FieldRemoveCommand.FIELDKEY_PARAMNAME),
                        () -> {
                            hp
                                    .OPTION("", true)
                                    .__escape("---")
                                    ._OPTION()
                                    .__(printFieldKeySelectOptions(hp, corpus, lang, false));
                        }))
                .__(Grid.END)
                .__(Common.REMOVE_CONFIRM_CHECK)
                .__end(commandBox);
        return true;
    }


    public static boolean printUiComponentPositionBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, UiComponents uiComponents, BdfServer bdfServer, Lang lang) {
        commandBox = commandBox.derive(UiComponentPositionCommand.COMMANDNAME, UiComponentPositionCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-ComponentPosition")
                .submitLocKey("_ submit.corpus.uicomponentposition");
        hp
                .__start(commandBox)
                .TEXTAREA(HA.name(UiComponentPositionCommand.COMPONENTPOSITION_PARAMNAME).cols(60).rows(20).attr("data-codemirror-mode", "uicomponents"));
        for (UiComponent uiComponent : uiComponents.getUiComponentList()) {
            hp
                    .__escape(uiComponent.getName());
            String label = L10nUtils.getTitle(bdfServer, corpus, uiComponent, lang);
            if (label != null) {
                hp
                        .__space()
                        .__escape('(')
                        .__escape(label)
                        .__escape(')');
            }
            hp
                    .__newLine();
        }
        hp
                ._TEXTAREA()
                .__end(commandBox);
        return true;
    }

    public static boolean printUiComponentOptionsBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, UiComponents uiComponents, BdfServer bdfServer, Lang lang) {
        commandBox = commandBox.derive(UiComponentOptionsCommand.COMMANDNAME, UiComponentOptionsCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-ComponentOptions")
                .submitLocKey("_ submit.corpus.uicomponentoptions");
        hp
                .__start(commandBox)
                .DL("global-DL");
        for (UiComponent uiComponent : uiComponents.getUiComponentList()) {
            if (uiComponent instanceof FieldUi) {
                FieldUi fieldUi = (FieldUi) uiComponent;
                if (hasUiOption(fieldUi)) {
                    String name = fieldUi.getFieldString();
                    boolean blockField = false;
                    FieldKey fieldKey = fieldUi.getFieldKey();
                    if (fieldKey.isSection()) {
                        blockField = true;
                    } else if (fieldKey.isInfo()) {
                        CorpusField corpusField = corpus.getCorpusMetadata().getCorpusField(fieldKey);
                        if (corpusField != null) {
                            blockField = corpusField.isBlockDisplayInfoField();
                        }
                    }
                    hp
                            .__(printComponentUiDt(hp, corpus, uiComponent, bdfServer, lang))
                            .DD()
                            .__(printOptions(hp, name, fieldUi, blockField))
                            ._DD();
                }
            } else if (uiComponent instanceof SpecialIncludeUi) {
                SpecialIncludeUi includeUi = (SpecialIncludeUi) uiComponent;
                String name = includeUi.getName();
                if (name.equals(FichothequeConstants.LIAGE_NAME)) {
                    hp
                            .__(printComponentUiDt(hp, corpus, uiComponent, bdfServer, lang))
                            .DD()
                            .__(printOptions(hp, name, includeUi, false))
                            ._DD();
                }
            } else if (uiComponent instanceof SubsetIncludeUi) {
                SubsetIncludeUi includeUi = (SubsetIncludeUi) uiComponent;
                String name = includeUi.getName();
                hp
                        .__(printComponentUiDt(hp, corpus, uiComponent, bdfServer, lang))
                        .DD()
                        .__(printOptions(hp, name, includeUi, false))
                        ._DD();
            }
        }
        hp
                ._DL()
                .__end(commandBox);
        return true;
    }

    private static boolean hasUiOption(FieldUi fieldUi) {
        switch (fieldUi.getFieldString()) {
            case FieldKey.SPECIAL_LANG:
                return false;
            default:
                return true;
        }
    }

    public static boolean printUiComponentAttributesBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, UiComponents uiComponents, BdfServer bdfServer, Lang lang) {
        Set<String> existingSet = new HashSet<String>();
        commandBox = commandBox.derive(UiComponentAttributesCommand.COMMANDNAME, UiComponentAttributesCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-ComponentAttributes")
                .submitLocKey("_ submit.global.attributechange");
        hp
                .__start(commandBox)
                .DL("global-DL");
        for (UiComponent uiComponent : uiComponents.getUiComponentList()) {
            String name = uiComponent.getName();
            if (!existingSet.contains(name)) {
                existingSet.add(name);
                hp
                        .__(printComponentUiDt(hp, corpus, uiComponent, bdfServer, lang))
                        .DD()
                        .TEXTAREA(hp.name(name + UiComponentAttributesCommand.ATTRIBUTES_PARAMSUFFIX).rows(4).cols(75).attr("data-codemirror-mode", "attributes"))
                        .__(new AttributesText(uiComponent.getAttributes()))
                        ._TEXTAREA()
                        ._DD();
            }
        }
        hp
                ._DL()
                .__end(commandBox);
        return true;
    }

    public static boolean printCorpusRemoveBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus) {
        commandBox = commandBox.derive(CorpusRemoveCommand.COMMANDNAME, CorpusRemoveCommand.COMMANDKEY)
                .__(insert(corpus))
                .__(Flag.UPDATE_COLLECTIONS)
                .__(Flag.UPDATE_CORPUS_TREE)
                .actionCssClass("action-Delete")
                .submitLocKey("_ submit.corpus.corpusremove");
        hp
                .__start(commandBox)
                .__(Common.REMOVE_CONFIRM_CHECK)
                .__end(commandBox);
        return true;
    }

    public static boolean printIncludeChangeBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, IncludeUi includeUi, Langs workingLangs) {
        String targetId = hp.generateId();
        Labels labels = includeUi.getCustomLabels();
        boolean custom = (labels != null);
        commandBox = commandBox.derive(IncludeChangeCommand.COMMANDNAME, IncludeChangeCommand.COMMANDKEY)
                .__(insert(corpus))
                .hidden(IncludeChangeCommand.KEY_PARAMNAME, includeUi.getName())
                .submitLocKey("_ submit.corpus.includechange");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.checkboxRow("_ label.corpus.customlabels", hp.name(IncludeChangeCommand.CUSTOM_PARAMNAME).value("1").checked(custom).populate(Deploy.checkbox(targetId)),
                        () -> {
                            hp
                                    .DIV(Grid.detailPanelTable().id(targetId).addClass(!custom, "hidden"))
                                    .__(LangRows.init(IncludeChangeCommand.TITLE_PARAMPREFIX, labels, workingLangs).cols(30))
                                    ._DIV();
                        }))
                .__(Grid.textAreaInputRow("_ label.global.attributes", hp.name(IncludeChangeCommand.ATTRIBUTES_PARAMNAME).rows(4).cols(50).attr("data-codemirror-mode", "attributes"),
                        new AttributesText(includeUi.getAttributes())))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }


    public static boolean printDataChangeBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, DataUi dataUi, Langs workingLangs) {
        commandBox = commandBox.derive(DataChangeCommand.COMMANDNAME, DataChangeCommand.COMMANDKEY)
                .__(insert(corpus))
                .hidden(DataChangeCommand.NAME_PARAMNAME, dataUi.getDataName())
                .submitLocKey("_ submit.corpus.datachange");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .DIV("grid-Row")
                .DIV("grid-UniqueCell")
                .__localize("_ title.corpus.includelabels")
                .DIV(Grid.detailPanelTable())
                .__(LangRows.init(DataChangeCommand.TITLE_PARAMPREFIX, dataUi.getLabels(), workingLangs).cols(30))
                ._DIV()
                ._DIV()
                ._DIV()
                .__(printExternalSourceParams(hp, dataUi.getExternalSourceDef()))
                .__(Grid.textAreaInputRow("_ label.global.attributes", hp.name(DataChangeCommand.ATTRIBUTES_PARAMNAME).rows(4).cols(50).attr("data-codemirror-mode", "attributes"),
                        new AttributesText(dataUi.getAttributes())))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    private static boolean printExternalSourceParams(HtmlPrinter hp, ExternalSourceDef externalSourceDef) {
        ExternalSourceType externalSourceType = ExternalSourceUtils.getMatchingExternalSourceType(externalSourceDef);
        for (ExternalSourceType.Param param : externalSourceType.getParamList()) {
            String paramName = param.getName();
            String value = externalSourceDef.getParam(paramName);
            if (value == null) {
                value = "";
            }
            hp
                    .__(Grid.textInputRow(param.getL10nObject(), hp.name(DataChangeCommand.PARAM_PARAMPREFIX + paramName).value(value).size("30")));
        }
        return true;
    }

    public static boolean printSpecialIncludeAddBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, List<SelectOption> optionList, String selected) {
        commandBox = commandBox.derive(SpecialIncludeAddCommand.COMMANDNAME, SpecialIncludeAddCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-New")
                .submitLocKey("_ submit.corpus.specialincludeadd");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.selectRow("_ label.corpus.specialinclude", hp.name(SpecialIncludeAddCommand.NAME_PARAMNAME), () -> {
                    for (SelectOption selectOption : optionList) {
                        selectOption.accept(hp, selected);
                    }
                }))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printDataCreationBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, BdfServer bdfServer) {
        List<ExternalSourceType> list = ExternalSourceUtils.getDataUiAvalaibleTypeList(bdfServer);
        commandBox = commandBox.derive(DataCreationCommand.COMMANDNAME, DataCreationCommand.COMMANDKEY)
                .__(insert(corpus))
                .submitLocKey("_ submit.corpus.datacreation");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.textInputRow("_ label.global.name", hp.name(DataCreationCommand.NAME_PARAMNAME).size("30").populate(InputPattern.TECHNICAL_STRICT).required(true)))
                .__(Grid.selectRow("_ label.corpus.externalsourcetype", hp.name(DataCreationCommand.TYPE_PARAMNAME), () -> {
                    boolean selected = true;
                    for (ExternalSourceType externalSourceType : list) {
                        hp
                                .OPTION(externalSourceType.getName(), selected)
                                .__localize(externalSourceType.getL10nObject())
                                ._OPTION();
                        selected = false;
                    }
                }))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printSubsetIncludeCreationBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, BdfServer bdfServer, Lang workingLang, short subsetCategory) {
        SubsetTree subsetTree = bdfServer.getTreeManager().getSubsetTree(subsetCategory);
        if (TreeUtils.getFirstSubsetKey(subsetTree) == null) {
            return false;
        }
        commandBox = commandBox.derive(SubsetIncludeCreationCommand.COMMANDNAME, SubsetIncludeCreationCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass(BdfHtmlUtils.getAddCss(subsetCategory))
                .submitLocKey("_ submit.corpus.subsetincludecreation");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.selectRow(BdfHtmlUtils.getSubsetCategoryLocKey(subsetCategory), hp.name(SubsetIncludeCreationCommand.SUBSET_PARAMNAME),
                        SubsetTreeOptions.init(subsetTree, bdfServer, workingLang).withKeys(true)
                ))
                .__if(((subsetCategory == SubsetKey.CATEGORY_CORPUS) || (subsetCategory == SubsetKey.CATEGORY_THESAURUS)),
                        () -> {
                            Subset masterSubset = corpus.getMasterSubset();
                            if ((masterSubset != null) && ((subsetCategory == SubsetKey.CATEGORY_CORPUS) || ((subsetCategory == SubsetKey.CATEGORY_THESAURUS) && (masterSubset instanceof Corpus)))) {
                                String l10nKey = getMasterL10nKey(masterSubset.getSubsetKey().getCategory());
                                hp
                                        .__(Grid.checkboxRow(l10nKey, hp.name(SubsetIncludeCreationCommand.MASTERINCLUDE_PARAMNAME).value("1")));
                            }
                        }
                )
                .__(Grid.textInputRow("_ label.global.mode", hp.name(SubsetIncludeCreationCommand.MODE_PARAMNAME).size("15").populate(InputPattern.TECHNICAL_STRICT)))
                .__(Grid.choiceSetRow("_ label.global.weight",
                        () -> {
                            hp
                                    .__(Grid.radioCell("_ label.corpus.weightfilter_no", hp.name(SubsetIncludeCreationCommand.WEIGHTFILTER_PARAMNAME).value(SubsetIncludeCreationCommand.NO_WEIGHTFILTER_PARAMVALUE).checked(true)))
                                    .__(Grid.radioCell("_ label.corpus.weightfilter_yes", hp.name(SubsetIncludeCreationCommand.WEIGHTFILTER_PARAMNAME).value(SubsetIncludeCreationCommand.YES_WEIGHTFILTER_PARAMVALUE).checked(false),
                                            () -> {
                                                hp
                                                        .__(Grid.START)
                                                        .__(Grid.textInputRow("_ label.global.weight", hp.name(SubsetIncludeCreationCommand.WEIGHTFILTERVALUE_PARAMNAME).size("3")))
                                                        .__(Grid.END);
                                            }));
                        }))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printComponentRemoveBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, UiComponent uiComponent) {
        commandBox = commandBox.derive(IncludeRemoveCommand.COMMANDNAME, IncludeRemoveCommand.COMMANDKEY)
                .__(insert(corpus))
                .hidden(IncludeRemoveCommand.NAME_PARAMNAME, uiComponent.getName())
                .actionCssClass("action-Delete")
                .submitLocKey("_ submit.corpus.includeremove");
        hp
                .__start(commandBox)
                .__end(commandBox);
        return true;
    }

    public static boolean printCommentChangeBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, CommentUi commentUi, Lang[] workingLangArray) {
        String[] htmlArray = UiUtils.toStringArray(commentUi, workingLangArray);
        commandBox = commandBox.derive(CommentChangeCommand.COMMANDNAME, CommentChangeCommand.COMMANDKEY)
                .__(insert(corpus))
                .hidden(CommentChangeCommand.NAME_PARAMNAME, commentUi.getCommentName())
                .submitLocKey("_ submit.corpus.commentchange");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(LangRows.init(CommentChangeCommand.COMMENT_PREFIX, workingLangArray, htmlArray).cols(77).rows(9).codemirrorMode("html"))
                .__(Grid.END)
                .__(Grid.START)
                .__(printCommentLocationRadioList(hp, commentUi.getLocation()))
                .__(Grid.textAreaInputRow("_ label.global.attributes", hp.name(CommentChangeCommand.ATTRIBUTES_PARAMNAME).rows(4).cols(50).attr("data-codemirror-mode", "attributes"),
                        new AttributesText(commentUi.getAttributes())))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printCommentCreationBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, Lang[] langArray) {
        int length = langArray.length;
        String[] empty = new String[length];
        for (int i = 0; i < length; i++) {
            empty[i] = "";
        }
        commandBox = commandBox.derive(CommentCreationCommand.COMMANDNAME, CommentCreationCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-CommentAdd")
                .submitLocKey("_ submit.corpus.commentcreation");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(printCommentLocationRadioList(hp, CommentUi.ALL_MASK))
                .__(Grid.END)
                .__(Grid.START)
                .__(LangRows.init(CommentChangeCommand.COMMENT_PREFIX, langArray, empty).cols(77).rows(9).codemirrorMode("html"))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }


    public static boolean printCommentRemoveBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, CommentUi commentUi) {
        commandBox = commandBox.derive(CommentRemoveCommand.COMMANDNAME, CommentRemoveCommand.COMMANDKEY)
                .__(insert(corpus))
                .hidden(CommentRemoveCommand.NAME_PARAMNAME, commentUi.getCommentName())
                .actionCssClass("action-Delete")
                .submitLocKey("_ submit.corpus.commentremove");
        hp
                .__start(commandBox)
                .__(Common.REMOVE_CONFIRM_CHECK)
                .__end(commandBox);
        return true;
    }

    public static boolean printReloadBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus) {
        commandBox = commandBox.derive(ReloadCommand.COMMANDNAME, ReloadCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-Refresh")
                .submitLocKey("_ submit.corpus.reload");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.checkboxRow("_ label.corpus.fichepurge", hp.name(ReloadCommand.PURGE_PARAMNAME).value("1").checked(false)))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printCloneBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, BdfServer bdfServer, Lang workingLang) {
        commandBox = commandBox.derive(CloneCommand.COMMANDNAME, CloneCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-Duplicate")
                .__(Flag.UPDATE_COLLECTIONS)
                .__(Flag.UPDATE_CORPUS_TREE)
                .submitLocKey("_ submit.corpus.clone");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.textInputRow("_ label.corpus.newcorpusname", hp.name(CloneCommand.NEWCORPUS_PARAMNAME).size("30").populate(InputPattern.TECHNICAL_STRICT).required(true)))
                .__(printSatelliteOpportunities(hp, bdfServer, workingLang))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printConversionBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, Lang lang) {
        commandBox = commandBox.derive(ConversionCommand.COMMANDNAME, ConversionCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-Duplicate")
                .submitLocKey("_ submit.corpus.fieldconversion");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.selectRow("_ label.corpus.old_fieldkey", hp.name(ConversionCommand.FIELD_PARAMNAME), () -> printFieldKeySelectOptions(hp, corpus, lang, true)))
                .__(Grid.selectRow("_ label.corpus.new_fieldcategory", hp.name(ConversionCommand.NEWCATEGORY_PARAMNAME), () -> printCategorySelectOptions(hp)))
                .__(Grid.textInputRow("_ label.corpus.new_fieldname", hp.name(ConversionCommand.NEWNAME_PARAMNAME).size("30")))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printSectionMergeBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, Lang lang) {
        commandBox = commandBox.derive(SectionMergeCommand.COMMANDNAME, SectionMergeCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-FieldRemove")
                .submitLocKey("_ submit.corpus.sectionmerge");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.selectRow("_ label.corpus.fieldkey_origin", hp.name(SectionMergeCommand.ORIGIN_PARAMNAME), () -> printSectionSelectOptions(hp, corpus, lang)))
                .__(Grid.textAreaInputRow("_ label.corpus.transitiontext", hp.name(SectionMergeCommand.TRANSITIONTEXT_PARAMNAME).rows(4).cols(60)))
                .__(Grid.selectRow("_ label.corpus.fieldkey_destination", hp.name(SectionMergeCommand.DESTINATION_PARAMNAME), () -> printSectionSelectOptions(hp, corpus, lang)))
                .__(Grid.END)
                .__(Common.MERGE_CONFIRM_CHECK)
                .__end(commandBox);
        return true;
    }

    public static boolean printDuplicationBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, BdfServer bdfServer, Lang lang) {
        String linkToOriginDetailId = hp.generateId();
        Attribute excludeAttribute = corpus.getCorpusMetadata().getAttributes().getAttribute(CommandSpace.DUPLICATION_EXCLUDE_KEY);
        boolean allChecked = (excludeAttribute == null);
        boolean filterChecked = !allChecked;
        commandBox = commandBox.derive(DuplicationCommand.COMMANDNAME, DuplicationCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-Duplicate")
                .submitLocKey("_ submit.corpus.ficheduplication");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.selectRow("_ label.corpus.destinationcorpus", hp.name(DuplicationCommand.DESTINATION_PARAMNAME),
                        SubsetTreeOptions.init(bdfServer.getTreeManager().getSubsetTree(SubsetKey.CATEGORY_CORPUS), bdfServer, lang)
                                .onlyNames(true)
                                .withKeys(true)
                                .selectedSubsetKey(corpus.getSubsetKey())
                ))
                .__(Grid.choiceSetRow("_ label.corpus.fichesorigin",
                        () -> {
                            hp
                                    .__(Grid.radioCell("_ label.corpus.mode_selection", hp.name(DuplicationCommand.MODE_PARAMNAME).value(DuplicationCommand.SELECTION_MODE_PARAMVALUE).checked(false)))
                                    .__(Grid.radioCell("_ label.corpus.mode_list", hp.name(DuplicationCommand.MODE_PARAMNAME).value(DuplicationCommand.LIST_MODE_PARAMVALUE).checked(true),
                                            () -> {
                                                hp
                                                        .__(Grid.START)
                                                        .__(Grid.textAreaBlockRow("_ label.corpus.idtokens", hp.name(DuplicationCommand.IDTOKENS_PARAMNAME).cols(80).rows(5)))
                                                        .__(Grid.checkboxRow("_ label.corpus.withdestinationids", hp.name(DuplicationCommand.WITHDESTINATIONIDS_PARAMNAME).value("1").checked(false)))
                                                        .__(Grid.END);
                                            }));
                        }))
                .__(Grid.choiceSetRow("_ label.corpus.duplicationfilter",
                        () -> {
                            hp
                                    .__(Grid.radioCell("_ label.corpus.duplicationfilter_all", hp.name(DuplicationCommand.FILTER_PARAMNAME).value(DuplicationCommand.FILTER_ALL_PARAMVALUE).checked(allChecked)))
                                    .__(Grid.radioCell("_ label.corpus.duplicationfilter_ficheonly", hp.name(DuplicationCommand.FILTER_PARAMNAME).value(DuplicationCommand.FILTER_FICHEONLY_PARAMVALUE).checked(false)))
                                    .__(Grid.radioCell("_ label.corpus.duplicationfilter_exclude", hp.name(DuplicationCommand.FILTER_PARAMNAME).value(DuplicationCommand.FILTER_EXCLUDE_PARAMVALUE).checked(filterChecked),
                                            () -> {
                                                hp
                                                        .__(Grid.START)
                                                        .__(Grid.textAreaBlockRow("_ label.corpus.duplicationexclude", hp.name(DuplicationCommand.EXCLUDE_PARAMNAME).cols(80).rows(5),
                                                                () -> {
                                                                    if (excludeAttribute != null) {
                                                                        boolean next = false;
                                                                        for (String value : excludeAttribute) {
                                                                            if (next) {
                                                                                hp.__escape(", ");
                                                                            } else {
                                                                                next = true;
                                                                            }
                                                                            hp.__escape(value);
                                                                        }
                                                                    }
                                                                }))
                                                        .__(Grid.checkboxRow("_ label.corpus.storeexclude", hp.name(DuplicationCommand.STORE_PARAMNAME).value("1").checked(false)))
                                                        .__(Grid.END);
                                            }));
                        }))
                .__(Grid.textAreaInputRow("_ label.corpus.fieldmatching", hp.name(DuplicationCommand.FIELDMATCHING_PARAMNAME).rows(4).cols(50),
                        () -> {
                            hp
                                    .__escape("", true);
                        }))
                .__(Grid.checkboxRow("_ label.corpus.linktoorigin", hp.name(DuplicationCommand.LINKTOORIGIN_PARAMNAME).value("1").checked(false).populate(Deploy.checkbox(linkToOriginDetailId)),
                        () -> {
                            hp
                                    .DIV(Grid.detailPanelTable().id(linkToOriginDetailId).addClass("hidden"))
                                    .__(Grid.textInputRow("_ label.global.mode", hp.name(DuplicationCommand.MODE_LINKTOORIGIN_PARAMNAME).size("15")))
                                    .__(Grid.textInputRow("_ label.global.weight", hp.name(DuplicationCommand.WEIGHT_LINKTOORIGIN_PARAMNAME).size("3")))
                                    ._DIV();
                        }))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printReponderationBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus) {
        commandBox = commandBox.derive(ReponderationCommand.COMMANDNAME, ReponderationCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-Run")
                .submitLocKey("_ submit.corpus.reponderation");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.textInputRow("_ label.corpus.junctionsubset", hp.name(ReponderationCommand.JUNCTIONSUBSET_PARAMNAME).size("30")))
                .__(Grid.choiceSetRow("_ label.corpus.fichesorigin",
                        () -> {
                            hp
                                    .__(Grid.radioCell("_ label.corpus.mode_selection", hp.name(ReponderationCommand.MODE_PARAMNAME).value(ReponderationCommand.SELECTION_MODE_PARAMVALUE).checked(false)))
                                    .__(Grid.radioCell("_ label.corpus.mode_list", hp.name(ReponderationCommand.MODE_PARAMNAME).value(ReponderationCommand.LIST_MODE_PARAMVALUE).checked(true),
                                            () -> {
                                                hp
                                                        .__(Grid.START)
                                                        .__(Grid.textAreaBlockRow("_ label.corpus.idtokens", hp.name(ReponderationCommand.IDTOKENS_PARAMNAME).cols(80).rows(5)))
                                                        .__(Grid.END);
                                            }));
                        }))
                .__(Grid.textInputRow("_ label.corpus.old_mode", hp.name(ReponderationCommand.OLDMODE_PARAMNAME).size("15")))
                .__(Grid.textInputRow("_ label.corpus.old_weight", hp.name(ReponderationCommand.OLDWEIGHT_PARAMNAME).size("3")))
                .__(Grid.textInputRow("_ label.corpus.new_mode", hp.name(ReponderationCommand.NEWMODE_PARAMNAME).size("15")))
                .__(Grid.textInputRow("_ label.corpus.new_weight", hp.name(ReponderationCommand.NEWWEIGHT_PARAMNAME).size("3")))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printCorpusAttributeChangeBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus) {
        commandBox = commandBox.derive(CorpusAttributeChangeCommand.COMMANDNAME, CorpusAttributeChangeCommand.COMMANDKEY)
                .__(insert(corpus))
                .actionCssClass("action-Attributes")
                .submitLocKey("_ submit.global.attributechange");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.textAreaBlockRow("_ label.global.attributes", hp.name(CorpusAttributeChangeCommand.ATTRIBUTES_PARAMNAME).rows(8).cols(75).attr("data-codemirror-mode", "attributes"),
                        new AttributesText(corpus.getCorpusMetadata().getAttributes())))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printFicheAttributeChangeBox(HtmlPrinter hp, CommandBox commandBox, FicheMeta ficheMeta) {
        commandBox = commandBox.derive(FicheAttributeChangeCommand.COMMANDNAME, FicheAttributeChangeCommand.COMMANDKEY)
                .__(insert(ficheMeta))
                .submitLocKey("_ submit.global.attributechange");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.textAreaBlockRow("_ label.global.attributes", HA.name(FicheAttributeChangeCommand.ATTRIBUTES_PARAMNAME).rows(8).cols(75).attr("data-codemirror-mode", "attributes"),
                        new AttributesText(ficheMeta.getAttributes())))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }

    public static boolean printImageToIllustrationBox(HtmlPrinter hp, CommandBox commandBox, Corpus corpus, BdfServer bdfServer, Lang lang) {
        List<CorpusField> imageFieldList = new ArrayList<CorpusField>();
        CorpusMetadata corpusMetadata = corpus.getCorpusMetadata();
        for (CorpusField corpusField : corpusMetadata.getPropList()) {
            switch (corpusField.getFicheItemType()) {
                case CorpusField.ITEM_FIELD:
                case CorpusField.IMAGE_FIELD:
                    imageFieldList.add(corpusField);
                    break;
                default:
                    break;
            }
        }
        if (imageFieldList.isEmpty()) {
            return false;
        }
        UiComponents uiComponents = bdfServer.getUiManager().getMainUiComponents(corpus);
        List<SubsetIncludeUi> albumIncludeList = UiUtils.getSubsetIncludeUiList(uiComponents, SubsetKey.CATEGORY_ALBUM);
        if (albumIncludeList.isEmpty()) {
            return false;
        }
        commandBox = commandBox.derive(ImageToIllustrationCommand.COMMANDNAME, ImageToIllustrationCommand.COMMANDKEY)
                .__(insert(corpus))
                .submitLocKey("_ submit.corpus.imagetoillustration");
        hp
                .__start(commandBox)
                .__(Grid.START)
                .__(Grid.selectRow("_ label.corpus.imagefield", hp.name(ImageToIllustrationCommand.FIELD_PARAMNAME),
                        () -> {
                            for (CorpusField corpusField : imageFieldList) {
                                hp
                                        .__(printFieldKeySelectOption(hp, corpusField, lang));
                            }
                        }))
                .__(Grid.selectRow("_ title.corpus.albuminclude_list", hp.name(ImageToIllustrationCommand.ALBUMINCLUDE_PARAMNAME),
                        () -> {
                            for (IncludeUi includeUi : albumIncludeList) {
                                String value = includeUi.getName();
                                String labelString = L10nUtils.getIncludeTitle(bdfServer, includeUi, lang);
                                if (labelString != null) {
                                    labelString = " " + labelString;
                                } else {
                                    labelString = "";
                                }
                                hp
                                        .OPTION(value, false)
                                        .__escape('[')
                                        .__escape(value)
                                        .__escape(']')
                                        .__escape(labelString)
                                        ._OPTION();
                            }
                        }))
                .__(Grid.textInputRow("_ label.corpus.baseurl", hp.name(ImageToIllustrationCommand.BASEURL_PARAMNAME).size("30")))
                .__(Grid.choiceSetRow("_ label.global.runmode",
                        () -> {
                            hp
                                    .__(Grid.radioCell("_ label.global.runmode_test", HA.name(ImageToIllustrationCommand.MODE_PARAMNAME).value(ImageToIllustrationCommand.TEST_MODE_PARAMVALUE).checked(true)))
                                    .__(Grid.radioCell("_ label.global.runmode_run", HA.name(ImageToIllustrationCommand.MODE_PARAMNAME).value(ImageToIllustrationCommand.RUN_MODE_PARAMVALUE).checked(false)));
                        }))
                .__(Grid.END)
                .__end(commandBox);
        return true;
    }


    private static boolean printSatelliteFicheWarning(HtmlPrinter hp, FicheMeta master, String warningKey, Lang workingLang, Locale formatLocale) {
        List<FicheMeta> satelliteList = new ArrayList<FicheMeta>();
        int ficheid = master.getId();
        for (Corpus satelliteCorpus : master.getCorpus().getSatelliteCorpusList()) {
            FicheMeta satelliteFicheMeta = satelliteCorpus.getFicheMetaById(ficheid);
            if (satelliteFicheMeta != null) {
                satelliteList.add(satelliteFicheMeta);
            }
        }
        if (satelliteList.isEmpty()) {
            return false;
        }
        Fiches fiches = FichesBuilder.init().addAll(satelliteList).toFiches();
        hp
                .P("global-Warning")
                .__localize(warningKey)
                ._P()
                .UL("command-fiches-List");
        for (Fiches.Entry entry : fiches.getEntryList()) {
            Corpus corpus = entry.getCorpus();
            hp
                    .LI()
                    .P()
                    .__(SubsetTitle.init(corpus, workingLang).subsetIcon(true))
                    ._P()
                    .__(FICHES_TREE, () -> {
                        for (FicheMeta ficheMeta : entry.getFicheMetaList()) {
                            hp
                                    .__(Tree.LEAF, () -> {
                                        hp
                                                .SPAN("command-fiches-Fiche")
                                                .__escape(CorpusMetadataUtils.getFicheTitle(ficheMeta, workingLang, formatLocale))
                                                ._SPAN();
                                    });
                        }
                    })
                    ._LI();
        }
        hp
                ._UL();
        return true;
    }

    private static boolean printSatelliteOpportunities(HtmlPrinter hp, BdfServer bdfServer, Lang workingLang) {
        hp
                .__(Grid.choiceSetRow("_ label.corpus.corpustype",
                        () -> {
                            hp
                                    .__(Grid.radioCell("_ label.corpus.corpustype_standard", hp.name(AbstractCorpusCreationCommand.CORPUSTYPE_PARAMNAME).value(AbstractCorpusCreationCommand.STANDARD_PARAMVALUE).checked(true)));
                            if (bdfServer.getFichotheque().getThesaurusList().size() > 0) {
                                SubsetTree thesaurusTree = bdfServer.getTreeManager().getSubsetTree(SubsetKey.CATEGORY_THESAURUS);
                                hp
                                        .__(Grid.radioCell("_ label.corpus.corpustype_thesaurussatellite", hp.name(AbstractCorpusCreationCommand.CORPUSTYPE_PARAMNAME).value(AbstractCorpusCreationCommand.THESAURUSSATELLITE_PARAMVALUE).checked(false),
                                                () -> {
                                                    hp
                                                            .__(Grid.START)
                                                            .__(Grid.selectRow("_ label.global.thesaurus", hp.name(AbstractCorpusCreationCommand.MASTERTHESAURUS_PARAMNAME),
                                                                    SubsetTreeOptions.init(thesaurusTree, bdfServer, workingLang)
                                                                            .onlyNames(true)
                                                                            .withKeys(true)
                                                            ))
                                                            .__(Grid.END);
                                                }));
                            }
                            List<Corpus> corpusList = bdfServer.getFichotheque().getCorpusList();
                            if (!corpusList.isEmpty()) {
                                Set<SubsetKey> noSatelliteSet = new HashSet<SubsetKey>();
                                for (Corpus corpus : corpusList) {
                                    if (corpus.getMasterSubset() == null) {
                                        noSatelliteSet.add(corpus.getSubsetKey());
                                    }
                                }
                                if (!noSatelliteSet.isEmpty()) {
                                    SubsetTree corpusTree = TreeFilterEngine.selection(noSatelliteSet, bdfServer.getTreeManager().getSubsetTree(SubsetKey.CATEGORY_CORPUS));
                                    hp
                                            .__(Grid.radioCell("_ label.corpus.corpustype_corpussatellite", hp.name(AbstractCorpusCreationCommand.CORPUSTYPE_PARAMNAME).value(AbstractCorpusCreationCommand.CORPUSSATELLITE_PARAMVALUE).checked(false),
                                                    () -> {
                                                        hp
                                                                .__(Grid.START)
                                                                .__(Grid.selectRow("_ label.global.corpus", hp.name(AbstractCorpusCreationCommand.MASTERCORPUS_PARAMNAME),
                                                                        SubsetTreeOptions.init(corpusTree, bdfServer, workingLang)
                                                                                .onlyNames(true)
                                                                                .withKeys(true)
                                                                ))
                                                                .__(Grid.END);
                                                    }));
                                }
                            }
                        }));
        return true;
    }

    private static boolean printCorpusFieldList(HtmlPrinter hp, List<CorpusField> corpusFieldList, String titleKey, Langs langs, Lang lang) {
        if (corpusFieldList.isEmpty()) {
            return false;
        }
        hp
                .H2()
                .__localize(titleKey)
                ._H2()
                .DL("global-DL");
        for (CorpusField corpusField : corpusFieldList) {
            hp
                    .DT()
                    .__(BdfHtmlUtils.printCodeMirrorSpan(hp, corpusField, lang))
                    ._DT()
                    .DD()
                    .__(Grid.START)
                    .__(LangRows.init(corpusField.getFieldString() + "/", corpusField.getLabels(), langs).cols(30))
                    .__(Grid.END)
                    ._DD();
        }
        hp
                ._DL();
        return true;
    }

    private static boolean printFieldTypeSelectRow(HtmlPrinter hp, short fieldCategory) {
        if (!FieldCreationCommand.isWithTypeSelect(fieldCategory)) {
            return false;
        }
        hp
                .__(Grid.selectRow("_ label.corpus.ficheitemtype", hp.name(FieldCreationCommand.FICHEITEMTYPE_PARAMNAME),
                        () -> {
                            hp
                                    .OPTION("", true)
                                    .__escape("---")
                                    ._OPTION()
                                    .__(printFicheItemTypeOption(hp, CorpusField.ITEM_FIELD))
                                    .__(printFicheItemTypeOption(hp, CorpusField.PERSON_FIELD))
                                    .__(printFicheItemTypeOption(hp, CorpusField.LANGUAGE_FIELD))
                                    .__(printFicheItemTypeOption(hp, CorpusField.COUNTRY_FIELD))
                                    .__(printFicheItemTypeOption(hp, CorpusField.DATE_FIELD))
                                    .__(printFicheItemTypeOption(hp, CorpusField.LINK_FIELD))
                                    .__(printFicheItemTypeOption(hp, CorpusField.EMAIL_FIELD))
                                    .__(printFicheItemTypeOption(hp, CorpusField.NUMBER_FIELD))
                                    .__(printFicheItemTypeOption(hp, CorpusField.AMOUNT_FIELD))
                                    .__(printFicheItemTypeOption(hp, CorpusField.GEOPOINT_FIELD))
                                    .__(printFicheItemTypeOption(hp, CorpusField.PARA_FIELD))
                                    .__(printFicheItemTypeOption(hp, CorpusField.IMAGE_FIELD));
                        }));
        return true;
    }

    private static boolean printFicheItemTypeOption(HtmlPrinter hp, String ficheItemType) {
        hp
                .OPTION(ficheItemType, false)
                .__localize(CorpusHtmlUtils.getFicheItemMessageKey(ficheItemType))
                .__space()
                .__escape('[')
                .__escape(ficheItemType)
                .__escape(']')
                ._OPTION();
        return true;
    }

    private static boolean printJunctionNodeList(HtmlPrinter hp, BdfServer bdfServer, List<SubsetTree.Node> nodeList, Lang workingLang, String paramName) {
        for (SubsetTree.Node node : nodeList) {
            hp
                    .LI();
            if (node instanceof GroupNode) {
                hp
                        .P("corpus-junction-GroupTitle")
                        .__escape(TreeUtils.getTitle(bdfServer, (GroupNode) node, workingLang))
                        ._P()
                        .UL("corpus-junction-GroupList")
                        .__(printJunctionNodeList(hp, bdfServer, ((GroupNode) node).getSubnodeList(), workingLang, paramName))
                        ._UL();
            } else {
                JunctionSubsetNode subsetNode = (JunctionSubsetNode) node;
                Subset subset = subsetNode.getSubset();
                hp
                        .P("corpus-junction-SubsetTitle")
                        .__(SubsetTitle.init(subset, workingLang).subsetIcon(true))
                        ._P()
                        .__(JunctionSelection.TREE, () -> {
                            for (Junctions.Entry entry : subsetNode.getJunctions().getEntryList()) {
                                SubsetItem subsetItem = entry.getSubsetItem();
                                String globalId = subsetItem.getGlobalId();
                                String name;
                                if (subsetItem instanceof Illustration) {
                                    name = ((Illustration) subsetItem).getFileName();
                                } else if (subsetItem instanceof Document) {
                                    name = AddendaUtils.toTitle((Document) subsetItem);
                                } else {
                                    name = "";
                                }
                                HtmlAttributes inputAttributes = hp.name(paramName).value(globalId);
                                hp
                                        .__(Tree.checkboxLeaf(inputAttributes, () -> {
                                            hp
                                                    .__escape(globalId)
                                                    .__dash()
                                                    .__escape(name);
                                        }));
                            }
                        });
            }
            hp
                    ._LI();
        }
        return true;
    }


    private static boolean printFieldKeySelectOptions(HtmlPrinter hp, Corpus corpus, Lang lang, boolean withNoRemoveable) {
        CorpusMetadata corpusMetadata = corpus.getCorpusMetadata();
        if (withNoRemoveable) {
            hp
                    .__(printFieldKeySelectOption(hp, corpusMetadata.getCorpusField(FieldKey.TITLE), lang))
                    .__(printFieldKeySelectOption(hp, corpusMetadata.getCorpusField(FieldKey.LANG), lang));
        }
        if (corpusMetadata.isWithSubtitle()) {
            hp
                    .__(printFieldKeySelectOption(hp, corpusMetadata.getCorpusField(FieldKey.SUBTITLE), lang));
        }
        if (withNoRemoveable) {
            hp
                    .__(printFieldKeySelectOption(hp, corpusMetadata.getCorpusField(FieldKey.OWNERS), lang));
        }
        for (CorpusField corpusField : corpusMetadata.getPropList()) {
            hp
                    .__(printFieldKeySelectOption(hp, corpusField, lang));
        }
        for (CorpusField corpusField : corpusMetadata.getInfoList()) {
            hp
                    .__(printFieldKeySelectOption(hp, corpusField, lang));
        }
        for (CorpusField corpusField : corpusMetadata.getSectionList()) {
            hp
                    .__(printFieldKeySelectOption(hp, corpusField, lang));
        }
        return true;
    }

    private static boolean printSectionSelectOptions(HtmlPrinter hp, Corpus corpus, Lang lang) {
        CorpusMetadata corpusMetadata = corpus.getCorpusMetadata();
        for (CorpusField corpusField : corpusMetadata.getSectionList()) {
            hp
                    .__(printFieldKeySelectOption(hp, corpusField, lang));
        }
        return true;
    }

    private static boolean printFieldKeySelectOption(HtmlPrinter hp, CorpusField corpusField, Lang lang) {
        hp
                .OPTION(corpusField.getFieldString(), false)
                .__escape(CorpusMetadataUtils.getFieldTitle(corpusField, lang, true))
                ._OPTION();
        return true;
    }

    private static boolean printCategorySelectOptions(HtmlPrinter hp) {
        hp
                .OPTION(FieldKey.PROP_CATEGORY_STRING, true)
                .__localize("_ label.corpus.category_prop")
                ._OPTION()
                .OPTION(FieldKey.INFO_CATEGORY_STRING, false)
                .__localize("_ label.corpus.category_info")
                ._OPTION()
                .OPTION(FieldKey.SECTION_CATEGORY_STRING, false)
                .__localize("_ label.corpus.category_section")
                ._OPTION();
        return true;
    }


    private static boolean printComponentUiDt(HtmlPrinter hp, Corpus corpus, UiComponent uiComponent, BdfServer bdfServer, Lang lang) {
        hp
                .DT();
        if (uiComponent instanceof FieldUi) {
            CorpusField corpusField = corpus.getCorpusMetadata().getCorpusField(((FieldUi) uiComponent).getFieldKey());
            if (corpusField != null) {
                BdfHtmlUtils.printCodeMirrorSpan(hp, corpusField, lang);
            } else {
                hp
                        .__escape(((FieldUi) uiComponent).getFieldString());
            }
        } else if (uiComponent instanceof SpecialIncludeUi) {
            BdfHtmlUtils.printCodeMirrorSpan(hp, (SpecialIncludeUi) uiComponent, bdfServer, lang);
        } else if (uiComponent instanceof SubsetIncludeUi) {
            BdfHtmlUtils.printCodeMirrorSpan(hp, (SubsetIncludeUi) uiComponent, bdfServer, lang);
        } else if (uiComponent instanceof CommentUi) {
            BdfHtmlUtils.printCodeMirrorSpan(hp, (CommentUi) uiComponent, lang);
        } else if (uiComponent instanceof DataUi) {
            BdfHtmlUtils.printCodeMirrorSpan(hp, (DataUi) uiComponent, lang);
        } else {
            hp
                    .__escape(uiComponent.getName());
        }
        hp
                ._DT();
        return true;
    }

    private static boolean printOptions(HtmlPrinter hp, String name, UiComponent uiComponent, boolean blockField) {
        String status = uiComponent.getStatus();
        hp
                .__(Grid.START);
        if (uiComponent.isModifiableStatus()) {
            hp
                    .__(Grid.selectRow("_ label.corpus.componentstatus", hp.name(name + UiComponentOptionsCommand.STATUS_PARAMSUFFIX),
                            () -> {
                                for (SelectOption option : STATUS_OPTIONS) {
                                    hp
                                            .__(option, status);
                                }
                            }));
        }
        if (uiComponent.isRelevantOption(BdfServerConstants.INCLUDEVARIANT_OPTION)) {
            String currentValue = uiComponent.getOptionValue(BdfServerConstants.INCLUDEVARIANT_OPTION);
            hp
                    .__(Grid.selectRow("_ label.corpus.includevariant", hp.name(name + UiComponentOptionsCommand.VARIANT_PARAMSUFFIX),
                            () -> {
                                for (SelectOption option : VARIANT_OPTIONS) {
                                    hp
                                            .__(option, currentValue);
                                }
                            }));

        }
        String conditionalId = null;
        if (uiComponent.isRelevantOption(BdfServerConstants.INPUTTYPE_OPTION)) {
            conditionalId = hp.generateId();
            String currentValue = uiComponent.getOptionValue(BdfServerConstants.INPUTTYPE_OPTION, BdfServerConstants.INPUT_TEXT);
            hp
                    .__(Grid.selectRow("_ label.corpus.inputtype", hp.name(name + UiComponentOptionsCommand.INPUT_PARAMSUFFIX).id(conditionalId),
                            () -> {
                                for (SelectOption option : INPUTTYPE_OPTIONS) {
                                    hp
                                            .__(option, currentValue);
                                }
                            }));
        }
        if (uiComponent.isRelevantOption(BdfServerConstants.INPUTWIDTH_OPTION)) {
            HtmlAttributes selectAttributes = hp.name(name + UiComponentOptionsCommand.WIDTH_PARAMSUFFIX);
            if (conditionalId != null) {
                populateTypeConditional(selectAttributes, conditionalId);
            }
            String currentWidthType = FicheFormUtils.getWidth(uiComponent);
            hp
                    .__(Grid.selectRow("_ label.corpus.size", selectAttributes,
                            () -> {
                                for (SelectOption option : WIDTHTYPE_OPTIONS) {
                                    hp
                                            .__(option, currentWidthType);
                                }
                            }));
        }
        if (uiComponent.isRelevantOption(BdfServerConstants.INPUTROWS_OPTION)) {
            HtmlAttributes inputAttributes = hp.name(name + UiComponentOptionsCommand.ROWS_PARAMSUFFIX).value(String.valueOf(FicheFormUtils.getRows(uiComponent))).size("3");
            if (conditionalId != null) {
                populateTypeConditional(inputAttributes, conditionalId);
            }
            hp
                    .__(Grid.textInputRow("_ label.corpus.rows", inputAttributes));
        }
        if (uiComponent.isRelevantOption(BdfServerConstants.DEFAULTVALUE_OPTION)) {
            String defaultValue = uiComponent.getOptionValue(BdfServerConstants.DEFAULTVALUE_OPTION);
            if (defaultValue.indexOf('\n') > -1) {
                blockField = true;
            }
            if (blockField) {
                hp
                        .__(Grid.textAreaInputRow("_ label.corpus.defaulvalue", hp.name(name + UiComponentOptionsCommand.DEFAULT_PARAMSUFFIX).value(defaultValue).rows(4).cols(50).classes("command-LargeInput"),
                                () -> {
                                    hp
                                            .__escape(defaultValue, true);
                                }));
            } else {
                hp
                        .__(Grid.textInputRow("_ label.corpus.defaulvalue", hp.name(name + UiComponentOptionsCommand.DEFAULT_PARAMSUFFIX).value(defaultValue).size("40")));
            }
        }
        hp
                .__(Grid.END);
        return true;
    }

    private static void populateTypeConditional(HtmlAttributes htmlAttributes, String conditionalId) {
        htmlAttributes.attr("data-conditional-source", conditionalId)
                .attr("data-conditional-values", BdfServerConstants.INPUT_TEXT)
                .attr("data-conditional-parent", ".grid-Row");
    }

    private static boolean printCommentLocationRadioList(HtmlPrinter hp, int position) {
        hp
                .__(Grid.choiceSetRow("_ label.corpus.commentlocation",
                        () -> {
                            hp
                                    .__(Grid.radioCell("_ label.corpus.commentlocation_form", hp.name(CommentChangeCommand.LOCATION_PARAMNAME).value(CommentChangeCommand.LOCATION_FORM_PARAMVALUE).checked((position == CommentUi.FORM_BITVALUE))))
                                    .__(Grid.radioCell("_ label.corpus.commentlocation_template", hp.name(CommentChangeCommand.LOCATION_PARAMNAME).value(CommentChangeCommand.LOCATION_TEMPLATE_PARAMVALUE).checked((position == CommentUi.TEMPLATE_BITVALUE))))
                                    .__(Grid.radioCell("_ label.corpus.commentlocation_both", hp.name(CommentChangeCommand.LOCATION_PARAMNAME).value(CommentChangeCommand.LOCATION_BOTH_PARAMVALUE).checked((position == CommentUi.ALL_MASK))));
                        }));
        return true;
    }

    private static String getMasterL10nKey(short subsetCategory) {
        switch (subsetCategory) {
            case SubsetKey.CATEGORY_CORPUS:
                return "_ label.corpus.masterinclude_fiche";
            default:
                return "_ label.corpus.masterinclude_motcle";
        }
    }


    private static class DiscardText implements Consumer<HtmlPrinter> {

        private final FicheMeta ficheMeta;

        private DiscardText(FicheMeta ficheMeta) {
            this.ficheMeta = ficheMeta;
        }

        @Override
        public void accept(HtmlPrinter hp) {
            BdfHtmlUtils.printAttributeToText(hp, ficheMeta.getAttributes().getAttribute(BdfSpace.DISCARDTEXT_KEY));
        }

    }

}
