/* 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;

import fr.exemole.bdfserver.tools.storage.StorageUtils;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import net.mapeadores.util.buildinfo.BuildInfo;
import net.mapeadores.util.html.HtmlAttributes;
import net.mapeadores.util.html.HtmlPrinterUtils;
import net.mapeadores.util.html.HtmlProducer;
import net.mapeadores.util.html.PageHtmlPrinter;
import net.mapeadores.util.jslib.JsAnalyser;
import net.mapeadores.util.jslib.JsLib;
import net.mapeadores.util.logging.CommandMessage;
import net.mapeadores.util.text.RelativePath;


/**
 *
 * @author Vincent Calame
 */
public abstract class BdfHtmlProducer extends PageHtmlPrinter implements HtmlProducer {

    private final JsAnalyser jsAnalyser;
    private final BuildInfo buildInfo;
    private final Set<String> themeCssPathSet = new LinkedHashSet<String>();
    private final Set<String> supplementaryCssPathSet = new LinkedHashSet<String>();
    private final Set<String> customCssPathSet = new LinkedHashSet<String>();
    private BdfJsLibAssembly jsLibAssembly = null;
    private String reversePath = "";
    private CommandMessage commandMessage;
    private boolean withFicheCss = false;
    private boolean withFicheElementCss = false;
    private boolean withThemeElementCss = true;
    private boolean withFontAwesome = false;
    private List<HtmlAttributes> supplementaryIconAttributesList = null;
    private StringBuilder logBuffer;

    public BdfHtmlProducer(JsAnalyser jsAnalyser, BuildInfo buildInfo) {
        this.jsAnalyser = jsAnalyser;
        this.buildInfo = buildInfo;
    }

    public final void addThemeCss(String... cssThemeFile) {
        for (String value : cssThemeFile) {
            themeCssPathSet.add("theme/css/" + value);
        }
    }

    public final void addExtensionThemeCss(String extensionName, String... cssThemeFile) {
        for (String value : cssThemeFile) {
            themeCssPathSet.add(StorageUtils.getExtensionResourcePath(extensionName, "theme/css/" + value));
        }
    }

    public final void addAppThemeCss(String appName, String... cssThemeFile) {
        for (String value : cssThemeFile) {
            themeCssPathSet.add(StorageUtils.getAppResourcePath(appName, "theme/css/" + value));
        }
    }

    public final void addSupplementaryCss(RelativePath path) {
        supplementaryCssPathSet.add(path.getPath());
    }

    public final void addCustomCss(RelativePath path) {
        customCssPathSet.add(path.getPath());
    }

    public final void addFicheCss(boolean withFicheElementCss) {
        this.withFicheCss = true;
        this.withFicheElementCss = withFicheElementCss;
    }

    public final void addFontAwesomeCss() {
        this.withFontAwesome = true;
    }

    public final void ignoreThemeElementCss() {
        this.withThemeElementCss = false;
    }

    public final void setReversePath(String reversePath) {
        if (reversePath == null) {
            this.reversePath = "";
        } else {
            this.reversePath = reversePath;
        }
    }

    public String getReversePath() {
        return reversePath;
    }

    public BdfJsLibAssembly getJsLibAssembly() {
        return jsLibAssembly;
    }

    public void setCommandMessage(CommandMessage commandMessage) {
        this.commandMessage = commandMessage;
    }

    public void setSupplementaryIconAttributesList(List<HtmlAttributes> supplementaryIconAttributesList) {
        this.supplementaryIconAttributesList = supplementaryIconAttributesList;
    }

    public CommandMessage getCommandMessage() {
        return commandMessage;
    }

    public boolean printCommandMessage() {
        return HtmlPrinterUtils.printCommandMessage(this, getCommandMessage(), "global-DoneMessage", "global-ErrorMessage");
    }

    public void addLog(String logMessage) {
        if (logBuffer == null) {
            logBuffer = new StringBuilder();
            logBuffer.append(logMessage);
        } else {
            logBuffer.append("\n");
            logBuffer.append(logMessage);
        }
    }

