/* BdfServer - Copyright (c) 202-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.tools.exportation.table;

import fr.exemole.bdfserver.api.exportation.table.FicheTableParameters;
import net.fichotheque.Fichotheque;
import net.fichotheque.FichothequeConstants;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.metadata.CorpusField;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.exportation.table.FormatColDef;
import net.fichotheque.format.FormatSourceKey;
import net.fichotheque.format.SubsetPathKey;
import net.fichotheque.include.ExtendedIncludeKey;
import net.fichotheque.namespaces.FormatSpace;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.tools.format.FichothequeFormatDefBuilder;
import net.fichotheque.utils.TableDefUtils;
import net.mapeadores.util.attr.Attributes;
import net.mapeadores.util.date.FuzzyDate;
import net.mapeadores.util.format.FormatConstants;


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

    private BdfColDefs() {

    }

    public static FormatColDef chrono(FichothequeFormatDefBuilder formatDefBuilder, String name, String patternMode) {
        formatDefBuilder.addSource(FormatSourceKey.newSpecialIncludeNameInstance(name));
        switch (patternMode) {
            case FicheTableParameters.STANDARD_PATTERNMODE:
            case FicheTableParameters.CODE_PATTERNMODE:
                formatDefBuilder
                        .addFormatPattern("{iso}")
                        .setCastType(FormatConstants.DATE_CAST)
                        .putStringValue(FormatConstants.DATESTYLE_PARAMKEY, FormatConstants.SHORT_DATESTYLE);

                break;
            case FicheTableParameters.FORMSYNTAX_PATTERNMODE:
                formatDefBuilder
                        .addFormatPattern("{formsyntax}");
                break;
            case FicheTableParameters.LABEL_PATTERNMODE:
                formatDefBuilder
                        .addFormatPattern("{label}");
                break;
        }
        return TableDefUtils.toFormatColDef(name, formatDefBuilder.toFichothequeFormatDef());
    }

    public static FormatColDef liage(FichothequeFormatDefBuilder formatDefBuilder, String patternMode) {
        formatDefBuilder.addSource(FormatSourceKey.newSpecialIncludeNameInstance(FichothequeConstants.LIAGE_NAME));
        switch (patternMode) {
            case FicheTableParameters.STANDARD_PATTERNMODE:
            case FicheTableParameters.LABEL_PATTERNMODE:
                formatDefBuilder
                        .addFormatPattern("{title}")
                        .putStringValue(FormatConstants.SEPARATOR_PARAMKEY, ", ");
                break;
            case FicheTableParameters.CODE_PATTERNMODE:
                formatDefBuilder.addFormatPattern("{corpus}/{id}");
                break;
            case FicheTableParameters.FORMSYNTAX_PATTERNMODE:
                formatDefBuilder.addFormatPattern("{formsyntax}");
                break;
        }
        return TableDefUtils.toFormatColDef(FichothequeConstants.LIAGE_NAME, formatDefBuilder.toFichothequeFormatDef());
    }

    public static FormatColDef corpusField(FichothequeFormatDefBuilder formatDefBuilder, CorpusField corpusField, String patternMode, Attributes attributes) {
        formatDefBuilder.addSource(FormatSourceKey.newFieldKeyInstance(corpusField.getFieldKey()));
        if (isWithIntegerCast(corpusField)) {
            formatDefBuilder
                    .setCastType(FormatConstants.INTEGER_CAST);
        }
        switch (patternMode) {
            case FicheTableParameters.FORMSYNTAX_PATTERNMODE: {
                formatDefBuilder
                        .addFormatPattern("{formsyntax}");
                break;
            }
            case FicheTableParameters.STANDARD_PATTERNMODE: {
                if (isWithSeparator(corpusField)) {
                    commonLabel(formatDefBuilder, corpusField, attributes, true);
                } else {
                    switch (corpusField.getFicheItemType()) {
                        case CorpusField.AMOUNT_FIELD:
                            formatDefBuilder
                                    .addFormatPattern("{code}")
                                    .setCastType(FormatConstants.MONEY_CAST);
                            break;
                        case CorpusField.NUMBER_FIELD:
                            formatDefBuilder
                                    .addFormatPattern("{code}")
                                    .setCastType(FormatConstants.DECIMAL_CAST);
                            break;
                        case CorpusField.DATE_FIELD:
                            String dateStyle = getDateStyle(attributes, FormatConstants.LONG_DATESTYLE);
                            formatDefBuilder
                                    .addFormatPattern("{code}")
                                    .setCastType(FormatConstants.DATE_CAST)
                                    .putStringValue(FormatConstants.DATESTYLE_PARAMKEY, dateStyle);
                            break;
                        case CorpusField.COUNTRY_FIELD:
                        case CorpusField.LANGUAGE_FIELD:
                            commonLabel(formatDefBuilder, corpusField, attributes, false);
                            break;
                    }
                }
                break;
            }
            case FicheTableParameters.LABEL_PATTERNMODE: {
                commonLabel(formatDefBuilder, corpusField, attributes, isWithSeparator(corpusField));
                break;
            }
            case FicheTableParameters.CODE_PATTERNMODE: {
                switch (corpusField.getFicheItemType()) {
                    case CorpusField.AMOUNT_FIELD:
                    case CorpusField.NUMBER_FIELD:
                    case CorpusField.COUNTRY_FIELD:
                    case CorpusField.LANGUAGE_FIELD:
                        formatDefBuilder
                                .addFormatPattern("{code}");
                        break;
                }
                break;
            }
        }
        return TableDefUtils.toFormatColDef(corpusField.getFieldString(), formatDefBuilder.toFichothequeFormatDef());
    }

    private static void commonLabel(FichothequeFormatDefBuilder formatDefBuilder, CorpusField corpusField, Attributes attributes, boolean withSeparator) {
        String separator = ", ";
        switch (corpusField.getFicheItemType()) {
            case CorpusField.AMOUNT_FIELD:
                separator = " | ";
                formatDefBuilder
                        .addFormatPattern(getAmountLabelPattern(attributes));
                break;
            case CorpusField.NUMBER_FIELD:
                separator = " | ";
                formatDefBuilder
                        .addFormatPattern("{label}");
                break;
            case CorpusField.DATE_FIELD:
                separator = " | ";
                formatDefBuilder
                        .addFormatPattern(getDateLabelPattern(attributes));
                break;
            case CorpusField.COUNTRY_FIELD:
            case CorpusField.LANGUAGE_FIELD:
                formatDefBuilder
                        .addFormatPattern("{label}");
                break;
        }
        if (withSeparator) {
            formatDefBuilder
                    .putStringValue(FormatConstants.SEPARATOR_PARAMKEY, separator);
        }
    }

    public static FormatColDef subsetIncludeField(FichothequeFormatDefBuilder formatDefBuilder, ExtendedIncludeKey includeKey, String patternMode, Fichotheque fichotheque, SubsetPathKey masterPath) {
        if ((includeKey.isMaster()) && (masterPath != null)) {
            formatDefBuilder.addSource(FormatSourceKey.newIncludeKeyInstance(includeKey.getRootIncludeKey(), masterPath));
        } else {
            formatDefBuilder.addSource(FormatSourceKey.newIncludeKeyInstance(includeKey.getRootIncludeKey()));
        }
        SubsetKey subsetKey = includeKey.getSubsetKey();
        if (subsetKey.isThesaurusSubset()) {
            boolean isIdalpha = isIdalpha(fichotheque, subsetKey);
            switch (patternMode) {
                case FicheTableParameters.STANDARD_PATTERNMODE:
                case FicheTableParameters.LABEL_PATTERNMODE:
                    if (isIdalpha) {
                        formatDefBuilder
                                .addFormatPattern("{idalpha} – {label}");
                    } else {
                        formatDefBuilder
                                .addFormatPattern("{label}");
                    }
                    break;
                case FicheTableParameters.CODE_PATTERNMODE:
                    if (isIdalpha) {
                        formatDefBuilder
                                .addFormatPattern("{idalpha}");
                    } else {
                        formatDefBuilder
                                .addFormatPattern("{id}");
                    }
                    break;
                case FicheTableParameters.FORMSYNTAX_PATTERNMODE:
                    formatDefBuilder
                            .addFormatPattern("{formsyntax}");
                    break;
            }
        } else if (subsetKey.isCorpusSubset()) {
            switch (patternMode) {
                case FicheTableParameters.STANDARD_PATTERNMODE:
                case FicheTableParameters.LABEL_PATTERNMODE:
                    formatDefBuilder
                            .addFormatPattern("{title}")
                            .putStringValue(FormatConstants.SEPARATOR_PARAMKEY, ", ");
                    break;
                case FicheTableParameters.CODE_PATTERNMODE:
                    formatDefBuilder
                            .addFormatPattern("{id}");
                    break;
                case FicheTableParameters.FORMSYNTAX_PATTERNMODE:
                    formatDefBuilder
                            .addFormatPattern("{formsyntax}");
                    break;
            }
        } else {
            switch (patternMode) {
                case FicheTableParameters.STANDARD_PATTERNMODE:
                case FicheTableParameters.CODE_PATTERNMODE:
                case FicheTableParameters.LABEL_PATTERNMODE:
                    break;
                case FicheTableParameters.FORMSYNTAX_PATTERNMODE:
                    formatDefBuilder
                            .addFormatPattern("{formsyntax}");
                    break;
            }
        }
        return TableDefUtils.toFormatColDef(includeKey.getKeyString(), formatDefBuilder.toFichothequeFormatDef());
    }

    private static boolean isWithSeparator(CorpusField corpusField) {
        switch (corpusField.getCategory()) {
            case FieldKey.INFO_CATEGORY:
                return true;
            case FieldKey.SPECIAL_CATEGORY:
                switch (corpusField.getFieldString()) {
                    case FieldKey.SPECIAL_OWNERS:
                        return true;

                }
            default:
                return false;
        }
    }

    private static boolean isWithIntegerCast(CorpusField corpusField) {
        switch (corpusField.getFieldString()) {
            case FieldKey.SPECIAL_ID:
                return true;
            default:
                return false;

        }
    }

    private static boolean isIdalpha(Fichotheque fichotheque, SubsetKey subsetKey) {
        Thesaurus thesaurus = (Thesaurus) fichotheque.getSubset(subsetKey);
        if (thesaurus != null) {
            return thesaurus.isIdalphaType();
        } else {
            return false;
        }
    }

    private static String getAmountLabelPattern(Attributes attributes) {
        StringBuilder buf = new StringBuilder();
        buf.append("{label");
        String amountSubunit = attributes.getFirstValue(FormatSpace.AMOUNTSUBUNIT_KEY);
        if (amountSubunit != null) {
            buf.append(",subunit=");
            buf.append(amountSubunit);
        }
        buf.append("}");
        return buf.toString();
    }

    private static String getDateLabelPattern(Attributes attributes) {
        String dateStyle = getDateStyle(attributes, FormatConstants.LONG_DATESTYLE);
        StringBuilder buf = new StringBuilder();
        buf.append("{label");
        buf.append(",datestyle=");
        buf.append(dateStyle);
        String truncateType = attributes.getFirstValue(FormatSpace.DATELABELTRUNCATE_KEY);
        if (truncateType != null) {
            try {
                truncateType = FuzzyDate.checkDateType(truncateType);
                buf.append(",truncate=");
                buf.append(truncateType);
            } catch (IllegalArgumentException e) {

            }
        }
        buf.append("}");
        return buf.toString();
    }

    private static String getDateStyle(Attributes attributes, String defaultDateStyle) {
        if (attributes == null) {
            return defaultDateStyle;
        }
        String dateStyle = attributes.getFirstValue(FormatSpace.DATESTYLE_KEY);
        if (dateStyle == null) {
            return defaultDateStyle;
        }
        try {
            return FormatConstants.checkDateStyle(dateStyle);
        } catch (IllegalArgumentException iae) {
            return defaultDateStyle;
        }
    }

}
