/* BdfServer - 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 fr.exemole.bdfserver.tools.exportation.table;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.exportation.table.FicheTableParameters;
import fr.exemole.bdfserver.api.namespaces.CellSpace;
import fr.exemole.bdfserver.api.ui.FieldUi;
import fr.exemole.bdfserver.api.ui.SpecialIncludeUi;
import fr.exemole.bdfserver.api.ui.SubsetIncludeUi;
import fr.exemole.bdfserver.api.ui.UiComponent;
import fr.exemole.bdfserver.api.ui.UiComponents;
import java.util.ArrayList;
import java.util.List;
import net.fichotheque.Fichotheque;
import net.fichotheque.FichothequeConstants;
import net.fichotheque.Subset;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.metadata.CorpusField;
import net.fichotheque.corpus.metadata.CorpusMetadata;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.exportation.table.FormatColDef;
import net.fichotheque.exportation.table.TableDef;
import net.fichotheque.exportation.table.TableDefItem;
import net.fichotheque.format.FormatSourceKey;
import net.fichotheque.format.SubsetPathKey;
import net.fichotheque.include.ExtendedIncludeKey;
import net.fichotheque.permission.PermissionSummary;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.thesaurus.metadata.ThesaurusFieldKey;
import net.fichotheque.thesaurus.metadata.ThesaurusLangChecker;
import net.fichotheque.tools.format.FichothequeFormatDefBuilder;
import net.fichotheque.utils.TableDefUtils;
import net.fichotheque.utils.ThesaurusUtils;
import net.mapeadores.util.attr.Attribute;
import net.mapeadores.util.format.FormatConstants;


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

    private DefaultTableDefFactory() {

    }

    public static TableDef fromUi(BdfServer bdfServer, Corpus corpus, FicheTableParameters ficheTableParameters, PermissionSummary permissionSummary) {
        CorpusMetadata corpusMetadata = corpus.getCorpusMetadata();
        String patternMode = ficheTableParameters.getPatternMode();
        Fichotheque fichotheque = corpus.getFichotheque();
        SubsetPathKey masterPath = getMasterPath(corpus, permissionSummary);
        List<TableDefItem> tableDefItemList = new ArrayList<TableDefItem>();
        tableDefItemList.add(BdfColDefs.corpusField(FichothequeFormatDefBuilder.init(), corpusMetadata.getCorpusField(FieldKey.ID), patternMode, null));
        UiComponents uiComponents = bdfServer.getUiManager().getMainUiComponents(corpus);
        for (UiComponent uiComponent : uiComponents.getUiComponentList()) {
            FichothequeFormatDefBuilder formatDefBuilder = new FichothequeFormatDefBuilder();
            if (uiComponent instanceof FieldUi) {
                FieldUi fieldUi = (FieldUi) uiComponent;
                FieldKey fieldKey = fieldUi.getFieldKey();
                if ((!ficheTableParameters.isWith(FicheTableParameters.WITH_SECTION)) && (fieldKey.isSection())) {
                    continue;
                }
                CorpusField corpusField = corpusMetadata.getCorpusField(fieldKey);
                if (corpusField != null) {
                    tableDefItemList.add(BdfColDefs.corpusField(formatDefBuilder, corpusField, patternMode, fieldUi.getAttributes()));
                }
            } else if (uiComponent instanceof SpecialIncludeUi) {
                switch (uiComponent.getName()) {
                    case FichothequeConstants.LIAGE_NAME:
                        if (ficheTableParameters.isWith(FicheTableParameters.WITH_CORPUSINCLUDE)) {
                            tableDefItemList.add(BdfColDefs.liage(formatDefBuilder, patternMode));
                        }
                }
            } else if (uiComponent instanceof SubsetIncludeUi) {
                SubsetIncludeUi includeUi = (SubsetIncludeUi) uiComponent;
                ExtendedIncludeKey extendedIncludeKey = includeUi.getExtendedIncludeKey();
                if (testInclude(ficheTableParameters, extendedIncludeKey)) {
                    Subset otherSubset = bdfServer.getFichotheque().getSubset(extendedIncludeKey.getSubsetKey());
                    if ((otherSubset != null) && (permissionSummary.hasAccess(otherSubset))) {
                        tableDefItemList.add(BdfColDefs.subsetIncludeField(formatDefBuilder, extendedIncludeKey, patternMode, fichotheque, masterPath));
                    }
                }
            }
        }
        if (ficheTableParameters.isWith(FicheTableParameters.WITH_CHRONO)) {
            tableDefItemList.add(BdfColDefs.chrono(FichothequeFormatDefBuilder.init(), FichothequeConstants.DATECREATION_NAME, patternMode));
            tableDefItemList.add(BdfColDefs.chrono(FichothequeFormatDefBuilder.init(), FichothequeConstants.DATEMODIFICATION_NAME, patternMode));
        }
        return TableDefUtils.toTableDef(tableDefItemList);
    }

    public static TableDef fromComponentList(BdfServer bdfServer, Corpus corpus, List<UiComponent> componentList, String patternMode, PermissionSummary permissionSummary) {
        CorpusMetadata corpusMetadata = corpus.getCorpusMetadata();
        Fichotheque fichotheque = corpus.getFichotheque();
        SubsetPathKey masterPath = getMasterPath(corpus, permissionSummary);
        List<TableDefItem> tableDefItemList = new ArrayList<TableDefItem>();
        for (UiComponent uiComponent : componentList) {
            FichothequeFormatDefBuilder formatDefBuilder = new FichothequeFormatDefBuilder();
            checkAttributes(formatDefBuilder, uiComponent);
            if (uiComponent instanceof FieldUi) {
                FieldUi fieldUi = (FieldUi) uiComponent;
                FieldKey fieldKey = fieldUi.getFieldKey();
                CorpusField corpusField = corpusMetadata.getCorpusField(fieldKey);
                if (corpusField != null) {
                    tableDefItemList.add(BdfColDefs.corpusField(formatDefBuilder, corpusField, patternMode, fieldUi.getAttributes()));
                }
            } else if (uiComponent instanceof SpecialIncludeUi) {
                switch (uiComponent.getName()) {
                    case FichothequeConstants.LIAGE_NAME:
                        tableDefItemList.add(BdfColDefs.liage(formatDefBuilder, patternMode));
                }
            } else if (uiComponent instanceof SubsetIncludeUi) {
                SubsetIncludeUi includeUi = (SubsetIncludeUi) uiComponent;
                ExtendedIncludeKey extendedIncludeKey = includeUi.getExtendedIncludeKey();
                Subset otherSubset = bdfServer.getFichotheque().getSubset(extendedIncludeKey.getSubsetKey());
                if ((otherSubset != null) && (permissionSummary.hasAccess(otherSubset))) {
                    tableDefItemList.add(BdfColDefs.subsetIncludeField(formatDefBuilder, extendedIncludeKey, patternMode, fichotheque, masterPath));
                }
            }
        }
        return TableDefUtils.toTableDef(tableDefItemList);
    }

    public static TableDef fromThesaurusMetadata(Thesaurus thesaurus, ThesaurusLangChecker thesaurusLangChecker) {
        List<TableDefItem> tableDefItemList = new ArrayList<TableDefItem>();
        List<ThesaurusFieldKey> coreList = ThesaurusUtils.computeCoreFieldList(thesaurus, thesaurusLangChecker);
        for (ThesaurusFieldKey thesaurusFieldKey : coreList) {
            FichothequeFormatDefBuilder formatDefBuilder = new FichothequeFormatDefBuilder();
            formatDefBuilder.addSource(FormatSourceKey.newThesaurusFieldKeyInstance(thesaurusFieldKey));
            if (castToInteger(thesaurusFieldKey)) {
                formatDefBuilder.setCastType(FormatConstants.INTEGER_CAST);
            }
            FormatColDef colDef = TableDefUtils.toFormatColDef(thesaurusFieldKey.toString(), formatDefBuilder.toFichothequeFormatDef());
            tableDefItemList.add(colDef);
        }
        return TableDefUtils.toTableDef(tableDefItemList);
    }

    private static boolean castToInteger(ThesaurusFieldKey thesaurusFieldKey) {
        if (thesaurusFieldKey.equals(ThesaurusFieldKey.ID)) {
            return true;
        }
        if (thesaurusFieldKey.equals(ThesaurusFieldKey.PARENT_ID)) {
            return true;
        }
        if (thesaurusFieldKey.equals(ThesaurusFieldKey.LEVEL)) {
            return true;
        }
        return false;
    }

    private static boolean testInclude(FicheTableParameters ficheTableParameters, ExtendedIncludeKey extendedIncludeKey) {
        switch (extendedIncludeKey.getCategory()) {
            case SubsetKey.CATEGORY_ADDENDA:
                return ficheTableParameters.isWith(FicheTableParameters.WITH_ADDENDAINCLUDE);
            case SubsetKey.CATEGORY_ALBUM:
                return ficheTableParameters.isWith(FicheTableParameters.WITH_ALBUMINCLUDE);
            case SubsetKey.CATEGORY_CORPUS:
                return ficheTableParameters.isWith(FicheTableParameters.WITH_CORPUSINCLUDE);
            case SubsetKey.CATEGORY_THESAURUS:
                return ficheTableParameters.isWith(FicheTableParameters.WITH_THESAURUSINCLUDE);
            default:
                return false;
        }
    }

    private static SubsetPathKey getMasterPath(Corpus corpus, PermissionSummary permissionSummary) {
        Subset masterSubset = corpus.getMasterSubset();
        if ((masterSubset != null) && (masterSubset instanceof Thesaurus) && (permissionSummary.hasAccess(masterSubset))) {
            return SubsetPathKey.newParentagePath(masterSubset.getSubsetKey());
        } else {
            return null;
        }
    }

    private static void checkAttributes(FichothequeFormatDefBuilder formatDefBuilder, UiComponent uiComponent) {
        Attribute cellFormat = uiComponent.getAttributes().getAttribute(CellSpace.FORMAT_KEY);
        if (cellFormat != null) {
            formatDefBuilder.putStringValue(CellSpace.FORMAT_KEY.toString(), cellFormat.getFirstValue());
        }
    }

}
