/* FichothequeLib_Tools  - 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 net.fichotheque.tools.format.catalogs;

import java.io.IOException;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
import net.fichotheque.FichothequeQuestioner;
import net.fichotheque.Subset;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.fiche.AmountItem;
import net.fichotheque.corpus.fiche.CountryItem;
import net.fichotheque.corpus.fiche.DateItem;
import net.fichotheque.corpus.fiche.EmailItem;
import net.fichotheque.corpus.fiche.FicheItem;
import net.fichotheque.corpus.fiche.GeopointItem;
import net.fichotheque.corpus.fiche.ImageItem;
import net.fichotheque.corpus.fiche.Item;
import net.fichotheque.corpus.fiche.LanguageItem;
import net.fichotheque.corpus.fiche.LinkItem;
import net.fichotheque.corpus.fiche.NumberItem;
import net.fichotheque.corpus.fiche.ParaItem;
import net.fichotheque.corpus.fiche.PersonItem;
import net.fichotheque.format.FormatSource;
import net.fichotheque.format.formatters.FicheBlockFormatter;
import net.fichotheque.format.formatters.FicheItemFormatter;
import net.fichotheque.json.FicheItemJson;
import net.fichotheque.sphere.Redacteur;
import net.fichotheque.syntax.FormSyntax;
import net.fichotheque.tools.format.JsonParameters;
import net.fichotheque.tools.format.LangParameters;
import net.fichotheque.tools.format.FormatterEngineUtils;
import net.fichotheque.utils.SphereUtils;
import net.mapeadores.util.date.FuzzyDate;
import net.mapeadores.util.date.FuzzyDateFormatter;
import net.mapeadores.util.exceptions.ShouldNotOccurException;
import net.mapeadores.util.json.JSONWriter;
import net.mapeadores.util.json.PropertyEligibility;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.LangContext;
import net.mapeadores.util.localisation.MessageLocalisation;
import net.mapeadores.util.localisation.MessageLocalisationProvider;
import net.mapeadores.util.localisation.SpecialCodes;
import net.mapeadores.util.models.PersonCore;
import net.mapeadores.util.money.ExtendedCurrency;
import net.mapeadores.util.money.MoneyUtils;
import net.mapeadores.util.primitives.Decimal;
import net.mapeadores.util.primitives.DegreSexagesimal;
import net.mapeadores.util.text.StringUtils;


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

    public final static FicheItemFormatter COUNTRY_CODE = (ficheItem, formatSource) -> {
        if (ficheItem instanceof CountryItem) {
            return ((CountryItem) ficheItem).getCountry().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter LANGUAGE_CODE = (ficheItem, formatSource) -> {
        if (ficheItem instanceof LanguageItem) {
            return ((LanguageItem) ficheItem).getLang().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter ITEM = (ficheItem, formatSource) -> {
        if (ficheItem instanceof Item) {
            return ((Item) ficheItem).getValue();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PARA_RAW = (ficheItem, formatSource) -> {
        if (ficheItem instanceof ParaItem) {
            return ((ParaItem) ficheItem).contentToString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter GEO_LAT = (ficheItem, formatSource) -> {
        if (ficheItem instanceof GeopointItem) {
            return ((GeopointItem) ficheItem).getLatitude().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter GEO_LON = (ficheItem, formatSource) -> {
        if (ficheItem instanceof GeopointItem) {
            return ((GeopointItem) ficheItem).getLongitude().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter LINK_HREF = (ficheItem, formatSource) -> {
        if (ficheItem instanceof LinkItem) {
            return ((LinkItem) ficheItem).getHref();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter LINK_TITLE = (ficheItem, formatSource) -> {
        if (ficheItem instanceof LinkItem) {
            return ((LinkItem) ficheItem).getTitle();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter LINK_COMMENT = (ficheItem, formatSource) -> {
        if (ficheItem instanceof LinkItem) {
            return ((LinkItem) ficheItem).getComment();
        }
        return getDefaultFormat(ficheItem);
    };
    public final static FicheItemFormatter IMAGE_SRC = (ficheItem, formatSource) -> {
        if (ficheItem instanceof ImageItem) {
            return ((ImageItem) ficheItem).getSrc();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter IMAGE_ALT = (ficheItem, formatSource) -> {
        if (ficheItem instanceof ImageItem) {
            return ((ImageItem) ficheItem).getAlt();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter IMAGE_TITLE = (ficheItem, formatSource) -> {
        if (ficheItem instanceof ImageItem) {
            return ((ImageItem) ficheItem).getTitle();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter EMAIL_COMPLETE = (ficheItem, formatSource) -> {
        if (ficheItem instanceof EmailItem) {
            return ((EmailItem) ficheItem).getEmailCore().toCompleteString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter EMAIL_ADDRESS = (ficheItem, formatSource) -> {
        if (ficheItem instanceof EmailItem) {
            return ((EmailItem) ficheItem).getEmailCore().getAddrSpec();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter EMAIL_NAME = (ficheItem, formatSource) -> {
        if (ficheItem instanceof EmailItem) {
            return ((EmailItem) ficheItem).getEmailCore().getRealName();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter NUMBER_CODE = (ficheItem, formatSource) -> {
        if (ficheItem instanceof NumberItem) {
            return ((NumberItem) ficheItem).getDecimal().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter AMOUNT_CODE = (ficheItem, formatSource) -> {
        if (ficheItem instanceof AmountItem) {
            return ((AmountItem) ficheItem).toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter AMOUNT_CURRENCY = (ficheItem, formatSource) -> {
        if (ficheItem instanceof AmountItem) {
            return ((AmountItem) ficheItem).getCurrency().getCurrencyCode();
        }
        return getDefaultFormat(ficheItem);
    };
    public final static FicheItemFormatter AMOUNT_DECIMAL = (ficheItem, formatSource) -> {
        if (ficheItem instanceof AmountItem) {
            return ((AmountItem) ficheItem).getDecimal().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter AMOUNT_MONEYLONG = (ficheItem, formatSource) -> {
        if (ficheItem instanceof AmountItem) {
            return String.valueOf(((AmountItem) ficheItem).toMoneyLong());
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_CODE = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return ((DateItem) ficheItem).getDate().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_ISO = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return ((DateItem) ficheItem).getDate().toISOString(false);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_ISO_LAST = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return ((DateItem) ficheItem).getDate().toISOString(true);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_YEAR = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return String.valueOf(((DateItem) ficheItem).getDate().getYear());
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_ISOMONTH = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return ((DateItem) ficheItem).getDate().toMonthString(false);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_ISOMONTH_LAST = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return ((DateItem) ficheItem).getDate().toMonthString(true);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_LOGIN = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            String userGlobalId = ((PersonItem) ficheItem).getRedacteurGlobalId();
            if (userGlobalId != null) {
                Redacteur redacteur = formatSource.getFichothequeQuestioner().getRedacteurByGlobalId(userGlobalId);
                if (redacteur != null) {
                    return redacteur.getLogin();
                } else {
                    return "";
                }
            } else {
                return "";
            }
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_SPHERE = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            String redacteurGlobalId = ((PersonItem) ficheItem).getRedacteurGlobalId();
            if (redacteurGlobalId != null) {
                try {
                    SubsetKey sphereKey = SphereUtils.getSubsetKey(redacteurGlobalId);
                    return sphereKey.getSubsetName();
                } catch (ParseException pe) {
                    return "#ERR: wrong redacteurGlobaleId = " + redacteurGlobalId;
                }
            } else {
                return "";
            }
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_CODE = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            String userGlobalId = ((PersonItem) ficheItem).getRedacteurGlobalId();
            if (userGlobalId != null) {
                Redacteur redacteur = formatSource.getFichothequeQuestioner().getRedacteurByGlobalId(userGlobalId);
                if (redacteur != null) {
                    return redacteur.getBracketStyle();
                } else {
                    return userGlobalId;
                }
            } else {
                return ((PersonItem) ficheItem).getPersonCore().toStandardStyle();
            }
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_STANDARD = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterEngineUtils.toPersonCore(ficheItem, formatSource);
            return personCore.toStandardStyle();
        }
        return getDefaultFormat(ficheItem);
    };
    public final static FicheItemFormatter PERSON_DIRECTORY = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterEngineUtils.toPersonCore(ficheItem, formatSource);
            return personCore.toDirectoryStyle(false);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_UPDIRECTORY = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterEngineUtils.toPersonCore(ficheItem, formatSource);
            return personCore.toDirectoryStyle(true);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_BIBLIO = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterEngineUtils.toPersonCore(ficheItem, formatSource);
            return personCore.toBiblioStyle(false);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_UPBIBLIO = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterEngineUtils.toPersonCore(ficheItem, formatSource);
            return personCore.toBiblioStyle(true);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_SURNAME = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            return FormatterEngineUtils.toPersonCore(ficheItem, formatSource).getSurname();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_UPSURNAME = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            return FormatterEngineUtils.toPersonCore(ficheItem, formatSource).getSurname().toUpperCase();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_FORENAME = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            return FormatterEngineUtils.toPersonCore(ficheItem, formatSource).getForename();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_NONLATIN = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            return FormatterEngineUtils.toPersonCore(ficheItem, formatSource).getNonlatin();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_SURNAMEFIRST = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterEngineUtils.toPersonCore(ficheItem, formatSource);
            return (personCore.isSurnameFirst()) ? "1" : "0";
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_ORGANISM = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            return ((PersonItem) ficheItem).getOrganism();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter FORMSYNTAX = (ficheItem, formatSource) -> {
        return FormSyntax.toString(ficheItem, formatSource.getFichothequeQuestioner(), null);
    };

    private FicheItemFormatterCatalog() {
    }

    public static FicheItemFormatter newLinkHrefPart(String base) {
        if (base == null) {
            return LINK_HREF;
        }
        return new LinkHref(base);
    }

    public static FicheItemFormatter newImageSrcPart(String base) {
        if (base == null) {
            return FicheItemFormatterCatalog.IMAGE_SRC;
        }
        return new ImageSrc(base);
    }

    private static String getDefaultFormat(FicheItem ficheItem) {
        if (ficheItem instanceof Item) {
            return ((Item) ficheItem).getValue();
        }
        return "#ERROR: wrong ficheItem = " + ficheItem.getClass().getName();
    }


    public static class Json implements FicheItemFormatter {

        private final JsonParameters jsonParameters;
        private final LangContext customLangContext;

        public Json(JsonParameters jsonParameters, LangContext customLangContext) {
            this.jsonParameters = jsonParameters;
            this.customLangContext = customLangContext;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            StringBuilder buf = new StringBuilder();
            JSONWriter jw = new JSONWriter(buf);
            try {
                jw.object();
                properties(jw, ficheItem, formatSource);
                jw.endObject();
            } catch (IOException ioe) {
                throw new ShouldNotOccurException(ioe);
            }
            return buf.toString();
        }

        private LangContext getLangContext(FormatSource formatSource) {
            if (customLangContext != null) {
                return customLangContext;
            } else {
                return formatSource.getLangContext();
            }
        }

        private void properties(JSONWriter jw, FicheItem ficheItem, FormatSource formatSource) throws IOException {
            PropertyEligibility propertyEligibility = jsonParameters.getPropertyEligibility();
            LangContext langContext = getLangContext(formatSource);
            FichothequeQuestioner fichothequeQuestioner = formatSource.getFichothequeQuestioner();
            MessageLocalisationProvider messageLocalisationProvider = formatSource.getFormatContext().getMessageLocalisationProvider();
            if (ficheItem instanceof Item) {
                FicheItemJson.properties(jw, (Item) ficheItem, propertyEligibility);
            } else if (ficheItem instanceof DateItem) {
                FicheItemJson.properties(jw, (DateItem) ficheItem, propertyEligibility, langContext, getFormatStyle());
            } else if (ficheItem instanceof CountryItem) {
                FicheItemJson.properties(jw, (CountryItem) ficheItem, propertyEligibility, langContext, messageLocalisationProvider);
            } else if (ficheItem instanceof LanguageItem) {
                FicheItemJson.properties(jw, (LanguageItem) ficheItem, propertyEligibility, langContext, messageLocalisationProvider);
            } else if (ficheItem instanceof GeopointItem) {
                FicheItemJson.properties(jw, (GeopointItem) ficheItem, propertyEligibility, langContext, messageLocalisationProvider);
            } else if (ficheItem instanceof LinkItem) {
                FicheItemJson.properties(jw, (LinkItem) ficheItem, propertyEligibility);
            } else if (ficheItem instanceof ImageItem) {
                FicheItemJson.properties(jw, (ImageItem) ficheItem, propertyEligibility);
            } else if (ficheItem instanceof EmailItem) {
                FicheItemJson.properties(jw, (EmailItem) ficheItem, propertyEligibility);
            } else if (ficheItem instanceof NumberItem) {
                FicheItemJson.properties(jw, (NumberItem) ficheItem, propertyEligibility, langContext);
            } else if (ficheItem instanceof AmountItem) {
                FicheItemJson.properties(jw, (AmountItem) ficheItem, propertyEligibility, langContext);
            } else if (ficheItem instanceof ParaItem) {
                FicheItemJson.properties(jw, (ParaItem) ficheItem, propertyEligibility);
            } else if (ficheItem instanceof PersonItem) {
                FicheItemJson.properties(jw, (PersonItem) ficheItem, propertyEligibility, fichothequeQuestioner);
            }
            if (propertyEligibility.includeProperty("formsyntax")) {
                jw.key("formsyntax");
                jw.value(FormSyntax.toString(ficheItem, fichothequeQuestioner, null));
            }
        }

        private FormatStyle getFormatStyle() {
            FormatStyle formatStyle = jsonParameters.getFormatStyle();
            if (formatStyle == null) {
                return FormatStyle.LONG;
            } else {
                return formatStyle;
            }
        }

    }


    public static class CountryLabel implements FicheItemFormatter {

        private final LangParameters langParameters;

        public CountryLabel(LangParameters langParameters) {
            this.langParameters = langParameters;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (!(ficheItem instanceof CountryItem)) {
                return getDefaultFormat(ficheItem);
            }
            CountryItem countryItem = (CountryItem) ficheItem;
            String countryCode = countryItem.getCountry().toString();
            StringBuilder buf = new StringBuilder();
            Lang[] langArray = LangParameters.checkLangArray(langParameters, formatSource);
            for (Lang lang : langArray) {
                MessageLocalisation messageLocalisation = formatSource.getMessageLocalisation(lang);
                String message = messageLocalisation.toString(countryCode);
                if (message != null) {
                    message = StringUtils.getFirstPart(message);
                    if (buf.length() > 0) {
                        buf.append(langParameters.getSeparator());
                    }
                    buf.append(message);
                }
            }
            return buf.toString();
        }

    }


    public static class LanguageLabel implements FicheItemFormatter {

        private final LangParameters langParameters;

        public LanguageLabel(LangParameters langParameters) {
            this.langParameters = langParameters;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (!(ficheItem instanceof LanguageItem)) {
                return getDefaultFormat(ficheItem);
            }
            LanguageItem languageItem = (LanguageItem) ficheItem;
            String langCode = languageItem.getLang().toString();
            StringBuilder buf = new StringBuilder();
            Lang[] langArray = LangParameters.checkLangArray(langParameters, formatSource);
            for (Lang lang : langArray) {
                MessageLocalisation messageLocalisation = formatSource.getMessageLocalisation(lang);
                String message = messageLocalisation.toString(langCode);
                if (message != null) {
                    message = StringUtils.getFirstPart(message);
                    if (buf.length() > 0) {
                        buf.append(langParameters.getSeparator());
                    }
                    buf.append(message);
                }
            }
            return buf.toString();
        }

    }


    public static class GeoLatLabel implements FicheItemFormatter {

        private final LangParameters langParameters;

        public GeoLatLabel(LangParameters langParameters) {
            this.langParameters = langParameters;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (!(ficheItem instanceof GeopointItem)) {
                return getDefaultFormat(ficheItem);
            }
            StringBuilder buf = new StringBuilder();
            DegreSexagesimal sexa = DegreSexagesimal.fromDegreDecimal(((GeopointItem) ficheItem).getLatitude());
            Lang[] langArray = LangParameters.checkLangArray(langParameters, formatSource);
            for (Lang lang : langArray) {
                if (buf.length() > 0) {
                    buf.append(langParameters.getSeparator());
                }
                MessageLocalisation messageLocalisation = formatSource.getMessageLocalisation(lang);
                String code = SpecialCodes.getLatitudeSpecialCode(sexa);
                buf.append(sexa.toString(false, " "));
                String message = messageLocalisation.toString(code);
                if (message != null) {
                    buf.append(message);
                } else {
                    buf.append(code);
                }
            }
            return buf.toString();
        }

    }


    public static class GeoLonLabel implements FicheItemFormatter {

        public final LangParameters langParameters;

        public GeoLonLabel(LangParameters langParameters) {
            this.langParameters = langParameters;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (!(ficheItem instanceof GeopointItem)) {
                return getDefaultFormat(ficheItem);
            }
            StringBuilder buf = new StringBuilder();
            DegreSexagesimal sexa = DegreSexagesimal.fromDegreDecimal(((GeopointItem) ficheItem).getLongitude());
            Lang[] langArray = LangParameters.checkLangArray(langParameters, formatSource);
            for (Lang lang : langArray) {
                if (buf.length() > 0) {
                    buf.append(langParameters.getSeparator());
                }
                MessageLocalisation messageLocalisation = formatSource.getMessageLocalisation(lang);
                String code = SpecialCodes.getLongitudeSpecialCode(sexa);
                buf.append(sexa.toString(false, " "));
                String message = messageLocalisation.toString(code);
                if (message != null) {
                    buf.append(message);
                } else {
                    buf.append(code);
                }
            }
            return buf.toString();
        }

    }


    public static class NumberLabel implements FicheItemFormatter {

        private final LangParameters langParameters;

        public NumberLabel(LangParameters langParameters) {
            this.langParameters = langParameters;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (!(ficheItem instanceof NumberItem)) {
                return getDefaultFormat(ficheItem);
            }
            Decimal decimal = ((NumberItem) ficheItem).getDecimal();
            StringBuilder buf = new StringBuilder();
            Locale[] array = LangParameters.checkLocaleArray(langParameters, formatSource);
            int length = array.length;
            for (int i = 0; i < length; i++) {
                if (i > 0) {
                    buf.append(langParameters.getSeparator());
                }
                appendLocale(buf, decimal, array[i]);
            }
            return buf.toString();
        }

        private void appendLocale(StringBuilder buf, Decimal decimal, Locale locale) {
            DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale);
            buf.append(decimal.toString(symbols));
        }

    }


    public static class AmountLabel implements FicheItemFormatter {

        private final LangParameters langParameters;
        private final boolean forceSubunit;

        public AmountLabel(LangParameters langParameters, boolean forceSubunit) {
            this.langParameters = langParameters;
            this.forceSubunit = forceSubunit;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (!(ficheItem instanceof AmountItem)) {
                return getDefaultFormat(ficheItem);
            }
            StringBuilder buf = new StringBuilder();
            AmountItem amountItem = (AmountItem) ficheItem;
            Decimal decimal = amountItem.getDecimal();
            long moneyLong = amountItem.toMoneyLong();
            ExtendedCurrency currency = amountItem.getCurrency();
            Locale[] array = LangParameters.checkLocaleArray(langParameters, formatSource);
            int length = array.length;
            for (int i = 0; i < length; i++) {
                if (i > 0) {
                    buf.append(langParameters.getSeparator());
                }
                appendLocale(buf, decimal, currency, moneyLong, array[i]);
            }
            return buf.toString();
        }

        private void appendLocale(StringBuilder buf, Decimal decimal, ExtendedCurrency currency, long moneyLong, Locale locale) {
            DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale);
            String strg;
            if (forceSubunit) {
                strg = MoneyUtils.toLitteralString(moneyLong, currency, symbols, false);
            } else {
                strg = MoneyUtils.toLitteralString(decimal, currency, symbols);
            }
            buf.append(strg);
        }

    }


    public static class LinkHref implements FicheItemFormatter {

        private final String base;

        public LinkHref(String base) {
            this.base = base;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (ficheItem instanceof LinkItem) {
                String href = ((LinkItem) ficheItem).getHref();
                if (!StringUtils.isAbsoluteUrlString(href)) {
                    href = base + href;
                }
                return href;
            } else {
                return getDefaultFormat(ficheItem);
            }
        }


    }


    public static class ImageSrc implements FicheItemFormatter {

        private final String base;

        public ImageSrc(String base) {
            this.base = base;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (!(ficheItem instanceof ImageItem)) {
                return getDefaultFormat(ficheItem);
            }
            String src = ((ImageItem) ficheItem).getSrc();
            if (!StringUtils.isAbsoluteUrlString(src)) {
                src = base + src;
            }
            return src;
        }


    }


    public static class DateLabel implements FicheItemFormatter {

        private final LangParameters langParameters;
        private final String truncateType;
        private final FormatStyle formatStyle;

        public DateLabel(LangParameters langParameters, String truncateType, FormatStyle formatStyle) {
            this.langParameters = langParameters;
            this.truncateType = truncateType;
            this.formatStyle = formatStyle;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (!(ficheItem instanceof DateItem)) {
                return getDefaultFormat(ficheItem);
            }
            DateItem dateItem = (DateItem) ficheItem;
            StringBuilder buf = new StringBuilder();
            FuzzyDate date = dateItem.getDate();
            if (!truncateType.equals(FuzzyDate.DAY_TYPE)) {
                date = date.truncate(truncateType);
            }
            Locale[] array = LangParameters.checkLocaleArray(langParameters, formatSource);
            int length = array.length;
            for (int i = 0; i < length; i++) {
                if (i > 0) {
                    buf.append(langParameters.getSeparator());
                }
                appendLocale(buf, date, array[i]);
            }
            return buf.toString();
        }

        private void appendLocale(StringBuilder buf, FuzzyDate date, Locale locale) {
            FuzzyDateFormatter fuzzyDateFormatter = FuzzyDateFormatter.build(formatStyle, locale);
            buf.append(fuzzyDateFormatter.format(date));
        }

    }


    public static class DatePattern implements FicheItemFormatter {

        private final DateTimeFormatter dateTimeFormatter;
        private final LangParameters langParameters;

        public DatePattern(DateTimeFormatter dateTimeFormatter, LangParameters langParameters) {
            this.dateTimeFormatter = dateTimeFormatter;
            this.langParameters = langParameters;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (!(ficheItem instanceof DateItem)) {
                return getDefaultFormat(ficheItem);
            }
            LocalDate date = ((DateItem) ficheItem).toLocalDate();
            if (langParameters == null) {
                return date.format(dateTimeFormatter);
            } else {
                StringBuilder buf = new StringBuilder();
                Locale[] array = LangParameters.checkLocaleArray(langParameters, formatSource);
                int length = array.length;
                for (int i = 0; i < length; i++) {
                    if (i > 0) {
                        buf.append(langParameters.getSeparator());
                    }
                    DateTimeFormatter locFormatter = dateTimeFormatter.withLocale(array[i]);
                    buf.append(date.format(locFormatter));
                }
                return buf.toString();
            }
        }

    }


    public static class ParaTransformation implements FicheItemFormatter {

        private final FicheBlockFormatter ficheBlockFormatter;

        public ParaTransformation(FicheBlockFormatter ficheBlockFormatter) {
            this.ficheBlockFormatter = ficheBlockFormatter;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (ficheItem instanceof ParaItem) {
                SubsetKey corpusKey = null;
                Subset currentSubset = formatSource.getSubsetItemPointeur().getSubset();
                if (currentSubset instanceof Corpus) {
                    corpusKey = currentSubset.getSubsetKey();
                }
                return ficheBlockFormatter.formatFicheBlocks(((ParaItem) ficheItem).toFicheBlocks(), formatSource, corpusKey);
            }
            return getDefaultFormat(ficheItem);
        }

    }

}
