/* FichothequeLib_Tools - Copyright (c) 2012-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.tools.extraction;

import java.util.AbstractList;
import java.util.List;
import java.util.Map;
import java.util.RandomAccess;
import java.util.SortedMap;
import java.util.TreeMap;
import net.fichotheque.SubsetKey;
import net.fichotheque.album.Album;
import net.fichotheque.album.Illustration;
import net.fichotheque.croisement.Croisement;
import net.fichotheque.croisement.LiaisonSortKey;
import net.fichotheque.croisement.Lien;
import net.fichotheque.extraction.def.AlbumExtractDef;
import net.fichotheque.extraction.def.IllustrationFilter;
import net.fichotheque.extraction.run.AlbumExtractResult;
import net.fichotheque.extraction.run.AlbumExtractor;
import net.fichotheque.extraction.run.IllustrationExtractInfo;
import net.fichotheque.utils.CroisementUtils;


/**
 *
 * @author Vincent Calame
 */
class AlbumExtractorImpl implements AlbumExtractor {

    private final Map<SubsetKey, ResultBuilder> builderMap = new TreeMap<SubsetKey, ResultBuilder>();
    private final AlbumExtractDef albumExtractDef;

    AlbumExtractorImpl(AlbumExtractDef albumExtractDef) {
        this.albumExtractDef = albumExtractDef;
    }

    @Override
    public void add(Illustration illustration, Croisement croisement) {
        Album album = illustration.getAlbum();
        ResultBuilder resultBuilder = builderMap.get(album.getSubsetKey());
        IllustrationFilter illustrationFilter = albumExtractDef.getIllustrationFilter();
        if (resultBuilder == null) {
            resultBuilder = new ResultBuilder(album);
            builderMap.put(album.getSubsetKey(), resultBuilder);
        }
        resultBuilder.add(illustration, illustrationFilter, croisement);
    }

    @Override
    public AlbumExtractResult getAlbumExtractResult() {
        AlbumExtractResult.Entry[] array = new AlbumExtractResult.Entry[builderMap.size()];
        int p = 0;
        for (ResultBuilder resultBuilder : builderMap.values()) {
            array[p] = new InternalEntry(resultBuilder.album, resultBuilder.getIllustrationExtractInfoList());
            p++;
        }
        InternalAlbumExtractResult albumExtractResult = new InternalAlbumExtractResult(albumExtractDef, new EntryList(array));
        return albumExtractResult;
    }


    private class ResultBuilder {

        private Album album;
        private final SortedMap<LiaisonSortKey, InternalIllustrationExtractInfo> map = new TreeMap<LiaisonSortKey, InternalIllustrationExtractInfo>();

        private ResultBuilder(Album album) {
            this.album = album;
        }

        private void add(Illustration illustration, IllustrationFilter illustrationFilter, Croisement croisement) {
            int position;
            if (croisement != null) {
                Lien lien = croisement.getLienList().get(0);
                position = CroisementUtils.getPosition(illustration, croisement.getCroisementKey(), lien);
            } else {
                position = map.size() + 1;
            }
            LiaisonSortKey key = new LiaisonSortKey(illustration.getId(), position);
            map.put(key, new InternalIllustrationExtractInfo(illustration, illustrationFilter, croisement));
        }

        private List<IllustrationExtractInfo> getIllustrationExtractInfoList() {
            return new IllustrationExtractInfoList(map.values().toArray(new IllustrationExtractInfo[map.size()]));
        }

    }


    private static class InternalAlbumExtractResult implements AlbumExtractResult {

        private final AlbumExtractDef albumExtractDef;
        private final List<Entry> entryList;

        private InternalAlbumExtractResult(AlbumExtractDef albumExtractDef, List<Entry> entryList) {
            this.albumExtractDef = albumExtractDef;
            this.entryList = entryList;
        }

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

        @Override
        public List<Entry> getEntryList() {
            return entryList;
        }

    }


    private static class InternalEntry implements AlbumExtractResult.Entry {

        private final Album album;
        private final List<IllustrationExtractInfo> list;

        private InternalEntry(Album album, List<IllustrationExtractInfo> list) {
            this.album = album;
            this.list = list;
        }

        @Override
        public Album getAlbum() {
            return album;
        }

        @Override
        public List<IllustrationExtractInfo> getIllustrationExtractInfoList() {
            return list;
        }

    }


    private static class InternalIllustrationExtractInfo implements IllustrationExtractInfo {

        private final Illustration illustration;
        private final IllustrationFilter illustrationFilter;
        private final Croisement croisement;

        public InternalIllustrationExtractInfo(Illustration illustration, IllustrationFilter illustrationFilter, Croisement croisement) {
            this.illustration = illustration;
            this.illustrationFilter = illustrationFilter;
            this.croisement = croisement;
        }

        @Override
        public Illustration getIllustration() {
            return illustration;
        }

        @Override
        public IllustrationFilter getIllustrationFilter() {
            return illustrationFilter;
        }

        @Override
        public Croisement getCroisement() {
            return croisement;
        }

    }


    private static class EntryList extends AbstractList<AlbumExtractResult.Entry> implements RandomAccess {

        private final AlbumExtractResult.Entry[] array;

        private EntryList(AlbumExtractResult.Entry[] array) {
            this.array = array;
        }

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

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

    }


    private static class IllustrationExtractInfoList extends AbstractList<IllustrationExtractInfo> implements RandomAccess {

        private final IllustrationExtractInfo[] array;

        private IllustrationExtractInfoList(IllustrationExtractInfo[] array) {
            this.array = array;
        }

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

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

    }

}
