/* BdfServer_Html - Copyright (c) 2020-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.html.consumers;

import fr.exemole.bdfserver.html.consumers.attributes.Deploy;
import java.util.function.Consumer;
import net.mapeadores.util.annotation.Nullable;
import net.mapeadores.util.html.ConsumerFactory;
import net.mapeadores.util.html.HA;
import net.mapeadores.util.html.HtmlAttributes;
import net.mapeadores.util.html.HtmlConstants;
import net.mapeadores.util.html.HtmlPrinter;


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

    public final static Consumer<HtmlPrinter> START = ConsumerFactory.startDiv("grid-Table");
    public final static Consumer<HtmlPrinter> END = ConsumerFactory.endDiv();
    public final static Consumer<HtmlPrinter> START_ROW = ConsumerFactory.startP("grid-Row");
    public final static Consumer<HtmlPrinter> END_ROW = ConsumerFactory.endP();
    public final static Consumer<HtmlPrinter> START_INPUTCELL = ConsumerFactory.startSpan("grid-InputCell");
    public final static Consumer<HtmlPrinter> END_INPUTCELL = ConsumerFactory.endSpan();
    public final static Consumer<HtmlPrinter> START_UNIQUECELL = ConsumerFactory.startSpan("grid-UniqueCell");
    public final static Consumer<HtmlPrinter> END_UNIQUECELL = ConsumerFactory.endSpan();
    public final static Consumer<HtmlPrinter> START_SUBTABLE = ConsumerFactory.startDiv("grid-Table grid-Subtable");
    public final static Consumer<HtmlPrinter> END_SUBTABLE = ConsumerFactory.endDiv();

    private Grid() {

    }

    public static Consumer<HtmlPrinter> fileInputRow(Object l10nObject, HtmlAttributes inputAttributes) {
        return inputRow(HtmlConstants.FILE_TYPE, l10nObject, inputAttributes);
    }

    public static Consumer<HtmlPrinter> passwordInputRow(Object l10nObject, HtmlAttributes inputAttributes) {
        return inputRow(HtmlConstants.PASSWORD_TYPE, l10nObject, inputAttributes);
    }

    public static Consumer<HtmlPrinter> textInputRow(Object l10nObject, HtmlAttributes inputAttributes) {
        return inputRow(HtmlConstants.TEXT_TYPE, l10nObject, inputAttributes);
    }

    public static Consumer<HtmlPrinter> inputRow(String type, Object l10nObject, HtmlAttributes inputAttributes) {
        return new InputRow(type, l10nObject, inputAttributes);
    }

    public static Consumer<HtmlPrinter> textAreaInputRow(Object l10nObject, HtmlAttributes textAreaAttributes) {
        return new TextAreaInputRow(l10nObject, textAreaAttributes, null);
    }

    public static Consumer<HtmlPrinter> textAreaInputRow(Object l10nObject, HtmlAttributes textAreaAttributes, @Nullable Consumer<HtmlPrinter> contentConsumer) {
        return new TextAreaInputRow(l10nObject, textAreaAttributes, contentConsumer);
    }

    public static Consumer<HtmlPrinter> textAreaInputRow(Object l10nObject, HtmlAttributes textAreaAttributes, @Nullable Runnable contentRunnable) {
        return new TextAreaInputRow(l10nObject, textAreaAttributes, contentRunnable);
    }

    public static Consumer<HtmlPrinter> textAreaBlockRow(Object l10nObject, HtmlAttributes textAreaAttributes) {
        return new TextAreaBlockRow(l10nObject, textAreaAttributes, null);
    }

    public static Consumer<HtmlPrinter> textAreaBlockRow(Object l10nObject, HtmlAttributes textAreaAttributes, @Nullable Consumer<HtmlPrinter> contentConsumer) {
        return new TextAreaBlockRow(l10nObject, textAreaAttributes, contentConsumer);
    }

    public static Consumer<HtmlPrinter> textAreaBlockRow(Object l10nObject, HtmlAttributes textAreaAttributes, @Nullable Runnable contentRunnable) {
        return new TextAreaBlockRow(l10nObject, textAreaAttributes, contentRunnable);
    }

    public static Consumer<HtmlPrinter> checkboxCell(Object l10nObject, HtmlAttributes inputAttributes) {
        return new ChoiceCell(HtmlConstants.CHECKBOX_TYPE, l10nObject, inputAttributes, null);
    }

    public static Consumer<HtmlPrinter> checkboxCell(Object l10nObject, HtmlAttributes inputAttributes, @Nullable Consumer<HtmlPrinter> detailConsumer) {
        return new ChoiceCell(HtmlConstants.CHECKBOX_TYPE, l10nObject, inputAttributes, detailConsumer);
    }

    public static Consumer<HtmlPrinter> checkboxCell(Object l10nObject, HtmlAttributes inputAttributes, @Nullable Runnable detailRunnable) {
        return new ChoiceCell(HtmlConstants.CHECKBOX_TYPE, l10nObject, inputAttributes, detailRunnable);
    }

    public static Consumer<HtmlPrinter> checkboxRow(Object l10nObject, HtmlAttributes inputAttributes) {
        return new ChoiceRow(HtmlConstants.CHECKBOX_TYPE, l10nObject, inputAttributes, null);
    }

    public static Consumer<HtmlPrinter> checkboxRow(Object l10nObject, HtmlAttributes inputAttributes, @Nullable Consumer<HtmlPrinter> contentConsumer) {
        return new ChoiceRow(HtmlConstants.CHECKBOX_TYPE, l10nObject, inputAttributes, contentConsumer);
    }

    public static Consumer<HtmlPrinter> checkboxRow(Object l10nObject, HtmlAttributes inputAttributes, @Nullable Runnable contentRunnable) {
        return new ChoiceRow(HtmlConstants.CHECKBOX_TYPE, l10nObject, inputAttributes, contentRunnable);
    }

    public static Consumer<HtmlPrinter> selectRow(Object l10nObject, HtmlAttributes selectAttributes, @Nullable Consumer<HtmlPrinter> optionsConsumer) {
        return new SelectRow(l10nObject, selectAttributes, optionsConsumer);
    }

    public static Consumer<HtmlPrinter> selectRow(Object l10nObject, HtmlAttributes selectAttributes, @Nullable Runnable optionsRunnable) {
        return new SelectRow(l10nObject, selectAttributes, optionsRunnable);
    }

    public static Consumer<HtmlPrinter> choiceSetRow(Object l10nObject, @Nullable Consumer<HtmlPrinter> consumer) {
        return new ChoiceSetRow(l10nObject, consumer);
    }

    public static Consumer<HtmlPrinter> choiceSetRow(Object l10nObject, @Nullable Runnable runnable) {
        return new ChoiceSetRow(l10nObject, runnable);
    }

    public static Consumer<HtmlPrinter> radioCell(Object l10nObject, HtmlAttributes inputAttributes) {
        return new ChoiceCell(HtmlConstants.RADIO_TYPE, l10nObject, inputAttributes, null);
    }

    public static Consumer<HtmlPrinter> radioCell(Object l10nObject, HtmlAttributes inputAttributes, @Nullable Consumer<HtmlPrinter> detailConsumer) {
        return new ChoiceCell(HtmlConstants.RADIO_TYPE, l10nObject, inputAttributes, detailConsumer);
    }

    public static Consumer<HtmlPrinter> radioCell(Object l10nObject, HtmlAttributes inputAttributes, @Nullable Runnable detailRunnable) {
        return new ChoiceCell(HtmlConstants.RADIO_TYPE, l10nObject, inputAttributes, detailRunnable);
    }

    public static Consumer<HtmlPrinter> radioRow(Object l10nObject, HtmlAttributes inputAttributes) {
        return new ChoiceRow(HtmlConstants.RADIO_TYPE, l10nObject, inputAttributes, null);
    }

    public static Consumer<HtmlPrinter> radioRow(Object l10nObject, HtmlAttributes inputAttributes, @Nullable Consumer<HtmlPrinter> contentConsumer) {
        return new ChoiceRow(HtmlConstants.RADIO_TYPE, l10nObject, inputAttributes, contentConsumer);
    }

    public static Consumer<HtmlPrinter> radioRow(Object l10nObject, HtmlAttributes inputAttributes, @Nullable Runnable contentRunnable) {
        return new ChoiceRow(HtmlConstants.RADIO_TYPE, l10nObject, inputAttributes, contentRunnable);
    }

    public static Consumer<HtmlPrinter> labelCells(Object l10nObject) {
        return new LabelCells(l10nObject);
    }

    public static Consumer<HtmlPrinter> labelCells(Object l10nObject, String forId) {
        return new LabelCells(l10nObject, forId);
    }

    public static HtmlAttributes detailPanelTable() {
        return HA.classes("global-DetailPanel grid-Table");
    }


    private static class LabelCells implements Consumer<HtmlPrinter> {

        private final Object l10nObject;
        private final String forId;

        private LabelCells(Object l10nObject) {
            this.l10nObject = l10nObject;
            this.forId = null;
        }

        private LabelCells(Object l10nObject, String forId) {
            this.l10nObject = l10nObject;
            this.forId = forId;
        }

        @Override
        public void accept(HtmlPrinter hp) {
            if (forId != null) {
                hp
                        .LABEL(HA.forId(forId).classes("grid-LabelCell"))
                        .__localize(l10nObject)
                        ._LABEL()
                        .SPAN("grid-ColonCell")
                        .__colon()
                        ._SPAN();
            } else {
                hp
                        .SPAN("grid-LabelCell")
                        .__localize(l10nObject)
                        ._SPAN()
                        .SPAN("grid-ColonCell")
                        .__colon()
                        ._SPAN();
            }
        }

    }


    private static class InputRow implements Consumer<HtmlPrinter> {

        private final String type;
        private final Object l10nObject;
        private final HtmlAttributes inputAttributes;

        private InputRow(String type, Object l10nObject, HtmlAttributes inputAttributes) {
            this.type = type;
            this.l10nObject = l10nObject;
            this.inputAttributes = inputAttributes;
        }

        @Override
        public void accept(HtmlPrinter hp) {
            hp
                    .__(Grid.START_ROW)
                    .__(labelCells(l10nObject, inputAttributes.id()))
                    .__(Grid.START_INPUTCELL)
                    .INPUT(inputAttributes.type(type))
                    .__(Grid.END_INPUTCELL)
                    .__(Grid.END_ROW);
        }

    }


    private static abstract class ContentFunction {

        protected final Object contentFunction;

        protected ContentFunction(Object contentFunction) {
            this.contentFunction = contentFunction;
        }

        protected void run(HtmlPrinter hp) {
            if (contentFunction != null) {
                if (contentFunction instanceof Consumer) {
                    ((Consumer<HtmlPrinter>) contentFunction).accept(hp);
                } else if (contentFunction instanceof Runnable) {
                    ((Runnable) contentFunction).run();
                }
            }
        }

        protected boolean hasFunction() {
            return (contentFunction != null);
        }

    }


    private static class TextAreaInputRow extends ContentFunction implements Consumer<HtmlPrinter> {

        private final Object l10nObject;
        private final HtmlAttributes textAreaAttributes;

        private TextAreaInputRow(Object l10nObject, HtmlAttributes textAreaAttributes, Object contentFunction) {
            super(contentFunction);
            this.l10nObject = l10nObject;
            this.textAreaAttributes = textAreaAttributes;
        }

        @Override
        public void accept(HtmlPrinter hp) {
            hp
                    .__(Grid.START_ROW)
                    .__(labelCells(l10nObject, textAreaAttributes.id()))
                    .__(Grid.START_INPUTCELL)
                    .TEXTAREA(textAreaAttributes);
            run(hp);
            hp
                    ._TEXTAREA()
                    .__(Grid.END_INPUTCELL)
                    .__(Grid.END_ROW);
        }

    }


    private static class TextAreaBlockRow extends ContentFunction implements Consumer<HtmlPrinter> {

        private final Object l10nObject;
        private final HtmlAttributes textAreaAttributes;

        private TextAreaBlockRow(Object l10nObject, HtmlAttributes textAreaAttributes, Object contentFunction) {
            super(contentFunction);
            this.l10nObject = l10nObject;
            this.textAreaAttributes = textAreaAttributes;
        }

        @Override
        public void accept(HtmlPrinter hp) {
            hp
                    .__(Grid.START_ROW)
                    .LABEL(HA.forId(textAreaAttributes.id()).classes("grid-LabelCell"))
                    .__localize(l10nObject)
                    .__colon()
                    ._LABEL()
                    .__(Grid.START_UNIQUECELL)
                    .TEXTAREA(textAreaAttributes);
            run(hp);
            hp
                    ._TEXTAREA()
                    .__(Grid.END_UNIQUECELL)
                    .__(Grid.END_ROW);
        }

    }


    private static class ChoiceRow extends ContentFunction implements Consumer<HtmlPrinter> {

        private final String type;
        private final Object l10nObject;
        private final HtmlAttributes inputAttributes;

        private ChoiceRow(String type, Object l10nObject, HtmlAttributes inputAttributes, Object contentFunction) {
            super(contentFunction);
            this.type = type;
            this.l10nObject = l10nObject;
            this.inputAttributes = inputAttributes;
        }

        @Override
        public void accept(HtmlPrinter hp) {
            hp
                    .DIV("grid-Row")
                    .DIV("grid-UniqueCell")
                    .SPAN("command-FlexInput")
                    .INPUT(inputAttributes.type(type))
                    .LABEL_for(inputAttributes.id())
                    .__localize(l10nObject)
                    ._LABEL()
                    ._SPAN();
            run(hp);
            hp
                    ._DIV()
                    ._DIV();
        }

    }


    private static class ChoiceSetRow extends ContentFunction implements Consumer<HtmlPrinter> {

        private final Object l10nObject;

        private ChoiceSetRow(Object l10nObject, Object contentFunction) {
            super(contentFunction);
            this.l10nObject = l10nObject;
        }

        @Override
        public void accept(HtmlPrinter hp) {
            hp
                    .FIELDSET("grid-Row grid-choice-Fieldset")
                    .LEGEND("grid-choice-Legend grid-Ignore")
                    .__(labelCells(l10nObject))
                    ._LEGEND()
                    .DIV("grid-choice-Content grid-Ignore");
            run(hp);
            hp
                    ._DIV()
                    ._FIELDSET();
        }

    }


    private static class SelectRow extends ContentFunction implements Consumer<HtmlPrinter> {

        private final Object l10nObject;
        private final HtmlAttributes selectAttributes;

        private SelectRow(Object l10nObject, HtmlAttributes selectAttributes, Object contentFunction) {
            super(contentFunction);
            this.l10nObject = l10nObject;
            this.selectAttributes = selectAttributes;
        }

        @Override
        public void accept(HtmlPrinter hp) {
            hp
                    .__(Grid.START_ROW)
                    .__(labelCells(l10nObject, selectAttributes.id()))
                    .__(Grid.START_INPUTCELL)
                    .SELECT(selectAttributes);
            run(hp);
            hp
                    ._SELECT()
                    .__(Grid.END_INPUTCELL)
                    .__(Grid.END_ROW);
        }

    }


    private static class ChoiceCell extends ContentFunction implements Consumer<HtmlPrinter> {

        private final String type;
        private final Object l10nObject;
        private final HtmlAttributes inputAttributes;

        private ChoiceCell(String type, Object l10nObject, HtmlAttributes inputAttributes, Object contentFunction) {
            super(contentFunction);
            this.type = type;
            this.l10nObject = l10nObject;
            this.inputAttributes = inputAttributes;
        }

        @Override
        public void accept(HtmlPrinter hp) {
            boolean withDetail = hasFunction();
            String detailId;
            if (withDetail) {
                detailId = hp.generateId();
                inputAttributes.populate(Deploy.radio(detailId));
            } else {
                detailId = null;
            }
            hp
                    .SPAN("grid-choice-InputCell")
                    .INPUT(inputAttributes.type(type))
                    ._SPAN()
                    .SPAN("grid-choice-LabelCell")
                    .LABEL_for(inputAttributes.id())
                    .__localize(l10nObject)
                    ._LABEL()
                    ._SPAN();
            if (withDetail) {
                hp
                        .DIV(HA.id(detailId).classes("global-DetailPanel grid-choice-DetailCell").addClass(!inputAttributes.checked(), "hidden"));
                run(hp);
                hp
                        ._DIV();
            }
        }

    }

}
