/* FichothequeLib_Xml - Copyright (c) 2021-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.fichotheque.xml.storage;

import java.io.IOException;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.fiche.Atts;
import net.fichotheque.corpus.fiche.Cdatadiv;
import net.fichotheque.corpus.fiche.Code;
import net.fichotheque.corpus.fiche.Div;
import net.fichotheque.corpus.fiche.FicheBlock;
import net.fichotheque.corpus.fiche.FicheBlocks;
import net.fichotheque.corpus.fiche.H;
import net.fichotheque.corpus.fiche.Insert;
import net.fichotheque.corpus.fiche.Li;
import net.fichotheque.corpus.fiche.Ln;
import net.fichotheque.corpus.fiche.P;
import net.fichotheque.corpus.fiche.S;
import net.fichotheque.corpus.fiche.Table;
import net.fichotheque.corpus.fiche.Td;
import net.fichotheque.corpus.fiche.TextContent;
import net.fichotheque.corpus.fiche.Tr;
import net.fichotheque.corpus.fiche.Ul;
import net.fichotheque.corpus.fiche.ZoneBlock;
import net.mapeadores.util.xml.XMLPart;
import net.mapeadores.util.xml.XMLUtils;
import net.mapeadores.util.xml.XMLWriter;


/**
 *
 * @author Vincent Calame
 */
public class FicheBlockStorageXMLPart extends XMLPart {

    public FicheBlockStorageXMLPart(XMLWriter xmlWriter) {
        super(xmlWriter);
    }

    public void addFicheBlock(FicheBlock ficheBlock) throws IOException {
        if (ficheBlock instanceof P) {
            addP((P) ficheBlock);
        } else if (ficheBlock instanceof H) {
            addH((H) ficheBlock);
        } else if (ficheBlock instanceof Ul) {
            addUl((Ul) ficheBlock);
        } else if (ficheBlock instanceof Code) {
            addCode((Code) ficheBlock);
        } else if (ficheBlock instanceof Table) {
            addTable((Table) ficheBlock);
        } else if (ficheBlock instanceof Insert) {
            addInsert((Insert) ficheBlock);
        } else if (ficheBlock instanceof Div) {
            addDiv((Div) ficheBlock);
        } else if (ficheBlock instanceof Cdatadiv) {
            addCdataDiv((Cdatadiv) ficheBlock);
        } else {
            throw new IllegalArgumentException("unknown FicheBlock Implementation");
        }
    }

    public void addFicheBlocks(FicheBlocks ficheBlocks) throws IOException {
        int size = ficheBlocks.size();
        for (int i = 0; i < size; i++) {
            addFicheBlock(ficheBlocks.get(i));
        }
    }

    public void addTextContent(TextContent content) throws IOException {
        for (Object obj : content) {
            if (obj instanceof String) {
                addText((String) obj);
            } else if (obj instanceof S) {
                addS((S) obj);
            }
        }
    }

    public void addP(P p) throws IOException {
        startOpenTag("p");
        addAttribute("type", P.typeToString(p.getType()));
        addAttribute("source", p.getSource());
        addAtts(p);
        endOpenTag();
        addTextContent(p);
        closeTag("p", false);
    }

    public void addH(H h) throws IOException {
        startOpenTag("h");
        addAttribute("level", String.valueOf(h.getLevel()));
        addAtts(h);
        endOpenTag();
        addTextContent(h);
        closeTag("h", false);
    }

    public void addUl(Ul ul) throws IOException {
        startOpenTag("ul");
        addAtts(ul);
        endOpenTag();
        for (Li li : ul) {
            addLi(li);
        }
        closeTag("ul");
    }

    public void addLi(Li li) throws IOException {
        startOpenTag("li");
        addAtts(li.getAtts());
        endOpenTag();
        addFicheBlocks(li);
        closeTag("li");
    }

    public void addCode(Code code) throws IOException {
        startOpenTag("code");
        addAttribute("type", Code.typeToString(code.getType()));
        addAtts(code);
        endOpenTag();
        addZoneBlockElements(code);
        for (Ln ln : code) {
            addLn(ln);
        }
        closeTag("code");
    }

