/* BdfServer_Html - Copyright (c) 2010-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;

import fr.exemole.bdfserver.api.BdfExtensionReference;
import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.instruction.BdfCommandResult;
import fr.exemole.bdfserver.api.instruction.BdfParameters;
import fr.exemole.bdfserver.api.interaction.InteractionConstants;
import fr.exemole.bdfserver.api.managers.ExtensionManager;
import fr.exemole.bdfserver.api.namespaces.UiSpace;
import fr.exemole.bdfserver.api.providers.ActionProvider;
import fr.exemole.bdfserver.api.users.BdfUser;
import fr.exemole.bdfserver.html.consumers.Button;
import fr.exemole.bdfserver.html.consumers.PageUnit;
import fr.exemole.bdfserver.tools.storage.IconScanEngine;
import fr.exemole.bdfserver.tools.users.BdfUserUtils;
import java.text.DecimalFormatSymbols;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import net.fichotheque.Fichotheque;
import net.fichotheque.utils.FichothequeMetadataUtils;
import net.fichotheque.utils.FichothequeUtils;
import net.mapeadores.util.html.CommandBox;
import net.mapeadores.util.html.HA;
import net.mapeadores.util.html.HtmlAttributes;
import net.mapeadores.util.html.HtmlConstants;
import net.mapeadores.util.html.HtmlPrinter;
import net.mapeadores.util.html.HtmlPrinterUtils;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.LangPreference;
import net.mapeadores.util.localisation.LangsUtils;
import net.mapeadores.util.logging.CommandMessage;
import net.mapeadores.util.request.RequestConstants;


/**
 *
 * @author Vincent Calame
 */
public abstract class BdfServerHtmlProducer extends BdfHtmlProducer {

    protected BdfServer bdfServer;
    protected BdfUser bdfUser;
    protected Lang workingLang;
    protected Locale formatLocale;
    protected LangPreference langPreference;
    protected Fichotheque fichotheque;
    protected BdfParameters bdfParameters;
    private BdfCommandResult bdfCommandResult;
    private BdfHtmlHookManager bdfHtmlHookManager;


    private BdfServerHtmlProducer(BdfServer bdfServer) {
        super(bdfServer.getJsAnalyser(), bdfServer.getBuildInfo());
        this.bdfServer = bdfServer;
        this.fichotheque = bdfServer.getFichotheque();
        setBodyCssClass("global-body-Default");
    }

    public BdfServerHtmlProducer(BdfServer bdfServer, LangPreference langPreference) {
        this(bdfServer);
        this.workingLang = LangsUtils.getPreferredAvailableLang(bdfServer.getLangConfiguration().getWorkingLangs(), langPreference);
        this.formatLocale = workingLang.toLocale();
        this.langPreference = langPreference;
        this.bdfUser = null;
        addMessageLocalisation(bdfServer.getL10nManager().getMessageLocalisation(langPreference));
    }

    public BdfServerHtmlProducer(BdfParameters bdfParameters) {
        this(bdfParameters.getBdfServer());
        this.bdfParameters = bdfParameters;
        this.bdfUser = bdfParameters.getBdfUser();
        this.workingLang = bdfUser.getWorkingLang();
        this.formatLocale = bdfUser.getFormatLocale();
        this.langPreference = bdfUser.getLangPreference();
        addMessageLocalisation(bdfServer.getL10nManager().getMessageLocalisation(bdfUser));
        setWithJavascript(BdfUserUtils.isWithJavascript(bdfUser));
    }

    public BdfServer getBdfServer() {
        return bdfServer;
    }

    public Fichotheque getFichotheque() {
        return fichotheque;
    }

    public BdfUser getBdfUser() {
        return bdfUser;
    }

    public Map<String, String> getStoredValues(String name) {
        return bdfServer.getStoredValues(bdfUser, name);
    }

    public final void addThemeCssForAction(String actionKey) {
        for (BdfExtensionReference extensionReference : bdfServer.getExtensionManager().getBdfExtensionReferenceList()) {
            ActionProvider actionProvider = (ActionProvider) extensionReference.getImplementation(ActionProvider.class);
            if (actionProvider != null) {
                String cssThemeFile = actionProvider.getCssThemeFile(actionKey);
                if (cssThemeFile != null) {
                    addExtensionThemeCss(extensionReference.getRegistrationName(), cssThemeFile);
                }
            }
        }
    }

    public final boolean checkFontAwesome() {
        boolean present = bdfServer.getFichotheque().getFichothequeMetadata().getAttributes().isTrue(UiSpace.FONTAWESOME_KEY);
        if (present) {
            addFontAwesomeCss();
        }
        return present;
    }

    public final void scanIcons() {
        setSupplementaryIconAttributesList(IconScanEngine.run(bdfServer.getResourceStorages(), bdfServer.getMimeTypeResolver()));
    }


    public BdfServerHtmlProducer setBdfCommandResult(BdfCommandResult bdfCommandResult) {
        this.bdfCommandResult = bdfCommandResult;
        return this;
    }

