/* FichothequeLib_API - Copyright (c) 2011-2023 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.utils;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import net.fichotheque.FichothequeConstants;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.extraction.FilterParameters;
import net.fichotheque.extraction.def.AddendaExtractDef;
import net.fichotheque.extraction.def.AlbumExtractDef;
import net.fichotheque.extraction.def.CorpusExtractDef;
import net.fichotheque.extraction.def.FicheFilter;
import net.fichotheque.extraction.def.MotcleFilter;
import net.fichotheque.extraction.def.SubsetExtractDef;
import net.fichotheque.extraction.def.TagNameInfo;
import net.fichotheque.extraction.def.ThesaurusExtractDef;
import net.fichotheque.extraction.filterunit.AddendaExtractFilterUnit;
import net.fichotheque.extraction.filterunit.AlbumExtractFilterUnit;
import net.fichotheque.extraction.filterunit.ChronoFilterUnit;
import net.fichotheque.extraction.filterunit.CorpusExtractFilterUnit;
import net.fichotheque.extraction.filterunit.DataFilterUnit;
import net.fichotheque.extraction.filterunit.DefaultIncludeUnit;
import net.fichotheque.extraction.filterunit.FicheParentageFilterUnit;
import net.fichotheque.extraction.filterunit.FieldKeyFilterUnit;
import net.fichotheque.extraction.filterunit.FieldNamePrefixFilterUnit;
import net.fichotheque.extraction.filterunit.FilterUnit;
import net.fichotheque.extraction.filterunit.LotFilterUnit;
import net.fichotheque.extraction.filterunit.MasterMotcleFilterUnit;
import net.fichotheque.extraction.filterunit.PhraseFilterUnit;
import net.fichotheque.extraction.filterunit.ThesaurusExtractFilterUnit;
import net.fichotheque.include.ExtendedIncludeKey;
import net.mapeadores.util.exceptions.SwitchException;
import net.mapeadores.util.text.StringUtils;
import net.fichotheque.extraction.filterunit.HeadFilterUnit;
import net.fichotheque.extraction.filterunit.BodyFilterUnit;


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

    public final static HeadFilterUnit HEAD_FILTERUNIT = new InternalHeadFilterUnit();
    public final static BodyFilterUnit BODY_FILTERUNIT = new InternalBodyFilterUnit();
    public final static ChronoFilterUnit CHRONO_FILTERUNIT = new InternalChronoFilterUnit();
    public final static PhraseFilterUnit FICHEPHRASE_FILTERUNIT = new InternalPhraseFilterUnit(FichothequeConstants.FICHE_PHRASE);


    private FilterUnits() {
    }

    public static FieldKeyFilterUnit fieldKey(FieldKey fieldKey, FilterParameters filterParameters) {
        if (fieldKey == null) {
            throw new NullPointerException("fieldKey is null");
        }
        if (filterParameters == null) {
            throw new NullPointerException("filterParameters is null");
        }
        return new InternalFieldKeyFilterUnit(fieldKey, filterParameters);
    }

    public static LotFilterUnit lot(TagNameInfo tagNameInfo, List<FilterUnit> filterUnitList) {
        return new InternalLotFilterUnit(tagNameInfo, ExtractionUtils.toImmutableList(filterUnitList));
    }

    public static FieldNamePrefixFilterUnit fieldNamePrefix(short category, String prefix, FilterParameters filterParameters) {
        return new InternalFieldNamePrefixFilterUnit(category, prefix, filterParameters);
    }

    public static FilterUnit subsetExtract(SubsetExtractDef subsetExtractDef, FilterParameters filterParameters) {
        if (subsetExtractDef == null) {
            throw new NullPointerException("subsetExtractDef is null");
        }
        if (filterParameters == null) {
            throw new NullPointerException("filterParameters is null");
        }
        switch (subsetExtractDef.getCategory()) {
            case SubsetKey.CATEGORY_CORPUS:
                return corpusExtract((CorpusExtractDef) subsetExtractDef, filterParameters);
            case SubsetKey.CATEGORY_THESAURUS:
                return thesaurusExtract((ThesaurusExtractDef) subsetExtractDef, filterParameters);
            case SubsetKey.CATEGORY_ALBUM:
                return albumExtract((AlbumExtractDef) subsetExtractDef, filterParameters);
            case SubsetKey.CATEGORY_ADDENDA:
                return addendaExtract((AddendaExtractDef) subsetExtractDef, filterParameters);
            default:
                throw new SwitchException("unknown category: " + subsetExtractDef.getCategory());
        }
    }

    public static CorpusExtractFilterUnit corpusExtract(CorpusExtractDef corpusExtractDef, FilterParameters filterParameters) {
        if (filterParameters == null) {
            throw new NullPointerException("filterParameters is null");
        }
        return new InternalCorpusExtractFilterUnit(corpusExtractDef, filterParameters);
    }

    public static ThesaurusExtractFilterUnit thesaurusExtract(ThesaurusExtractDef thesaurusExtractDef, FilterParameters filterParameters) {
        if (filterParameters == null) {
            throw new NullPointerException("filterParameters is null");
        }
        return new InternalThesaurusExtractFilterUnit(thesaurusExtractDef, filterParameters);
    }

    public static AlbumExtractFilterUnit albumExtract(AlbumExtractDef albumExtractDef, FilterParameters filterParameters) {
        if (filterParameters == null) {
            throw new NullPointerException("filterParameters is null");
        }
        return new InternalAlbumExtractFilterUnit(albumExtractDef, filterParameters);
    }

    public static AddendaExtractFilterUnit addendaExtract(AddendaExtractDef addendaExtractDef, FilterParameters filterParameters) {
        if (filterParameters == null) {
            throw new NullPointerException("filterParameters is null");
        }
        return new InternalAddendaExtractFilterUnit(addendaExtractDef, filterParameters);
    }

    public static FicheParentageFilterUnit ficheParentage(FicheFilter ficheFilter, FilterParameters filterParameters, Collection<SubsetKey> subsetKeys) {
        if (ficheFilter == null) {
            throw new NullPointerException("ficheFilter is null");
        }
        if (filterParameters == null) {
            throw new NullPointerException("filterParameters is null");
        }
        return new InternalFicheParentageFilterUnit(ficheFilter, filterParameters, FichothequeUtils.toList(subsetKeys));
    }

    public static MasterMotcleFilterUnit masterMotcle(MotcleFilter motcleFilter, FilterParameters filterParameters) {
        if (motcleFilter == null) {
            throw new NullPointerException("masterMotcleFilter is null");
        }
        if (filterParameters == null) {
            throw new NullPointerException("filterParameters is null");
        }
        return new InternalMasterMotcleFilterUnit(motcleFilter, filterParameters);
    }

    public static PhraseFilterUnit phrase(String phraseName) {
        switch (phraseName) {
            case FichothequeConstants.FICHE_PHRASE:
                return FICHEPHRASE_FILTERUNIT;
            default:
                return new InternalPhraseFilterUnit(phraseName);
        }
    }

    public static DataFilterUnit data(String name, FilterParameters filterParameters) {
        if (name == null) {
            throw new NullPointerException("name is null");
        }
        if (filterParameters == null) {
            throw new NullPointerException("filterParameters is null");
        }
        return new InternalDataFilterUnit(name, filterParameters);
    }

    public static CorpusExtractFilterUnit defaultCorpusExtract(CorpusExtractDef corpusExtractDef, ExtendedIncludeKey includeKey) {
        return new DefaultCorpusExtractFilterUnit(corpusExtractDef, includeKey);
    }

    public static ThesaurusExtractFilterUnit defaultThesaurusExtract(ThesaurusExtractDef thesaurusExtractDef, ExtendedIncludeKey includeKey) {
        return new DefaultThesaurusExtractFilterUnit(thesaurusExtractDef, includeKey);
    }

    public static AlbumExtractFilterUnit defaultAlbumExtract(AlbumExtractDef albumExtractDef, ExtendedIncludeKey includeKey) {
        return new DefaultAlbumExtractFilterUnit(albumExtractDef, includeKey);
    }

    public static AddendaExtractFilterUnit defaultAddendaExtract(AddendaExtractDef addendaExtractDef, ExtendedIncludeKey includeKey) {
        return new DefaultAddendaExtractFilterUnit(addendaExtractDef, includeKey);
    }


    private static abstract class InternalFilterUnit implements FilterUnit {

        private final FilterParameters filterParameters;

        private InternalFilterUnit(FilterParameters filterParameters) {
            this.filterParameters = filterParameters;
        }

        @Override
        public Set<String> getParameterNameSet() {
            return filterParameters.getParameterNameSet();
        }

        @Override
        public List<String> getParameter(String name) {
            return filterParameters.getParameter(name);
        }

    }


    private static abstract class NoParameterFilterUnit implements FilterUnit {


        private NoParameterFilterUnit() {

        }

        @Override
        public Set<String> getParameterNameSet() {
            return StringUtils.EMPTY_STRINGSET;
        }

        @Override
        public List<String> getParameter(String name) {
            return StringUtils.EMPTY_STRINGLIST;
        }


    }


    private static class InternalHeadFilterUnit extends NoParameterFilterUnit implements HeadFilterUnit {


        private InternalHeadFilterUnit() {
        }

    }


    private static class InternalBodyFilterUnit extends NoParameterFilterUnit implements BodyFilterUnit {

        private InternalBodyFilterUnit() {
        }

    }


    private static class InternalChronoFilterUnit extends NoParameterFilterUnit implements ChronoFilterUnit {

        private InternalChronoFilterUnit() {
        }

    }


    private static class InternalPhraseFilterUnit extends NoParameterFilterUnit implements PhraseFilterUnit {

        private final String phraseName;

        private InternalPhraseFilterUnit(String phraseName) {
            this.phraseName = phraseName;
        }

        @Override
        public String getName() {
            return phraseName;
        }

    }


    private static class InternalFieldKeyFilterUnit extends InternalFilterUnit implements FieldKeyFilterUnit {

        private final FieldKey fieldKey;

        private InternalFieldKeyFilterUnit(FieldKey fieldKey, FilterParameters filterParameters) {
            super(filterParameters);
            this.fieldKey = fieldKey;
        }

        @Override
        public FieldKey getFieldKey() {
            return fieldKey;
        }

    }


    private static class InternalLotFilterUnit extends NoParameterFilterUnit implements LotFilterUnit {

        private final TagNameInfo tagNameInfo;
        private final List<FilterUnit> filterUnitList;

        private InternalLotFilterUnit(TagNameInfo tagNameInfo, List<FilterUnit> filterUnitList) {
            this.tagNameInfo = tagNameInfo;
            this.filterUnitList = filterUnitList;
        }

        @Override
        public TagNameInfo getTagNameInfo() {
            return tagNameInfo;
        }

        @Override
        public List<FilterUnit> getFilterUnitList() {
            return filterUnitList;
        }

    }


    private static class InternalFieldNamePrefixFilterUnit extends InternalFilterUnit implements FieldNamePrefixFilterUnit {

        private final short category;
        private final String prefix;

        private InternalFieldNamePrefixFilterUnit(short category, String prefix, FilterParameters filterParameters) {
            super(filterParameters);
            this.category = category;
            this.prefix = prefix;
        }

        @Override
        public short getCategory() {
            return category;
        }

        @Override
        public String getPrefix() {
            return prefix;

        }

    }


    private static class InternalCorpusExtractFilterUnit extends InternalFilterUnit implements CorpusExtractFilterUnit {

        private final CorpusExtractDef corpusExtractDef;

        private InternalCorpusExtractFilterUnit(CorpusExtractDef corpusExtractDef, FilterParameters filterParameters) {
            super(filterParameters);
            this.corpusExtractDef = corpusExtractDef;
        }

        @Override
        public CorpusExtractDef getCorpusExtractDef() {
            return corpusExtractDef;
        }

    }


    private static class InternalThesaurusExtractFilterUnit extends InternalFilterUnit implements ThesaurusExtractFilterUnit {

        private final ThesaurusExtractDef thesaurusExtractDef;

        private InternalThesaurusExtractFilterUnit(ThesaurusExtractDef thesaurusExtractDef, FilterParameters filterParameters) {
            super(filterParameters);
            this.thesaurusExtractDef = thesaurusExtractDef;
        }

        @Override
        public ThesaurusExtractDef getThesaurusExtractDef() {
            return thesaurusExtractDef;
        }

    }


    private static class InternalAlbumExtractFilterUnit extends InternalFilterUnit implements AlbumExtractFilterUnit {

        private final AlbumExtractDef albumExtractDef;

        private InternalAlbumExtractFilterUnit(AlbumExtractDef albumExtractDef, FilterParameters filterParameters) {
            super(filterParameters);
            this.albumExtractDef = albumExtractDef;
        }

        @Override
        public AlbumExtractDef getAlbumExtractDef() {
            return albumExtractDef;
        }

    }


    private static class InternalAddendaExtractFilterUnit extends InternalFilterUnit implements AddendaExtractFilterUnit {

        private final AddendaExtractDef addendaExtractDef;

        private InternalAddendaExtractFilterUnit(AddendaExtractDef addendaExtractDef, FilterParameters filterParameters) {
            super(filterParameters);
            this.addendaExtractDef = addendaExtractDef;
        }

        @Override
        public AddendaExtractDef getAddendaExtractDef() {
            return addendaExtractDef;
        }

    }


    private static class InternalFicheParentageFilterUnit extends InternalFilterUnit implements FicheParentageFilterUnit {

        private final FicheFilter ficheFilter;
        private final List<SubsetKey> subsetKeyList;

        private InternalFicheParentageFilterUnit(FicheFilter ficheFilter, FilterParameters filterParameters, List<SubsetKey> subsetKeyList) {
            super(filterParameters);
            this.ficheFilter = ficheFilter;
            this.subsetKeyList = subsetKeyList;
        }

        @Override
        public FicheFilter getFicheFilter() {
            return ficheFilter;
        }

        @Override
        public List<SubsetKey> getSubsetKeyList() {
            return subsetKeyList;
        }

    }


    private static class InternalMasterMotcleFilterUnit extends InternalFilterUnit implements MasterMotcleFilterUnit {

        private final MotcleFilter motcleFilter;

        private InternalMasterMotcleFilterUnit(MotcleFilter motcleFilter, FilterParameters filterParameters) {
            super(filterParameters);
            this.motcleFilter = motcleFilter;
        }

        @Override
        public MotcleFilter getMotcleFilter() {
            return motcleFilter;
        }

    }


    private static class InternalDataFilterUnit extends InternalFilterUnit implements DataFilterUnit {

        private final String name;

        private InternalDataFilterUnit(String name, FilterParameters filterParameters) {
            super(filterParameters);
            this.name = name;
        }

        @Override
        public String getName() {
            return name;
        }

    }


    private static abstract class DefaultIncludeFilterUnit implements FilterUnit, DefaultIncludeUnit {

        private final ExtendedIncludeKey includeKey;

        private DefaultIncludeFilterUnit(ExtendedIncludeKey includeKey) {
            this.includeKey = includeKey;
        }

        @Override
        public Set<String> getParameterNameSet() {
            return StringUtils.EMPTY_STRINGSET;
        }

        @Override
        public List<String> getParameter(String name) {
            return StringUtils.EMPTY_STRINGLIST;
        }

        @Override
        public ExtendedIncludeKey getExtendedIncludeKey() {
            return includeKey;
        }

    }


    private static class DefaultCorpusExtractFilterUnit extends DefaultIncludeFilterUnit implements CorpusExtractFilterUnit {

        private final CorpusExtractDef corpusExtractDef;

        private DefaultCorpusExtractFilterUnit(CorpusExtractDef corpusExtractDef, ExtendedIncludeKey includeKey) {
            super(includeKey);
            this.corpusExtractDef = corpusExtractDef;
        }

        @Override
        public CorpusExtractDef getCorpusExtractDef() {
            return corpusExtractDef;
        }

    }


    private static class DefaultThesaurusExtractFilterUnit extends DefaultIncludeFilterUnit implements ThesaurusExtractFilterUnit {

        private final ThesaurusExtractDef thesaurusExtractDef;

        private DefaultThesaurusExtractFilterUnit(ThesaurusExtractDef thesaurusExtractDef, ExtendedIncludeKey includeKey) {
            super(includeKey);
            this.thesaurusExtractDef = thesaurusExtractDef;
        }

        @Override
        public ThesaurusExtractDef getThesaurusExtractDef() {
            return thesaurusExtractDef;
        }

    }


    private static class DefaultAlbumExtractFilterUnit extends DefaultIncludeFilterUnit implements AlbumExtractFilterUnit {

        private final AlbumExtractDef albumExtractDef;

        private DefaultAlbumExtractFilterUnit(AlbumExtractDef albumExtractDef, ExtendedIncludeKey includeKey) {
            super(includeKey);
            this.albumExtractDef = albumExtractDef;
        }

        @Override
        public AlbumExtractDef getAlbumExtractDef() {
            return albumExtractDef;
        }

    }


    private static class DefaultAddendaExtractFilterUnit extends DefaultIncludeFilterUnit implements AddendaExtractFilterUnit {

        private final AddendaExtractDef addendaExtractDef;

        private DefaultAddendaExtractFilterUnit(AddendaExtractDef addendaExtractDef, ExtendedIncludeKey includeKey) {
            super(includeKey);
            this.addendaExtractDef = addendaExtractDef;
        }

        @Override
        public AddendaExtractDef getAddendaExtractDef() {
            return addendaExtractDef;
        }

    }

}
