/* OdLib_Css- Copyright (c) 2007-2022 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 net.mapeadores.opendocument.css.output;

import java.io.IOException;
import java.util.Map;
import net.mapeadores.opendocument.elements.ElementMaps;
import net.mapeadores.opendocument.elements.ListStyleElement;
import net.mapeadores.opendocument.elements.StyleElement;


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


    private StylesConversionEngine() {

    }

    /**
     * Convertit elementMaps au format XML suivant la norme de l'entrée
     * styles.xml d'OpenDocument. La chaine commence par la déclaration xml
     * classique.
     *
     * @param elementMaps éléments à convertir
     * @return chaine contenant le XML complet
     */
    public static String toStyleXml(ElementMaps elementMaps) {
        StringBuilder buf = new StringBuilder();
        StylesXMLWriter stylesWriter = new StylesXMLWriter(buf, 0);

        try {
            stylesWriter.appendXMLDeclaration();
            stylesWriter.openStyleDocument();
            stylesWriter.openStyles();
            writeStyles(stylesWriter, elementMaps);
            stylesWriter.closeStyles();
            stylesWriter.closeStyleDocument();
        } catch (IOException ioe) {

        }
        return buf.toString();
    }

    /**
     * Convertit les styles d'elementMaps correspondant à des styles automatique
     * au format XML. La balise racine est &lt;office:automatic-styles&gt;. Ce
     * format ne corresponda pas à une entrée OpenDocument. Son but est d'être
     * un contenu XML valide qui peut être utilisé dans du XSLT pour la
     * construction finale de l'entrée OpenDocument content.xml.
     *
     * @param elementMaps éléments à convertir
     * @return chaine contenant le XML complet
     */
    public static String toAutomaticStylesXml(ElementMaps elementMaps) {
        StringBuilder buf = new StringBuilder();
        StylesXMLWriter stylesWriter = new StylesXMLWriter(buf, -999);
        try {
            stylesWriter.appendXMLDeclaration();
            stylesWriter.startOpenTag("office:automatic-styles");
            stylesWriter.appendNameSpaceAttributes();
            stylesWriter.endOpenTag();
            writeAutomaticStyles(stylesWriter, elementMaps);
            stylesWriter.closeTag("office:automatic-styles");
        } catch (IOException ioe) {

        }
        return buf.toString();
    }

    /**
     * Ajoute à Appendable tous les styles définis par elementsMaps en suivant
     * le format XML d'OpenDocument pour les styles.
     *
     * @param appendable destination
     * @param elementMaps informations de style à ajouter
     * @throws IOException
     */
    public static void appendAllStyles(Appendable appendable, ElementMaps elementMaps) throws IOException {
        StylesXMLWriter stylesWriter = new StylesXMLWriter(appendable, 0);
        writeStyles(stylesWriter, elementMaps);
    }

    /**
     * Ajoute à Appendable les styles qui doivent figurer dans la partie
     * Automatic Styles du content.xml car ils ne sont pas reconnus s'ils
     * figurent dans styles. Il s'agit des familles StyleElement.TABLE_FAMILY,
     * StyleElement.TABLECOLUMN_FAMILY, StyleElement.TABLECELL_FAMILY,
     * StyleElement.TABLEROW_FAMILY
     *
     * @param appendable destination
     * @param elementMaps informations de style à ajouter
     * @throws IOException
     */
    public static void appendAutomaticStyles(Appendable appendable, ElementMaps elementMaps) throws IOException {
        StylesXMLWriter stylesWriter = new StylesXMLWriter(appendable, 0);
        writeAutomaticStyles(stylesWriter, elementMaps);
    }

    public static String insertAllStyles(String stylesXml, ElementMaps elementMaps, boolean includeH) {
        int index = stylesXml.indexOf("</office:styles>");
        if (index == -1) {
            return stylesXml;
        }
        String part1 = stylesXml.substring(0, index);
        String part2 = stylesXml.substring(index);
        StringBuilder buf = new StringBuilder(part1);
        StylesXMLWriter stylesWriter = new StylesXMLWriter(buf, 0);
        try {
            if (includeH) {
                for (StyleElement styleElement : elementMaps.getHMap().values()) {
                    if (!part1.contains("style:name=\"" + styleElement.getStyleName() + "\"")) {
                        stylesWriter.addStyleElement(styleElement);
                    }
                }
            }
            insertStyles(part1, stylesWriter, elementMaps, StyleElement.PARAGRAPH_FAMILY);
            insertStyles(part1, stylesWriter, elementMaps, StyleElement.TEXT_FAMILY);
            insertStyles(part1, stylesWriter, elementMaps, StyleElement.TABLE_FAMILY);
            insertStyles(part1, stylesWriter, elementMaps, StyleElement.TABLECOLUMN_FAMILY);
            insertStyles(part1, stylesWriter, elementMaps, StyleElement.TABLECELL_FAMILY);
            insertStyles(part1, stylesWriter, elementMaps, StyleElement.TABLEROW_FAMILY);
            insertStyles(part1, stylesWriter, elementMaps, StyleElement.GRAPHIC_FAMILY);
            Map<String, ListStyleElement> map = elementMaps.getListStyleMap();
            for (ListStyleElement listStyleElement : map.values()) {
                if (!part1.contains("style:name=\"" + listStyleElement.getStyleName() + "\"")) {
                    stylesWriter.addListStyleElement(listStyleElement);
                }
            }
        } catch (IOException ioe) {

        }
        buf.append(part2);
        return buf.toString();
    }


    private static void writeAutomaticStyles(StylesXMLWriter stylesWriter, ElementMaps elementMaps) throws IOException {
        writeStyles(stylesWriter, elementMaps, StyleElement.TABLE_FAMILY);
        writeStyles(stylesWriter, elementMaps, StyleElement.TABLECOLUMN_FAMILY);
        writeStyles(stylesWriter, elementMaps, StyleElement.TABLECELL_FAMILY);
        writeStyles(stylesWriter, elementMaps, StyleElement.TABLEROW_FAMILY);
    }

    private static void writeStyles(StylesXMLWriter stylesWriter, ElementMaps elementMaps) throws IOException {
        for (StyleElement styleElement : elementMaps.getHMap().values()) {
            stylesWriter.addStyleElement(styleElement);
        }
        writeStyles(stylesWriter, elementMaps, StyleElement.PARAGRAPH_FAMILY);
        writeStyles(stylesWriter, elementMaps, StyleElement.TEXT_FAMILY);
        writeStyles(stylesWriter, elementMaps, StyleElement.TABLE_FAMILY);
        writeStyles(stylesWriter, elementMaps, StyleElement.TABLECOLUMN_FAMILY);
        writeStyles(stylesWriter, elementMaps, StyleElement.TABLECELL_FAMILY);
        writeStyles(stylesWriter, elementMaps, StyleElement.TABLEROW_FAMILY);
        writeStyles(stylesWriter, elementMaps, StyleElement.GRAPHIC_FAMILY);
        Map<String, ListStyleElement> map = elementMaps.getListStyleMap();
        for (ListStyleElement listStyleElement : map.values()) {
            stylesWriter.addListStyleElement(listStyleElement);
        }
    }

    private static void writeStyles(StylesXMLWriter stylesWriter, ElementMaps elementMaps, String family) throws IOException {
        Map<String, StyleElement> map = elementMaps.getFamilyMap(family);
        if ((map == null) || (map.isEmpty())) {
            return;
        }
        for (StyleElement styleElement : map.values()) {
            stylesWriter.addStyleElement(styleElement);
        }
    }

    private static void insertStyles(String text, StylesXMLWriter stylesWriter, ElementMaps elementMaps, String family) throws IOException {
        Map<String, StyleElement> map = elementMaps.getFamilyMap(family);
        if ((map == null) || (map.isEmpty())) {
            return;
        }
        for (StyleElement styleElement : map.values()) {
            if (!text.contains("style:name=\"" + styleElement.getStyleName() + "\"")) {
                stylesWriter.addStyleElement(styleElement);
            }
        }
    }


}
