/* BdfServer_Get - Copyright (c) 2011-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 fr.exemole.bdfserver.get.streamproducers;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import net.fichotheque.thesaurus.Motcle;
import net.fichotheque.thesaurus.Thesaurus;
import net.mapeadores.opendocument.io.OdSource;
import net.mapeadores.opendocument.io.OdXML;
import net.mapeadores.opendocument.io.OdZip;
import net.mapeadores.opendocument.io.OdZipEngine;
import net.mapeadores.util.io.StreamProducer;
import net.mapeadores.util.mimetype.MimeTypeConstants;
import net.mapeadores.util.text.lexie.LexieDistribution;
import net.mapeadores.util.text.lexie.LexieSource;
import net.mapeadores.util.text.lexie.Occurrence;
import net.mapeadores.util.text.lexie.TextLexieUnit;
import net.mapeadores.util.xml.AppendableXMLWriter;
import net.mapeadores.util.xml.XMLPart;
import net.mapeadores.util.xml.XMLUtils;
import net.mapeadores.util.xml.XMLWriter;


/**
 *
 * @author Vincent Calame
 */
public class LexieDistributionOdsProducer implements StreamProducer {

    private final String fileName;
    private final LexieDistribution lexieDistribution;
    private final Thesaurus thesaurus;

    public LexieDistributionOdsProducer(String fileName, LexieDistribution lexieDistribution, Thesaurus thesaurus) {
        this.fileName = fileName;
        this.lexieDistribution = lexieDistribution;
        this.thesaurus = thesaurus;
    }

    @Override
    public String getMimeType() {
        return MimeTypeConstants.ODS;
    }

    @Override
    public String getCharset() {
        return null;
    }

    @Override
    public String getFileName() {
        return fileName;
    }

    @Override
    public void writeStream(OutputStream outputStream) throws IOException {
        OdZipEngine.run(outputStream, OdZip.spreadSheet()
                .contentOdSource(new ContentOdSource())
        );
    }


    private class ContentOdSource implements OdSource {

        private ContentOdSource() {
        }

        @Override
        public void writeStream(OutputStream outputStream) throws IOException {
            BufferedWriter buf = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
            AppendableXMLWriter xmlWriter = XMLUtils.toXMLWriter(buf);
            xmlWriter.appendXMLDeclaration();
            LexieDistributionXMLPart lexieDistributionXMLPart = new LexieDistributionXMLPart(xmlWriter, thesaurus, lexieDistribution);
            lexieDistributionXMLPart.start();
            lexieDistributionXMLPart.addTable();
            lexieDistributionXMLPart.end();
            buf.flush();
        }

    }


    private static class LexieDistributionXMLPart extends XMLPart {

        private final LexieDistribution lexieDistribution;
        private final Thesaurus thesaurus;
        private final boolean withIdalpha;

        private LexieDistributionXMLPart(XMLWriter xmlWriter, Thesaurus thesaurus, LexieDistribution lexieDistribution) {
            super(xmlWriter);
            this.lexieDistribution = lexieDistribution;
            this.thesaurus = thesaurus;
            this.withIdalpha = thesaurus.isIdalphaType();
        }

        public void start() throws IOException {
            OdXML.openDocumentContent(this);
            OdXML.openBody(this);
            OdXML.openSpreadsheet(this);
        }

        public void end() throws IOException {
            OdXML.closeSpreadsheet(this);
            OdXML.closeBody(this);
            OdXML.closeDocumentContent(this);
        }

        public void addTable() throws IOException {
            String thesaurusName = thesaurus.getSubsetName();
            OdXML.openTable(this, thesaurusName);
            printFirstRow();
            int lexieCount = lexieDistribution.getLexieUnitCount();
            for (int i = 0; i < lexieCount; i++) {
                addLexieUnit(lexieDistribution.getLexieUnit(i));
            }
            OdXML.closeTable(this);
        }

        private void addLexieUnit(TextLexieUnit lexieUnit) throws IOException {
            String canonical = lexieUnit.getCanonicalLexie();
            int occurrenceCount = lexieUnit.getOccurrenceCount();
            boolean premier = true;
            LexieSource previousLexieSource = null;
            for (int i = 0; i < occurrenceCount; i++) {
                Occurrence occurrence = lexieUnit.getOccurrence(i);
                LexieSource lexieSource = occurrence.getParsedLexieSource().getLexieSource();
                if (previousLexieSource != null) {
                    if (previousLexieSource.equals(lexieSource)) {
                        continue;
                    }
                }
                previousLexieSource = lexieSource;
                OdXML.openTableRow(this);
                if (premier) {
                    OdXML.addStringTableCell(this, canonical);
                    premier = false;
                } else {
                    OdXML.addEmptyTableCell(this);
                }
                OdXML.addStringTableCell(this, lexieSource.getSourceText());
                Motcle motcle = (Motcle) lexieSource.getSourceObject();
                OdXML.addNumberTableCell(this, motcle.getId());
                if (withIdalpha) {
                    OdXML.addStringTableCell(this, motcle.getIdalpha());
                }
                OdXML.addStringTableCell(this, canonical);
                OdXML.closeTableRow(this);
            }
        }

        private void printFirstRow() throws IOException {
            OdXML.openTableRow(this);
            OdXML.addStringTableCell(this, "lexie");
            OdXML.addStringTableCell(this, "lib");
            OdXML.addStringTableCell(this, "id");
            if (withIdalpha) {
                OdXML.addStringTableCell(this, "idalpha");
            }
            OdXML.addStringTableCell(this, "lexie_rep");
            OdXML.closeTableRow(this);
        }

    }

}
