/* FichothequeLib_API - Copyright (c) 2020-2022 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.selection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.fichotheque.SubsetKey;
import net.fichotheque.album.Album;
import net.fichotheque.album.Illustration;
import net.fichotheque.croisement.Croisement;
import net.fichotheque.selection.CroisementCondition;
import net.fichotheque.selection.IllustrationCondition;
import net.fichotheque.selection.IllustrationQuery;
import net.fichotheque.selection.IllustrationSelector;
import net.fichotheque.selection.SelectionContext;
import net.fichotheque.utils.FichothequeUtils;
import net.fichotheque.utils.SelectionUtils;
import net.mapeadores.util.annotation.Nullable;


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

    private final SelectionContext selectionContext;
    private final Map<SubsetKey, List<IllustrationSelectEngine>> listMap = new HashMap<SubsetKey, List<IllustrationSelectEngine>>();
    private final List<Album> albumList = new ArrayList<Album>();
    private IllustrationSelectEngine firstEngine;
    private int engineCount = 0;

    public IllustrationSelectorBuilder(SelectionContext selectionContext) {
        this.selectionContext = selectionContext;
    }

    public IllustrationSelectorBuilder add(IllustrationQuery illustrationQuery, CroisementCondition croisementCondition) {
        Album[] albumArray = SelectionUtils.toAlbumArray(selectionContext.getFichotheque(), illustrationQuery, selectionContext.getSubsetAccessPredicate());
        IllustrationSelectEngine illustrationSelectEngine = new IllustrationSelectEngine(illustrationQuery, croisementCondition, selectionContext);
        if (firstEngine == null) {
            firstEngine = illustrationSelectEngine;
        }
        engineCount++;
        for (Album album : albumArray) {
            List<IllustrationSelectEngine> list = checkAlbum(album);
            list.add(illustrationSelectEngine);
        }
        return this;
    }

    public IllustrationSelectorBuilder addAll(Collection<IllustrationCondition.Entry> entries) {
        for (IllustrationCondition.Entry entry : entries) {
            add(entry.getIllustrationQuery(), entry.getCroisementCondition());
        }
        return this;
    }

    public IllustrationSelector toIllustrationSelector() {
        switch (engineCount) {
            case 0: {
                List<Album> finalAlbumList = FichothequeUtils.wrap(FichothequeUtils.toAlbumArray(selectionContext.getFichotheque(), selectionContext.getSubsetAccessPredicate()));
                return new UniqueIllustrationSelector(finalAlbumList, null, new IllustrationSelectEngine(SelectionUtils.EMPTY_ILLUSTRATIONQUERY, null, selectionContext));
            }
            case 1: {
                List<Album> finalAlbumList = FichothequeUtils.wrap(albumList.toArray(new Album[albumList.size()]));
                return new UniqueIllustrationSelector(finalAlbumList, new HashSet<SubsetKey>(listMap.keySet()), firstEngine);
            }
            default: {
                List<Album> finalAlbumList = FichothequeUtils.wrap(albumList.toArray(new Album[albumList.size()]));
                Map<SubsetKey, IllustrationSelectEngine[]> arrayMap = new HashMap<SubsetKey, IllustrationSelectEngine[]>();
                for (Map.Entry<SubsetKey, List<IllustrationSelectEngine>> entry : listMap.entrySet()) {
                    List<IllustrationSelectEngine> list = entry.getValue();
                    IllustrationSelectEngine[] array = list.toArray(new IllustrationSelectEngine[list.size()]);
                    arrayMap.put(entry.getKey(), array);
                }
                return new MultiIllustrationSelector(finalAlbumList, arrayMap);
            }
        }
    }

    private List<IllustrationSelectEngine> checkAlbum(Album album) {
        List<IllustrationSelectEngine> currentList = listMap.get(album.getSubsetKey());
        if (currentList == null) {
            currentList = new ArrayList<IllustrationSelectEngine>();
            albumList.add(album);
            listMap.put(album.getSubsetKey(), currentList);
        }
        return currentList;
    }

    public static IllustrationSelectorBuilder init(SelectionContext selectionContext) {
        return new IllustrationSelectorBuilder(selectionContext);
    }


    private static class MultiIllustrationSelector implements IllustrationSelector {

        private final List<Album> albumList;
        private final Map<SubsetKey, IllustrationSelectEngine[]> arrayMap;

        private MultiIllustrationSelector(List<Album> albumList, Map<SubsetKey, IllustrationSelectEngine[]> arrayMap) {
            this.albumList = albumList;
            this.arrayMap = arrayMap;
        }

        @Override
        public List<Album> getAlbumList() {
            return albumList;
        }

        @Override
        public boolean test(Illustration illustration) {
            IllustrationSelectEngine[] array = arrayMap.get(illustration.getSubsetKey());
            if (array == null) {
                return false;
            }
            for (IllustrationSelectEngine engine : array) {
                if (engine.isSelected(illustration)) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public Croisement isSelected(Illustration illustration, Croisement croisement) {
            IllustrationSelectEngine[] array = arrayMap.get(illustration.getSubsetKey());
            if (array == null) {
                return null;
            }
            FilteredCroisementBuilder builder = new FilteredCroisementBuilder(croisement);
            for (IllustrationSelectEngine engine : array) {
                engine.filter(illustration, builder);
            }
            return builder.toCroisement();
        }

    }


    private static class UniqueIllustrationSelector implements IllustrationSelector {

        private final List<Album> albumList;
        private final Set<SubsetKey> keySet;
        private final IllustrationSelectEngine illustrationSelectEngine;

        private UniqueIllustrationSelector(List<Album> albumList, @Nullable Set<SubsetKey> keySet, IllustrationSelectEngine illustrationSelectEngine) {
            this.albumList = albumList;
            this.keySet = keySet;
            this.illustrationSelectEngine = illustrationSelectEngine;
        }

        @Override
        public List<Album> getAlbumList() {
            return albumList;
        }

        @Override
        public boolean test(Illustration illustration) {
            if ((keySet != null) && (!keySet.contains(illustration.getSubsetKey()))) {
                return false;
            }
            return illustrationSelectEngine.isSelected(illustration);
        }

        @Override
        public Croisement isSelected(Illustration illustration, Croisement croisement) {
            if ((keySet != null) && (!keySet.contains(illustration.getSubsetKey()))) {
                return null;
            }
            FilteredCroisementBuilder builder = new FilteredCroisementBuilder(croisement);
            illustrationSelectEngine.filter(illustration, builder);
            return builder.toCroisement();
        }

    }

}