    public BdfCommandResult getBdfCommandResult() {
        return bdfCommandResult;
    }

    @Override
    public CommandMessage getCommandMessage() {
        CommandMessage commandMessage = super.getCommandMessage();
        if (commandMessage != null) {
            return commandMessage;
        } else if (bdfCommandResult != null) {
            return bdfCommandResult.getCommandMessage();
        } else {
            return null;
        }
    }

    public Lang getWorkingLang() {
        return workingLang;
    }

    public Locale getFormatLocale() {
        return formatLocale;
    }

    public DateTimeFormatter getDateTimeFormatter(FormatStyle formatStyle) {
        return DateTimeFormatter.ofLocalizedDate(formatStyle).withLocale(formatLocale);
    }

    public DecimalFormatSymbols getDecimalFormatSymbols() {
        return new DecimalFormatSymbols(formatLocale);
    }


    @Override
    public HtmlPrinter __start(Object object) {
        if (object instanceof CommandBox) {
            startCommandBox((CommandBox) object);
            return this;
        } else {
            return super.__start(object);
        }
    }

    @Override
    public HtmlPrinter __end(Object object) {
        if (object instanceof CommandBox) {
            endCommandBox(((CommandBox) object));
            return this;
        } else {
            return super.__end(object);
        }
    }

    public void start() {
        start(FichothequeMetadataUtils.getTitle(bdfServer.getFichotheque(), workingLang));
    }

    public void startLoc(String titleMessageKey, boolean appendToFichothequeName) {
        if (appendToFichothequeName) {
            start(FichothequeMetadataUtils.getTitle(bdfServer.getFichotheque(), workingLang) + " - " + getLocalization(titleMessageKey));
        } else {
            start(getLocalization(titleMessageKey));
        }
    }

    public void startPhrase(String phraseName) {
        String title = null;
        if (phraseName != null) {
            title = FichothequeUtils.getPhraseLabel(bdfServer.getFichotheque().getFichothequeMetadata().getPhrases(), phraseName, workingLang);
        }
        if (title == null) {
            title = FichothequeMetadataUtils.getTitle(bdfServer.getFichotheque(), workingLang);
        }
        start(title);
    }

    @Override
    public void start(String title) {
        if (isWithJavascript()) {
            resolveJavascript();
        }
        resolveCss();
        setIcons();
        super.start(langPreference.getFirstLang(), title);
    }


    public void start(String title, boolean appendToFichothequeName) {
        if (appendToFichothequeName) {
            start(FichothequeMetadataUtils.getTitle(bdfServer.getFichotheque(), workingLang) + " - " + title);
        } else {
            start(title);
        }
    }

    @Override
    public void end() {
        if (isWithJavascript()) {
            BdfJsLibAssembly jsLibAssembly = getJsLibAssembly();
            if (jsLibAssembly != null) {
                jsLibAssembly.end(this, bdfServer.getResourceStorages(), bdfServer.getFichotheque(), bdfParameters, workingLang);
            }
        }
        if (bdfUser != null) {
            String log = getLog();
            if (!log.isEmpty()) {
                this
                        .COMMENT()
                        .__newLine()
                        .__escape(log)
                        .__newLine()
                        ._COMMENT();
            }
        }
        super.end();
    }

    public boolean printCommandMessageUnit() {
        CommandMessage cm = getCommandMessage();
        if (cm != null) {
            __(PageUnit.SIMPLE, () -> {
                HtmlPrinterUtils.printCommandMessage(this, cm, "global-DoneMessage", "global-ErrorMessage");
            });
            return true;
        } else {
            return false;
        }
    }

    public final void initHook(Class bdfHtmlProducerClass) {
        ExtensionManager extensionManager = bdfServer.getExtensionManager();
        for (BdfExtensionReference extensionReference : extensionManager.getBdfExtensionReferenceList()) {
            BdfHtmlHookProvider bdfHtmlHookProvider = (BdfHtmlHookProvider) extensionReference.getImplementation(BdfHtmlHookProvider.class);
            if (bdfHtmlHookProvider != null) {
                BdfHtmlHook bdfHtmlHook = bdfHtmlHookProvider.getBdfHtmlHook(bdfHtmlProducerClass);
                if (bdfHtmlHook != null) {
                    if (bdfHtmlHookManager == null) {
                        bdfHtmlHookManager = new BdfHtmlHookManager();
                    }
                    bdfHtmlHookManager.add(bdfHtmlHook);
                }
            }
        }
        if (bdfHtmlHookManager != null) {
            bdfHtmlHookManager.init(this);
        }
    }

    public void insertInclude(String insertName) {
        if (bdfHtmlHookManager != null) {
            bdfHtmlHookManager.insert(this, insertName);
        }
    }