    public String getLog() {
        if (logBuffer == null) {
            return "";
        } else {
            return logBuffer.toString();
        }
    }

    protected void setIcons() {
        addIconPng(reversePath + StorageUtils.ICON.toString(), "16");
        addIconPng(reversePath + StorageUtils.ICON32.toString(), "32");
        if (supplementaryIconAttributesList != null) {
            for (HtmlAttributes ha : supplementaryIconAttributesList) {
                addIcon(ha.href(reversePath + ha.href()));
            }
        }
    }

    protected void resolveJavascript() {
        if (jsLibAssembly != null) {
            String suffix = "";
            if (buildInfo != null) {
                suffix = "?v=" + buildInfo.getVersion();
            }
            jsLibAssembly.resolve(this, reversePath, suffix);
        }
    }

    protected void resolveCss() {
        String suffix = "";
        if (buildInfo != null) {
            suffix = "?v=" + buildInfo.getVersion();
        }
        if (withFontAwesome) {
            addCssUrl(reversePath + "third-lib/fontawesome/css/fontawesome.css" + suffix);
            addCssUrl(reversePath + "third-lib/fontawesome/css/solid.css" + suffix);
        }
        if (withFicheElementCss) {
            addCssUrl(reversePath + "css/fiche-elements.css" + suffix);
        }
        if (withFicheCss) {
            addCssUrl(reversePath + "css/_ficheblockelements.css" + suffix);
            addCssUrl(reversePath + "css/_predefinedclasses.css" + suffix);
            addCssUrl(reversePath + "css/fiche-classes.css" + suffix);
        }
        resolveThemeCss(suffix);
        for (String supplementaryPath : supplementaryCssPathSet) {
            addCssUrl(reversePath + supplementaryPath);
        }
        if (withFicheCss) {
            addCssUrl(reversePath + "custom/fiche.css");
        }
        addCssUrl(reversePath + "custom/theme.css");
        for (String customPath : customCssPathSet) {
            addCssUrl(reversePath + customPath);
        }
    }

    private void resolveThemeCss(String suffix) {
        if (jsLibAssembly != null) {
            for (String path : jsLibAssembly.getJsLibCssPaths()) {
                themeCssPathSet.add(path);
            }
        }
        if (withThemeElementCss) {
            addCssUrl(reversePath + "theme/css/_normalize.css" + suffix);
            addCssUrl(reversePath + "theme/css/_default.css" + suffix);
        }
        addCssUrl(reversePath + "theme/css/_overlay.css" + suffix);
        addCssUrl(reversePath + "theme/css/_global.css" + suffix);
        addCssUrl(reversePath + "theme/css/_grid.css" + suffix);
        addCssUrl(reversePath + "theme/css/_action.css" + suffix);
        addCssUrl(reversePath + "theme/css/_family.css" + suffix);
        addCssUrl(reversePath + "theme/css/_codemirror.css" + suffix);
        if (isWithJavascript()) {
            addCssUrl(reversePath + "theme/css/_javascript.css" + suffix);
        }
        for (String path : themeCssPathSet) {
            addCssUrl(reversePath + path + suffix);
        }
    }

    /**
     * Sert pour l'utilisation de LocalStorage (HTML 5), voir Bdf.Deploy.js
     */
    public final void setMainStorageKey(String... keyParts) {
        testJsLibAssembly();
        jsLibAssembly.setMainStorageKey(String.join("/", keyParts));
    }

    public final void addJsLib(JsLib jsLib) {
        testJsLibAssembly();
        jsLibAssembly.addJsLib(jsLib);
    }

    public abstract void printHtml();

    public abstract void start(String title);

    public void startLoc(String titleMessageKey) {
        start(getLocalization(titleMessageKey));
    }

    public void startLoc(String titleMessageKey, Object... messageValues) {
        start(getLocalization(titleMessageKey, messageValues));
    }

    @Override
    public void writeHtml(Appendable appendable) {
        initPrinter(appendable);
        printHtml();
    }

    private void testJsLibAssembly() {
        if (jsLibAssembly == null) {
            jsLibAssembly = new BdfJsLibAssembly(jsAnalyser);
        }
    }

}
