/* UtilLib - Copyright (c) 2012-2023 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.util.xml;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.mapeadores.util.primitives.io.PrimitivesWriter;


/**
 *
 * @author Vincent Calame
 */
public class PrimitivesXMLWriter implements XMLWriter {

    public final static byte ELEMENT_START = 1;
    public final static byte ELEMENT_END = 2;
    public final static byte TEXT = 3;
    private PrimitivesWriter primitivesWriter;
    private AttributesBuffer attributesBuffer = new AttributesBuffer();

    public PrimitivesXMLWriter(PrimitivesWriter primitivesWriter) {
        this.primitivesWriter = primitivesWriter;
    }

    @Override
    public PrimitivesXMLWriter addText(CharSequence charSequence) throws IOException {
        text(charSequence);
        return this;
    }

    @Override
    public PrimitivesXMLWriter openTag(String name) throws IOException {
        elementStart(name);
        checkNoAttributes();
        return this;
    }

    @Override
    public PrimitivesXMLWriter openTag(String name, boolean indentBefore) throws IOException {
        elementStart(name);
        checkNoAttributes();
        return this;
    }

    @Override
    public PrimitivesXMLWriter startOpenTag(String name) throws IOException {
        elementStart(name);
        return this;
    }

    @Override
    public PrimitivesXMLWriter startOpenTag(String name, boolean indentBefore) throws IOException {
        elementStart(name);
        return this;
    }

    @Override
    public PrimitivesXMLWriter closeTag(String name) throws IOException {
        elementEnd();
        return this;
    }

    @Override
    public PrimitivesXMLWriter closeTag(String name, boolean indentBefore) throws IOException {
        elementEnd();
        return this;
    }

    @Override
    public PrimitivesXMLWriter endOpenTag() throws IOException {
        flushAttributes();
        return this;
    }

    @Override
    public PrimitivesXMLWriter addAttribute(String name, String value) throws IOException {
        if ((value == null) || (value.length() == 0)) {
            return this;
        }
        appendAttribute(name, value);
        return this;
    }

    @Override
    public PrimitivesXMLWriter addAttribute(String name, int value) throws IOException {
        appendAttribute(name, String.valueOf(value));
        return this;
    }

    @Override
    public PrimitivesXMLWriter closeEmptyTag() throws IOException {
        flushAttributes();
        elementEnd();
        return this;
    }

    @Override
    public PrimitivesXMLWriter addSimpleElement(String name, String value) throws IOException {
        if ((value == null) || (value.length() == 0)) {
            return this;
        }
        elementStart(name);
        checkNoAttributes();
        text(value);
        elementEnd();
        return this;
    }

    @Override
    public PrimitivesXMLWriter addEmptyElement(String name) throws IOException {
        elementStart(name);
        checkNoAttributes();
        elementEnd();
        return this;
    }

    @Override
    public PrimitivesXMLWriter addCData(CharSequence charSequence) throws IOException {
        text(charSequence);
        return this;
    }

    private void elementStart(String name) throws IOException {
        primitivesWriter.writeByte(ELEMENT_START);
        primitivesWriter.writeString(name);
    }

    private void checkNoAttributes() throws IOException {
        primitivesWriter.writeInt(0);
    }

    private void elementEnd() throws IOException {
        primitivesWriter.writeByte(ELEMENT_END);
    }

    private void text(CharSequence charSequence) throws IOException {
        int length = charSequence.length();
        if (length == 0) {
            return;
        }
        primitivesWriter.writeByte(TEXT);
        primitivesWriter.writeInt(length);
        for (int i = 0; i < length; i++) {
            primitivesWriter.writeChar(charSequence.charAt(i));
        }
    }

    private void appendAttribute(String name, String value) throws IOException {
        attributesBuffer.append(name, value);
    }

    private void flushAttributes() throws IOException {
        attributesBuffer.flush(primitivesWriter);
    }


    private static class AttributesBuffer {

        private List<String> nameList = new ArrayList<String>();
        private List<String> valueList = new ArrayList<String>();

        private void flush(PrimitivesWriter primitivesWriter) throws IOException {
            int length = nameList.size();
            primitivesWriter.writeInt(length);
            for (int i = 0; i < length; i++) {
                primitivesWriter.writeString(nameList.get(i));
                primitivesWriter.writeString(valueList.get(i));
            }
            nameList.clear();
            valueList.clear();
        }

        private void append(String name, String value) {
            nameList.add(name);
            valueList.add(value);
        }

    }

}
