/* 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.formatters;

import java.io.IOException;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
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.utils.SphereUtils;
import net.mapeadores.util.exceptions.ShouldNotOccurException;
import net.mapeadores.util.json.JSONWriter;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.LangContext;
import net.mapeadores.util.localisation.MessageLocalisation;
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.primitives.FuzzyDate;
import net.mapeadores.util.text.DateFormatBundle;
import net.mapeadores.util.text.StringUtils;


/**
 *
 * @author Vincent Calame
 */
final class FicheItemFormatterParts {

    public final static FicheItemFormatter COUNTRY_CODE_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof CountryItem) {
            return ((CountryItem) ficheItem).getCountry().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter LANGUAGE_CODE_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof LanguageItem) {
            return ((LanguageItem) ficheItem).getLang().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter ITEM_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof Item) {
            return ((Item) ficheItem).getValue();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PARA_RAW_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof ParaItem) {
            return ((ParaItem) ficheItem).contentToString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter GEO_LAT_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof GeopointItem) {
            return ((GeopointItem) ficheItem).getLatitude().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter GEO_LON_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof GeopointItem) {
            return ((GeopointItem) ficheItem).getLongitude().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter LINK_HREF_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof LinkItem) {
            return ((LinkItem) ficheItem).getHref();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter LINK_TITLE_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof LinkItem) {
            return ((LinkItem) ficheItem).getTitle();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter LINK_COMMENT_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof LinkItem) {
            return ((LinkItem) ficheItem).getComment();
        }
        return getDefaultFormat(ficheItem);
    };
    public final static FicheItemFormatter IMAGE_SRC_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof ImageItem) {
            return ((ImageItem) ficheItem).getSrc();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter IMAGE_ALT_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof ImageItem) {
            return ((ImageItem) ficheItem).getAlt();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter IMAGE_TITLE_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof ImageItem) {
            return ((ImageItem) ficheItem).getTitle();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter EMAIL_COMPLETE_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof EmailItem) {
            return ((EmailItem) ficheItem).getEmailCore().toCompleteString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter EMAIL_ADDRESS_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof EmailItem) {
            return ((EmailItem) ficheItem).getEmailCore().getAddrSpec();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter EMAIL_NAME_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof EmailItem) {
            return ((EmailItem) ficheItem).getEmailCore().getRealName();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter NUMBER_CODE_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof NumberItem) {
            return ((NumberItem) ficheItem).getDecimal().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter AMOUNT_CODE_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof AmountItem) {
            return ((AmountItem) ficheItem).toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter AMOUNT_CURRENCY_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof AmountItem) {
            return ((AmountItem) ficheItem).getCurrency().getCurrencyCode();
        }
        return getDefaultFormat(ficheItem);
    };
    public final static FicheItemFormatter AMOUNT_DECIMAL_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof AmountItem) {
            return ((AmountItem) ficheItem).getDecimal().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter AMOUNT_MONEYLONG_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof AmountItem) {
            return String.valueOf(((AmountItem) ficheItem).toMoneyLong());
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_CODE_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return ((DateItem) ficheItem).getDate().toString();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_ISO_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return ((DateItem) ficheItem).getDate().toISOString(false);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_ISO_LAST_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return ((DateItem) ficheItem).getDate().toISOString(true);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_YEAR_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return String.valueOf(((DateItem) ficheItem).getDate().getYear());
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_ISOMONTH_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return ((DateItem) ficheItem).getDate().toMonthString(false);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter DATE_ISOMONTH_LAST_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof DateItem) {
            return ((DateItem) ficheItem).getDate().toMonthString(true);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_LOGIN_PART = (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_PART = (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_PART = (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_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterParserUtils.toPersonCore(ficheItem, formatSource);
            return personCore.toStandardStyle();
        }
        return getDefaultFormat(ficheItem);
    };
    public final static FicheItemFormatter PERSON_DIRECTORY_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterParserUtils.toPersonCore(ficheItem, formatSource);
            return personCore.toDirectoryStyle(false);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_UPDIRECTORY_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterParserUtils.toPersonCore(ficheItem, formatSource);
            return personCore.toDirectoryStyle(true);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_BIBLIO_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterParserUtils.toPersonCore(ficheItem, formatSource);
            return personCore.toBiblioStyle(false);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_UPBIBLIO_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterParserUtils.toPersonCore(ficheItem, formatSource);
            return personCore.toBiblioStyle(true);
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_SURNAME_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            return FormatterParserUtils.toPersonCore(ficheItem, formatSource).getSurname();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_UPSURNAME_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            return FormatterParserUtils.toPersonCore(ficheItem, formatSource).getSurname().toUpperCase();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_FORENAME_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            return FormatterParserUtils.toPersonCore(ficheItem, formatSource).getForename();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_NONLATIN_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            return FormatterParserUtils.toPersonCore(ficheItem, formatSource).getNonlatin();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_SURNAMEFIRST_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            PersonCore personCore = FormatterParserUtils.toPersonCore(ficheItem, formatSource);
            return (personCore.isSurnameFirst()) ? "1" : "0";
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter PERSON_ORGANISM_PART = (ficheItem, formatSource) -> {
        if (ficheItem instanceof PersonItem) {
            return ((PersonItem) ficheItem).getOrganism();
        } else {
            return getDefaultFormat(ficheItem);
        }
    };
    public final static FicheItemFormatter FORMSYNTAX_FORMATTER = new FormSyntaxPart();

    private FicheItemFormatterParts() {
    }

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

    public static FicheItemFormatter newImageSrcPart(String base) {
        if (base == null) {
            return FicheItemFormatterParts.IMAGE_SRC_PART;
        }
        return new ImageSrcPart(base);
    }

    public static FicheItemFormatter newCountryLabelPart(LangParameters langParameters) {
        return new CountryLabelPart(langParameters);
    }

    public static FicheItemFormatter newLanguageLabelPart(LangParameters langParameters) {
        return new LanguageLabelPart(langParameters);
    }

    public static FicheItemFormatter newGeoLatLabelPart(LangParameters langParameters) {
        return new GeoLatLabelPart(langParameters);
    }

    public static FicheItemFormatter newGeoLonLabelPart(LangParameters langParameters) {
        return new GeoLonLabelPart(langParameters);
    }

    public static FicheItemFormatter newNumberLabelPart(LangParameters langParameters) {
        return new NumberLabelPart(langParameters);
    }

    public static FicheItemFormatter newAmountLabelPart(LangParameters langParameters) {
        return new AmountLabelPart(langParameters);
    }

    public static FicheItemFormatter newDateLabelPart(LangParameters langParameters, short truncateType) {
        return new DateLabelPart(langParameters, truncateType);
    }

    public static FicheItemFormatter newJsonPart(JsonParameters jsonParameters, LangParameters langParameters) {
        return new JsonPart(jsonParameters, langParameters.getCustomLangContext());
    }

    public static FicheItemFormatter newParaTransformationPart(FicheBlockFormatter ficheBlockFormatter) {
        return new ParaTransformationPart(ficheBlockFormatter);
    }

    public static FicheItemFormatter newDatePatternPart(DateTimeFormatter dateTimeFormatter) {
        return new DatePatternPart(dateTimeFormatter);
    }

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


    public static class JsonPart implements FicheItemFormatter {

        private final JsonParameters jsonParameters;
        private final LangContext customLangContext;

        private JsonPart(JsonParameters jsonParameters, LangContext customLangContext) {
            this.jsonParameters = jsonParameters;
            this.customLangContext = customLangContext;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            StringBuilder buf = new StringBuilder();
            JSONWriter jsonWriter = new JSONWriter(buf);
            try {
                LangContext langContext;
                if (customLangContext != null) {
                    langContext = customLangContext;
                } else {
                    langContext = formatSource.getLangContext();
                }
                FicheItemJson.object(jsonWriter, ficheItem, jsonParameters, langContext, formatSource.getFichothequeQuestioner(), formatSource.getFormatContext().getMessageLocalisationProvider());
            } catch (IOException ioe) {
                throw new ShouldNotOccurException(ioe);
            }
            return buf.toString();
        }

    }


    private static class CountryLabelPart implements FicheItemFormatter {

        private final LangParameters langParameters;

        private CountryLabelPart(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();
        }

    }


    private static class LanguageLabelPart implements FicheItemFormatter {

        private final LangParameters langParameters;

        private LanguageLabelPart(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();
        }

    }


    private static class GeoLatLabelPart implements FicheItemFormatter {

        private final LangParameters langParameters;

        private GeoLatLabelPart(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();
        }

    }


    private static class GeoLonLabelPart implements FicheItemFormatter {

        private final LangParameters langParameters;

        private GeoLonLabelPart(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();
        }

    }


    private static class NumberLabelPart implements FicheItemFormatter {

        private final LangParameters langParameters;

        private NumberLabelPart(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));
        }

    }


    private static class AmountLabelPart implements FicheItemFormatter {

        private final LangParameters langParameters;

        private AmountLabelPart(LangParameters langParameters) {
            this.langParameters = langParameters;
        }

        @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();
            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, array[i]);
            }
            return buf.toString();
        }

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

    }


    private static class LinkHrefPart implements FicheItemFormatter {

        private final String base;

        private LinkHrefPart(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);
            }
        }


    }


    private static class ImageSrcPart implements FicheItemFormatter {

        private final String base;

        private ImageSrcPart(String base) {
            this.base = base;
        }

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


    }


    private static class DateLabelPart implements FicheItemFormatter {

        private final LangParameters langParameters;
        private final short truncateType;

        private DateLabelPart(LangParameters langParameters, short truncateType) {
            this.langParameters = langParameters;
            this.truncateType = truncateType;
        }

        @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 != 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) {
            DateFormatBundle dateFormatBundle = DateFormatBundle.getDateFormatBundle(locale);
            buf.append(date.getDateLitteral(dateFormatBundle));
        }

    }


    private static class DatePatternPart implements FicheItemFormatter {

        private final DateTimeFormatter dateTimeFormatter;

        private DatePatternPart(DateTimeFormatter dateTimeFormatter) {
            this.dateTimeFormatter = dateTimeFormatter;
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            if (!(ficheItem instanceof DateItem)) {
                return getDefaultFormat(ficheItem);
            }
            DateItem dateItem = (DateItem) ficheItem;
            return dateItem.toLocalDate(false).format(dateTimeFormatter);
        }

    }


    private static class FormSyntaxPart implements FicheItemFormatter {

        private FormSyntaxPart() {
        }

        @Override
        public String formatFicheItem(FicheItem ficheItem, FormatSource formatSource) {
            return FormSyntax.toString(ficheItem, formatSource.getFichothequeQuestioner(), null);
        }

    }


    private static class ParaTransformationPart implements FicheItemFormatter {

        private final FicheBlockFormatter ficheBlockFormatter;

        private ParaTransformationPart(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);
        }

    }

}
