/* UtilLib - Copyright (c) 2007-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.mapeadores.util.format;

import java.util.HashMap;
import java.util.Map;
import net.mapeadores.util.primitives.PrimUtils;


/**
 *
 * @author Vincent Calame
 */
public abstract class FormatDefBuilder {

    private boolean formatPatternListInit = false;
    private final Map<Integer, InternalInnerSeparator> innerSeparatorMap = new HashMap<Integer, InternalInnerSeparator>();
    private final Map<Long, InternalSourceSeparator> sourceSeparatorMap = new HashMap<Long, InternalSourceSeparator>();

    public FormatDefBuilder() {
    }

    public FormatDefBuilder addFormatPattern(String fP) {
        if (fP != null) {
            fP = fP.trim();
            if (fP.length() == 0) {
                fP = null;
            }
        }
        if ((fP == null) && (!formatPatternListInit)) {
            return this;
        }
        formatPatternListInit = true;
        addCleanedFormatPattern(fP);
        return this;
    }

    public FormatDefBuilder setCastType(String castType) {
        put(FormatConstants.CAST_PARAMKEY, castType);
        return this;
    }

    public FormatDefBuilder setFixedChar(char carac) {
        put(FormatConstants.FIXEDCHAR_PARAMKEY, carac);
        return this;
    }

    public FormatDefBuilder putBooleanValue(String key, boolean value) {
        put(key, value);
        return this;
    }

    public FormatDefBuilder putStringValue(String key, String value) {
        if (value == null) {
            remove(key);
        } else {
            put(key, value);
        }
        return this;
    }

    public FormatDefBuilder putIntValue(String key, int value) {
        if (value < 0) {
            value = -1;
        }
        put(key, value);
        return this;
    }

    public FormatDefBuilder setCalcul(Calcul calcul) {
        if (calcul == null) {
            remove(FormatConstants.CALCUL_PARAMKEY);
        } else {
            put(FormatConstants.CALCUL_PARAMKEY, calcul);
        }
        return this;
    }

    public FormatDefBuilder setSum(boolean withSum, String sumCastType) {
        if (withSum) {
            put(FormatConstants.SUM_PARAMKEY, sumCastType);
        } else {
            remove(FormatConstants.SUM_PARAMKEY);
        }
        return this;
    }

    public FormatDefBuilder setFormula(boolean isFormula, String formulaCastType) {
        if (isFormula) {
            put(FormatConstants.FORMULA_PARAMKEY, formulaCastType);
        } else {
            remove(FormatConstants.FORMULA_PARAMKEY);
        }
        return this;
    }

    public FormatDefBuilder setInternalSeparator(int sourceIndex, String separator) {
        if (separator == null) {
            throw new IllegalArgumentException("separator is null");
        }
        InternalInnerSeparator innerSeparator = innerSeparatorMap.get(sourceIndex);
        if (innerSeparator == null) {
            innerSeparator = new InternalInnerSeparator(sourceIndex, separator);
            innerSeparatorMap.put(sourceIndex, innerSeparator);
            addInnerSeparator(innerSeparator);
        } else {
            innerSeparator.setSeparator(separator);
        }
        return this;
    }

    public FormatDefBuilder setSourceSeparator(int sourceIndex1, int sourceIndex2, String separator) {
        if (separator == null) {
            throw new IllegalArgumentException("separator is null");
        }
        if (sourceIndex1 == sourceIndex2) {
            throw new IllegalArgumentException("sourceIndex1 == sourceIndex2");
        }
        if (sourceIndex1 > sourceIndex2) {
            int tmp = sourceIndex1;
            sourceIndex1 = sourceIndex2;
            sourceIndex2 = tmp;
        }
        long l = PrimUtils.toLong(sourceIndex1, sourceIndex2);
        InternalSourceSeparator sourceSeparator = sourceSeparatorMap.get(l);
        if (sourceSeparator == null) {
            sourceSeparator = new InternalSourceSeparator(sourceIndex1, sourceIndex2, separator);
            sourceSeparatorMap.put(l, sourceSeparator);
            addSourceSeparator(sourceSeparator);
        } else {
            sourceSeparator.setSeparator(separator);
        }
        return this;
    }

    protected abstract void put(String paramName, Object paramValue);

    protected abstract void remove(String paramName);

    protected abstract void addInnerSeparator(FormatDef.InnerSeparator innerSeparator);

    protected abstract void addSourceSeparator(FormatDef.SourceSeparator sourceSeparator);

    protected abstract void addCleanedFormatPattern(String formatPattern);


    private static class InternalInnerSeparator implements FormatDef.InnerSeparator {

        private final int sourceIndex;
        private String separator;

        private InternalInnerSeparator(int sourceIndex, String separator) {
            this.sourceIndex = sourceIndex;
            this.separator = separator;
        }

        @Override
        public int getSourceIndex() {
            return sourceIndex;
        }

        @Override
        public String getSeparator() {
            return separator;
        }

        private void setSeparator(String separator) {
            this.separator = separator;
        }

    }


    private static class InternalSourceSeparator implements FormatDef.SourceSeparator {

        private final int sourceIndex1;
        private final int sourceIndex2;
        private String separator;

        private InternalSourceSeparator(int sourceIndex1, int sourceIndex2, String separator) {
            this.sourceIndex1 = sourceIndex1;
            this.sourceIndex2 = sourceIndex2;
            this.separator = separator;
        }

        @Override
        public int getSourceIndex1() {
            return sourceIndex1;
        }

        @Override
        public int getSourceIndex2() {
            return sourceIndex2;
        }

        @Override
        public String getSeparator() {
            return separator;
        }

        private void setSeparator(String separator) {
            this.separator = separator;
        }

    }

}
