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

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.RandomAccess;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.format.FichothequeFormatConstants;
import net.fichotheque.format.FichothequeFormatDef;
import net.fichotheque.format.FormatSourceKey;
import net.mapeadores.util.format.FormatDef;
import net.mapeadores.util.format.FormatDefBuilder;


/**
 *
 * @author Vincent Calame
 */
public class FichothequeFormatDefBuilder extends FormatDefBuilder {

    private final Map<String, Object> paramMap = new HashMap<String, Object>();
    private final List<FormatDef.InnerSeparator> innerSeparatorList = new ArrayList<FormatDef.InnerSeparator>();
    private final List<FormatDef.Pattern> patternList = new ArrayList<FormatDef.Pattern>();
    private final List<FormatDef.SourceSeparator> sourceSeparatorList = new ArrayList<FormatDef.SourceSeparator>();
    private final List<FormatSourceKey> formatSourceKeyList = new ArrayList<FormatSourceKey>();

    public FichothequeFormatDefBuilder() {
    }


    public FichothequeFormatDefBuilder addSource(FormatSourceKey formatSourceKey) {
        formatSourceKeyList.add(formatSourceKey);
        return this;
    }

    public FichothequeFormatDefBuilder setDefaultPropKey(FieldKey defaultPropKey) {
        if ((defaultPropKey != null) && (!defaultPropKey.isProp())) {
            throw new IllegalArgumentException("defaultPropKey is not a Prop field : " + defaultPropKey);
        }
        if (defaultPropKey == null) {
            remove(FichothequeFormatConstants.DEFAULTPROP_PARAMKEY);
        } else {
            put(FichothequeFormatConstants.DEFAULTPROP_PARAMKEY, defaultPropKey);
        }
        return this;
    }

    @Override
    protected void put(String paramName, Object paramValue) {
        paramMap.put(paramName, paramValue);
    }

    @Override
    protected void remove(String paramName) {
        paramMap.remove(paramName);
    }

    @Override
    protected void addInnerSeparator(FormatDef.InnerSeparator innerSeparator) {
        innerSeparatorList.add(innerSeparator);
    }

    @Override
    protected void addSourceSeparator(FormatDef.SourceSeparator sourceSeparator) {
        sourceSeparatorList.add(sourceSeparator);
    }

    @Override
    protected void addCleanedFormatPattern(String formatPattern) {
        patternList.add(new InternalPattern(formatPattern));
    }

    public FichothequeFormatDef toFichothequeFormatDef() {
        if (formatSourceKeyList.isEmpty()) {
            throw new IllegalStateException("No FormatSourceKey");
        }
        Map<String, Object> finalParamMap = new HashMap<String, Object>(paramMap);
        List<FormatDef.Pattern> finalPatternList = new PatternList(patternList.toArray(new FormatDef.Pattern[patternList.size()]));
        List<FormatDef.InnerSeparator> finalInnerSeparatorList = new InnerSeparatorList(innerSeparatorList.toArray(new FormatDef.InnerSeparator[innerSeparatorList.size()]));
        List<FormatDef.SourceSeparator> finalSourceSeparatorList = new SourceSeparatorList(sourceSeparatorList.toArray(new FormatDef.SourceSeparator[sourceSeparatorList.size()]));
        List<FormatSourceKey> finalFormatSourceKeyList = new FormatSourceKeyList(formatSourceKeyList.toArray(new FormatSourceKey[formatSourceKeyList.size()]));
        return new InternalFichothequeFormatDef(finalParamMap, finalPatternList, finalInnerSeparatorList, finalSourceSeparatorList, finalFormatSourceKeyList);
    }

    public static FichothequeFormatDefBuilder init() {
        return new FichothequeFormatDefBuilder();
    }


    private static class InternalFichothequeFormatDef implements FichothequeFormatDef {

        private final Map<String, Object> paramMap;
        private final List<FormatDef.Pattern> patternList;
        private final List<FormatDef.InnerSeparator> innerSeparatorList;
        private final List<FormatDef.SourceSeparator> sourceSeparatorList;
        private final List<FormatSourceKey> formatSourceKeyList;

        private InternalFichothequeFormatDef(Map<String, Object> paramMap, List<FormatDef.Pattern> patternList, List<FormatDef.InnerSeparator> innerSeparatorList, List<FormatDef.SourceSeparator> sourceSeparatorList, List<FormatSourceKey> formatSourceKeyList) {
            this.paramMap = paramMap;
            this.patternList = patternList;
            this.innerSeparatorList = innerSeparatorList;
            this.sourceSeparatorList = sourceSeparatorList;
            this.formatSourceKeyList = formatSourceKeyList;
        }

        @Override
        public Object getParameterValue(String paramName) {
            return paramMap.get(paramName);
        }

        @Override
        public List<Pattern> getPatternList() {
            return patternList;
        }

        @Override
        public List<FormatDef.InnerSeparator> getInnerSeparatorList() {
            return innerSeparatorList;
        }

        @Override
        public List<SourceSeparator> getSourceSeparatorList() {
            return sourceSeparatorList;
        }

        @Override
        public List<FormatSourceKey> getFormatSourceKeyList() {
            return formatSourceKeyList;
        }

    }


    private static class InnerSeparatorList extends AbstractList<FormatDef.InnerSeparator> implements RandomAccess {

        private final FormatDef.InnerSeparator[] array;

        private InnerSeparatorList(FormatDef.InnerSeparator[] array) {
            this.array = array;
        }

        @Override
        public int size() {
            return array.length;
        }

        @Override
        public FormatDef.InnerSeparator get(int index) {
            return array[index];
        }

    }


    private static class SourceSeparatorList extends AbstractList<FormatDef.SourceSeparator> implements RandomAccess {

        private final FormatDef.SourceSeparator[] array;

        private SourceSeparatorList(FormatDef.SourceSeparator[] array) {
            this.array = array;
        }

        @Override
        public int size() {
            return array.length;
        }

        @Override
        public FormatDef.SourceSeparator get(int index) {
            return array[index];
        }

    }


    private static class FormatSourceKeyList extends AbstractList<FormatSourceKey> implements RandomAccess {

        private final FormatSourceKey[] array;

        private FormatSourceKeyList(FormatSourceKey[] array) {
            this.array = array;
        }

        @Override
        public int size() {
            return array.length;
        }

        @Override
        public FormatSourceKey get(int index) {
            return array[index];
        }

    }


    private static class PatternList extends AbstractList<FormatDef.Pattern> implements RandomAccess {

        private final FormatDef.Pattern[] array;

        private PatternList(FormatDef.Pattern[] array) {
            this.array = array;
        }

        @Override
        public int size() {
            return array.length;
        }

        @Override
        public FormatDef.Pattern get(int index) {
            return array[index];
        }

    }


    private static class InternalPattern implements FormatDef.Pattern {

        private final String patternString;

        private InternalPattern(String patternString) {
            this.patternString = patternString;
        }

        @Override
        public boolean isDefault() {
            return (patternString == null);
        }

        @Override
        public String getPattern() {
            return patternString;
        }


    }

}