    public void addLn(Ln ln) throws IOException {
        int indentation = ln.getIndentation();
        startOpenTag("ln");
        if (indentation > 0) {
            addAttribute("indent", String.valueOf(indentation));
        }
        addAtts(ln.getAtts());
        endOpenTag();
        addText(ln.getValue());
        closeTag("ln", false);
    }

    public void addDiv(Div div) throws IOException {
        startOpenTag("div");
        XMLUtils.addXmlLangAttribute(this, div.getLang());
        addAtts(div);
        endOpenTag();
        addZoneBlockElements(div);
        openTag("fbl");
        addFicheBlocks(div);
        closeTag("fbl");
        closeTag("div");
    }

    public void addCdataDiv(Cdatadiv cdatadiv) throws IOException {
        startOpenTag("cdatadiv");
        addAtts(cdatadiv);
        endOpenTag();
        addZoneBlockElements(cdatadiv);
        startOpenTag("cdata");
        endOpenTag();
        addCData(cdatadiv.getCdata());
        closeTag("cdata", false);
        closeTag("cdatadiv");
    }

    public void addS(S s) throws IOException {
        short sType = s.getType();
        startOpenTag("s", false);
        addAttribute("type", S.typeToString(sType));
        addAttribute("ref", s.getRef());
        addAtts(s.getAtts());
        String value = s.getValue();
        if (value.length() > 0) {
            endOpenTag();
            addText(value);
            closeTag("s", false);
        } else {
            closeEmptyTag();
        }
    }

    public void addTable(Table table) throws IOException {
        startOpenTag("table");
        addAtts(table);
        endOpenTag();
        addZoneBlockElements(table);
        for (Tr tr : table) {
            addTr(tr);
        }
        closeTag("table");
    }

    public void addTr(Tr tr) throws IOException {
        startOpenTag("tr");
        addAtts(tr.getAtts());
        endOpenTag();
        for (Td td : tr) {
            addTd(td);
        }
        closeTag("tr");
    }

    public void addTd(Td td) throws IOException {
        startOpenTag("td");
        addAttribute("type", Td.typeToString(td.getType()));
        addAtts(td.getAtts());
        endOpenTag();
        addTextContent(td);
        closeTag("td", false);
    }

    public void addInsert(Insert insert) throws IOException {
        startOpenTag("insert");
        addAttribute("type", Insert.typeToString(insert.getType()));
        addAttribute("src", insert.getSrc());
        addAttribute("ref", insert.getRef());
        addAttribute("position", Insert.positionToString(insert.getPosition()));
        int width = insert.getWidth();
        if (width >= 0) {
            addAttribute("width", String.valueOf(width));
        }
        int height = insert.getHeight();
        if (height >= 0) {
            addAttribute("height", String.valueOf(height));
        }
        SubsetKey subsetKey = insert.getSubsetKey();
        if (subsetKey != null) {
            int id = insert.getId();
            if (subsetKey.isAddendaSubset()) {
                addAttribute("addenda", subsetKey.getSubsetName());
                addAttribute("id", id);
            } else {
                String albumDimName = insert.getAlbumDimName();
                addAttribute("album", subsetKey.getSubsetName());
                addAttribute("id", id);
                addAttribute("albumdim", albumDimName);
            }
        }
        addAtts(insert);
        endOpenTag();
        addZoneBlockElements(insert);
        addZoneBlockElement("alt", insert.getAlt());
        addZoneBlockElement("credit", insert.getCredit());
        closeTag("insert");
    }

    private void addZoneBlockElements(ZoneBlock zoneBlock) throws IOException {
        addZoneBlockElement("numero", zoneBlock.getNumero());
        addZoneBlockElement("legende", zoneBlock.getLegende());
    }

    private void addZoneBlockElement(String name, TextContent textContent) throws IOException {
        if (!textContent.isEmpty()) {
            startOpenTag(name);
            endOpenTag();
            addTextContent(textContent);
            closeTag(name, false);
        }
    }

    private void addAtts(FicheBlock ficheBlock) throws IOException {
        addAtts(ficheBlock.getAtts());
    }

    private void addAtts(Atts atts) throws IOException {
        int attLength = atts.size();
        for (int i = 0; i < attLength; i++) {
            addAttribute("att-" + atts.getName(i), atts.getValue(i));
        }
    }

}
