/* BdfServer - Copyright (c) 2012-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.impl;

import fr.exemole.bdfserver.api.managers.TableExportManager;
import fr.exemole.bdfserver.api.storage.BdfStorageException;
import fr.exemole.bdfserver.api.storage.StorageContent;
import fr.exemole.bdfserver.api.storage.TableExportStorage;
import fr.exemole.bdfserver.tools.exportation.table.TableExportCompiler;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import net.fichotheque.EditOrigin;
import net.fichotheque.Fichotheque;
import net.fichotheque.Subset;
import net.fichotheque.SubsetKey;
import net.fichotheque.exportation.table.TableDef;
import net.fichotheque.exportation.table.TableExport;
import net.fichotheque.exportation.table.TableExportContentDescription;
import net.fichotheque.exportation.table.TableExportContext;
import net.fichotheque.exportation.table.TableExportDef;
import net.fichotheque.exportation.table.TableExportDescription;
import net.fichotheque.tools.exportation.table.SubsetTableBuilder;
import net.fichotheque.tools.exportation.table.TableExportBuilder;
import net.fichotheque.utils.TableDefUtils;
import net.fichotheque.utils.TableExportUtils;
import net.mapeadores.util.io.IOUtils;


/**
 *
 * @author Vincent Calame
 */
class TableExportManagerImpl implements TableExportManager {

    private final Fichotheque fichotheque;
    private final TableExportStorage tableExportStorage;
    private final TableExportContext tableExportContext;
    private final SortedMap<String, TableExportDescription> tableExportDescriptionMap = new TreeMap<String, TableExportDescription>();
    private final SortedMap<String, TableExportDescription> validTableExportDescriptionMap = new TreeMap<String, TableExportDescription>();
    private List<TableExportDescription> tableExportDescriptionList = Collections.emptyList();
    private List<TableExportDescription> validTableExportDescriptionList = Collections.emptyList();


    TableExportManagerImpl(Fichotheque fichotheque, TableExportStorage tableExportStorage, TableExportContext tableExportContext) {
        this.fichotheque = fichotheque;
        this.tableExportStorage = tableExportStorage;
        this.tableExportContext = tableExportContext;
    }

    @Override
    public synchronized void update() {
        tableExportDescriptionMap.clear();
        validTableExportDescriptionMap.clear();
        TableExportStorage.Unit[] array = tableExportStorage.checkStorage();
        TableExportCompiler compiler = new TableExportCompiler(tableExportContext);
        for (TableExportStorage.Unit storageUnit : array) {
            TableExportDescription tableExportDescription = compiler.compile(storageUnit);
            if (tableExportDescription.isValid()) {
                validTableExportDescriptionMap.put(tableExportDescription.getName(), tableExportDescription);
            }
            tableExportDescriptionMap.put(tableExportDescription.getName(), tableExportDescription);
        }
        initLists();
    }

    @Override
    public synchronized List<TableExportDescription> getTableExportDescriptionList() {
        return tableExportDescriptionList;
    }

    @Override
    public synchronized List<TableExportDescription> getValidTableExportDescriptionList() {
        return validTableExportDescriptionList;
    }

    @Override
    public synchronized String getTableExportContent(String tableExportName, String contentPath) {
        StorageContent storageContent = tableExportStorage.getStorageContent(tableExportName, contentPath);
        if (storageContent != null) {
            try (InputStream is = storageContent.getInputStream()) {
                return IOUtils.toString(is, "UTF-8");
            } catch (IOException ioe) {
                throw new BdfStorageException(ioe);
            }
        } else {
            return null;
        }
    }

    @Override
    public synchronized TableExportDescription putTableExportDef(TableExportDef tableExportDef, EditOrigin editOrigin) {
        String tableExportName = tableExportDef.getName();
        tableExportStorage.saveTableExportDef(tableExportDef, editOrigin);
        return reinitTableExportDescription(tableExportName);
    }

