/* FichothequeLib_Tools - Copyright (c) 2022-2024 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.duplication;

import java.text.ParseException;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import net.fichotheque.Subset;
import net.fichotheque.SubsetItem;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.eligibility.SubsetEligibility;
import static net.fichotheque.utils.EligibilityUtils.ALL_SUBSETITEM_PREDICATE;
import static net.fichotheque.utils.EligibilityUtils.NONE_SUBSETITEM_PREDICATE;
import net.mapeadores.util.attr.Attribute;


/**
 *
 * @author Vincent Calame
 */
public class DuplicationFilterParser {

    private final ExcludePredicate excludePredicate = new ExcludePredicate();
    private final ExcludeSubsetEligibility excludeSubsetEligibility = new ExcludeSubsetEligibility();

    private DuplicationFilterParser() {

    }

    private void parseToken(String token) {
        if (token.endsWith("_*")) {
            String wildToken = token.substring(0, token.length() - 2);
            try {
                short category = SubsetKey.categoryToShort(wildToken);
                excludeSubsetEligibility.add(category);
            } catch (IllegalArgumentException iae) {

            }
        } else {
            try {
                FieldKey fieldKey = FieldKey.parse(token);
                excludePredicate.add(fieldKey);
            } catch (ParseException pe1) {
                try {
                    SubsetKey subsetKey = SubsetKey.parse(token);
                    excludeSubsetEligibility.add(subsetKey);
                } catch (ParseException pe2) {

                }
            }
        }
    }

    private DuplicationFilter toDuplicationFilter() {
        return new DuplicationFilter(excludeSubsetEligibility, excludePredicate);
    }

    public static DuplicationFilter parseExclude(String[] tokens) {
        DuplicationFilterParser duplicationFilterParser = new DuplicationFilterParser();
        for (String token : tokens) {
            duplicationFilterParser.parseToken(token);
        }
        return duplicationFilterParser.toDuplicationFilter();
    }

    public static DuplicationFilter parseExclude(Attribute attribute) {
        DuplicationFilterParser duplicationFilterParser = new DuplicationFilterParser();
        for (String value : attribute) {
            duplicationFilterParser.parseToken(value);
        }
        return duplicationFilterParser.toDuplicationFilter();
    }


    private static class ExcludePredicate implements Predicate<FieldKey> {

        private final Set<FieldKey> set = new HashSet<FieldKey>();

        private ExcludePredicate() {

        }

        @Override
        public boolean test(FieldKey fieldKey) {
            return !set.contains(fieldKey);
        }

        private void add(FieldKey fieldKey) {
            set.add(fieldKey);
        }

    }


    private static class ExcludeSubsetEligibility implements SubsetEligibility {

        private final Set<Short> categorySet = new HashSet<Short>();
        private final Set<SubsetKey> subsetSet = new HashSet<SubsetKey>();

        private ExcludeSubsetEligibility() {

        }

        @Override
        public boolean accept(SubsetKey subsetKey) {
            if (categorySet.contains(subsetKey.getCategory())) {
                return false;
            }
            if (subsetSet.contains(subsetKey)) {
                return false;
            }
            return true;
        }

        @Override
        public Predicate<SubsetItem> getPredicate(Subset subset) {
            if (accept(subset.getSubsetKey())) {
                return ALL_SUBSETITEM_PREDICATE;
            } else {
                return NONE_SUBSETITEM_PREDICATE;
            }
        }

        private void add(SubsetKey subsetKey) {
            subsetSet.add(subsetKey);
        }

        private void add(short category) {
            categorySet.add(category);
        }


    }

}