    private boolean startCommandBox(CommandBox commandBox) {
        String commandKey = commandBox.lockey();
        if (commandKey == null) {
            throw new IllegalStateException("commandKey is null");
        }
        String unitCssClasses;
        if (commandBox.mode().equals(InteractionConstants.SUBUNIT_MODE)) {
            unitCssClasses = "unit-Subunit family-Border";
        } else {
            unitCssClasses = "unit-Unit family-Border";
        }
        String family = commandBox.family();
        if (family != null) {
            unitCssClasses = unitCssClasses + " family-" + family;
        }
        String sectionId = generateId();
        String formId = generateId();
        HtmlAttributes sectionAttr = HA.id(sectionId).classes(unitCssClasses);
        if (commandBox.veil()) {
            sectionAttr.attr("data-veil-role", "unit");
        }
        this
                .SECTION(sectionAttr)
                .HEADER("unit-Header family-Colors")
                .H1("unit-Title command-Title family-Colors")
                .SPAN("command-TitleText")
                .__localize(commandKey)
                ._SPAN()
                .__(printTitleSubmitButton(commandBox, formId))
                ._H1()
                ._HEADER()
                .__(printFormStart(commandBox, formId))
                .DIV("unit-Body");
        return true;
    }

    private boolean printTitleSubmitButton(CommandBox commandBox, String formId) {
        String submitMessageKey = commandBox.submitLocKey();
        if (submitMessageKey == null) {
            return false;
        }
        this
                .__(Button.submit().action(getCommandBoxActionCssClass(commandBox)).tooltipMessage(submitMessageKey).formId(formId));
        return true;
    }

    private boolean endCommandBox(CommandBox commandBox) {
        String submitMessageKey = commandBox.submitLocKey();
        if (submitMessageKey != null) {
            this
                    .__(Button.COMMAND,
                            Button.submit(getCommandBoxActionCssClass(commandBox), submitMessageKey));
        }
        this
                .__(printCommandKey(commandBox))
                ._DIV()
                ._FORM()
                ._SECTION();
        return true;
    }

    private boolean printFormStart(CommandBox commandBox, String formId) {
        HtmlAttributes formAttributes = HA.action(commandBox.action()).id(formId);
        if (commandBox.multipart()) {
            formAttributes.enctype(HtmlConstants.MULTIPART_ENCTYPE);
        }
        String submitProcess = commandBox.submitProcess();
        formAttributes
                .attr("data-submit-process", submitProcess);
        String target = commandBox.target();
        if (target != null) {
            formAttributes.target(target);
        }
        this
                .FORM_post(formAttributes);
        this
                .INPUT_hidden(RequestConstants.COMMAND_PARAMETER, commandBox.name());
        String page = commandBox.page();
        if (page != null) {
            this
                    .INPUT_hidden(RequestConstants.PAGE_PARAMETER, page);
        }
        String errorPage = commandBox.errorPage();
        if (errorPage != null) {
            this
                    .INPUT_hidden(InteractionConstants.PAGE_ERROR_PARAMNAME, errorPage);
        }
        Map<String, String> hiddenAttributesMap = commandBox.hiddenMap();
        if (hiddenAttributesMap != null) {
            this
                    .INPUT_hidden(hiddenAttributesMap);
        }
        return true;
    }

    private String getCommandBoxActionCssClass(CommandBox commandBox) {
        String actionCssClass = commandBox.actionCssClass();
        if (actionCssClass != null) {
            return actionCssClass;
        } else {
            return "action-Save";
        }
    }

    private boolean printCommandKey(CommandBox commandBox) {
        String keyString = commandBox.lockey();
        if ((keyString == null) || (keyString.isEmpty())) {
            return false;
        }
        if (keyString.startsWith("_ ")) {
            keyString = keyString.substring(2);
        }
        String helpUrl = commandBox.helpUrl();
        if (helpUrl == null) {
            helpUrl = "http://www.fichotheque.net/" + keyString + ".html";
        }
        this
                .DIV("command-CommandKey ");
        if (helpUrl.isEmpty()) {
            this
                    .SPAN("family-Colors")
                    .__escape(keyString)
                    ._SPAN();
        } else {
            this
                    .A(HA.href(helpUrl).target(HtmlConstants.BLANK_TARGET).classes("command-HelpLink family-Colors").titleLocKey("_ info.global.commandhelp"))
                    .__escape(keyString)
                    ._A();
        }
        this
                ._DIV();
        return true;
    }


    private static class BdfHtmlHookManager {

        private final List<BdfHtmlHook> list = new ArrayList<BdfHtmlHook>();

        private BdfHtmlHookManager() {

        }

        private void add(BdfHtmlHook bdfHtmlHook) {
            list.add(bdfHtmlHook);
        }

        private void init(BdfServerHtmlProducer bdfHtmlProducer) {
            for (BdfHtmlHook bdfHtmlHook : list) {
                bdfHtmlHook.init(bdfHtmlProducer);
            }
        }

        private void insert(BdfServerHtmlProducer bdfHtmlProducer, String insertName) {
            for (BdfHtmlHook bdfHtmlHook : list) {
                bdfHtmlHook.insert(bdfHtmlProducer, insertName);
            }
        }


    }

}