    @Override
    public synchronized TableExportDescription putTableExportContent(String tableExportName, String contentPath, InputStream inputStream, EditOrigin editOrigin) throws IOException {
        if (tableExportDescriptionMap.containsKey(tableExportName)) {
            tableExportStorage.saveStorageContent(tableExportName, contentPath, inputStream, editOrigin);
            return reinitTableExportDescription(tableExportName);
        } else {
            return null;
        }
    }

    @Override
    public synchronized TableExportDescription removeTableExportContent(String tableExportName, String contentPath, EditOrigin editOrigin) {
        boolean done = tableExportStorage.removeStorageContent(tableExportName, contentPath, editOrigin);
        if (done) {
            return reinitTableExportDescription(tableExportName);
        } else {
            return null;
        }
    }

    @Override
    public synchronized TableExportDescription putTableDef(String tableExportName, SubsetKey corpusKey, TableDef tableDef, EditOrigin editOrigin) {
        StringBuilder buf = new StringBuilder();
        try {
            TableDefUtils.writeTableDef(buf, tableDef);
        } catch (IOException ioe) {
        }
        try (InputStream is = IOUtils.toInputStream(buf.toString(), "UTF-8")) {
            tableExportStorage.saveStorageContent(tableExportName, corpusKey + ".txt", is, editOrigin);
        } catch (IOException ioe) {
            throw new BdfStorageException(ioe);
        }
        return reinitTableExportDescription(tableExportName);
    }

    @Override
    public synchronized TableExport getTableExport(String tableExportName) {
        TableExportDescription tableExportDescription = validTableExportDescriptionMap.get(tableExportName);
        if (tableExportDescription == null) {
            return null;
        }
        TableExportBuilder tableExportBuilder = TableExportBuilder.init()
                .setTableExportDef(tableExportDescription.getTableExportDef());
        for (TableExportContentDescription contentDescription : tableExportDescription.getTableExportContentDescriptionList()) {
            if (!contentDescription.isValid()) {
                continue;
            }
            SubsetKey subsetKey = contentDescription.getSubsetKey();
            if (subsetKey == null) {
                continue;
            }
            Subset subset = fichotheque.getSubset(subsetKey);
            if (subset == null) {
                continue;
            }
            tableExportBuilder.addSubsetTable(SubsetTableBuilder.init(subset).populate(contentDescription.getTableDef(), tableExportContext).toSubsetTable());
        }
        return tableExportBuilder.toTableExport();
    }

    @Override
    public synchronized boolean containsTableExport(String tableExportName) {
        return validTableExportDescriptionMap.containsKey(tableExportName);
    }

    @Override
    public synchronized void removeTableExport(String tableExportName, EditOrigin editOrigin) {
        boolean done = tableExportStorage.removeTableExport(tableExportName, editOrigin);
        if (done) {
            update();
        }
    }

    @Override
    public synchronized TableExportDescription copyTableExport(String tableExportName, String newTableExportName, EditOrigin editOrigin) {
        boolean done = tableExportStorage.copyTableExport(tableExportName, newTableExportName, editOrigin);
        if (done) {
            update();
            return tableExportDescriptionMap.get(newTableExportName);
        } else {
            return null;
        }
    }

    private TableExportDescription reinitTableExportDescription(String tableExportName) {
        TableExportStorage.Unit tableExportStorageUnit = tableExportStorage.getTableExportStorageUnit(tableExportName);
        TableExportCompiler compiler = new TableExportCompiler(tableExportContext);
        TableExportDescription tableExportDescription = compiler.compile(tableExportStorageUnit);
        if (tableExportDescription.isValid()) {
            validTableExportDescriptionMap.put(tableExportName, tableExportDescription);
        } else {
            validTableExportDescriptionMap.remove(tableExportName);
        }
        tableExportDescriptionMap.put(tableExportName, tableExportDescription);
        initLists();
        return tableExportDescription;
    }

    private void initLists() {
        tableExportDescriptionList = TableExportUtils.wrap(tableExportDescriptionMap.values().toArray(new TableExportDescription[tableExportDescriptionMap.size()]));
        validTableExportDescriptionList = TableExportUtils.wrap(validTableExportDescriptionMap.values().toArray(new TableExportDescription[validTableExportDescriptionMap.size()]));
    }


}
