/* 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.croisement.Croisement;
import net.fichotheque.croisement.LiaisonSortKey;
import net.fichotheque.croisement.Lien;
import net.fichotheque.extraction.def.MotcleFilter;
import net.fichotheque.extraction.def.ThesaurusExtractDef;
import net.fichotheque.extraction.run.MotcleExtractInfo;
import net.fichotheque.extraction.run.ThesaurusExtractResult;
import net.fichotheque.extraction.run.ThesaurusExtractor;
import net.fichotheque.thesaurus.Motcle;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.utils.CroisementUtils;


/**
 *
 * @author Vincent Calame
 */
class ThesaurusExtractorImpl implements ThesaurusExtractor {

    private final Map<SubsetKey, ResultBuilder> builderMap = new TreeMap<SubsetKey, ResultBuilder>();
    private final ThesaurusExtractDef thesaurusExtractDef;

    ThesaurusExtractorImpl(ThesaurusExtractDef thesaurusExtractDef) {
        this.thesaurusExtractDef = thesaurusExtractDef;
    }

    @Override
    public void add(Motcle motcle, Croisement croisement) {
        Thesaurus thesaurus = motcle.getThesaurus();
        MotcleFilter motcleFilter = thesaurusExtractDef.getMotcleFilter();
        ResultBuilder resultBuilder = builderMap.get(thesaurus.getSubsetKey());
        if (resultBuilder == null) {
            resultBuilder = new ResultBuilder(thesaurus);
            builderMap.put(thesaurus.getSubsetKey(), resultBuilder);
        }
        resultBuilder.add(motcle, motcleFilter, croisement);

    }

    @Override
    public ThesaurusExtractResult getThesaurusExtractResult() {
        ThesaurusExtractResult.Entry[] array = new ThesaurusExtractResult.Entry[builderMap.size()];
        int p = 0;
        for (ResultBuilder resultBuilder : builderMap.values()) {
            array[p] = new InternalEntry(resultBuilder.thesaurus, resultBuilder.getMotcleExtractInfoList());
            p++;
        }
        InternalThesaurusExtractResult thesaurusExtractResult = new InternalThesaurusExtractResult(thesaurusExtractDef, new EntryList(array));
        return thesaurusExtractResult;
    }


    private static class ResultBuilder {

        private final Thesaurus thesaurus;
        private final SortedMap<LiaisonSortKey, InternalMotcleExtractInfo> map = new TreeMap<LiaisonSortKey, InternalMotcleExtractInfo>();

        private ResultBuilder(Thesaurus thesaurus) {
            this.thesaurus = thesaurus;
        }

        private void add(Motcle motcle, MotcleFilter motcleFilter, Croisement croisement) {
            int position;
            if (croisement != null) {
                Lien lien = croisement.getLienList().get(0);
                position = CroisementUtils.getPosition(motcle, croisement.getCroisementKey(), lien);
            } else {
                position = map.size() + 1;
            }
            LiaisonSortKey key = new LiaisonSortKey(motcle.getId(), position);
            map.put(key, new InternalMotcleExtractInfo(motcle, motcleFilter, croisement));
        }

        private List<MotcleExtractInfo> getMotcleExtractInfoList() {
            return new MotcleExtractInfoList(map.values().toArray(new MotcleExtractInfo[map.size()]));
        }

    }


    private static class InternalEntry implements ThesaurusExtractResult.Entry {

        private final Thesaurus thesaurus;
        private final List<MotcleExtractInfo> list;

        private InternalEntry(Thesaurus thesaurus, List<MotcleExtractInfo> list) {
            this.thesaurus = thesaurus;
            this.list = list;
        }

        @Override
        public Thesaurus getThesaurus() {
            return thesaurus;
        }

        @Override
        public List<MotcleExtractInfo> getMotcleExtractInfoList() {
            return list;
        }

    }


    private static class InternalThesaurusExtractResult implements ThesaurusExtractResult {

        private final ThesaurusExtractDef thesaurusExtractDef;
        private final List<Entry> entryList;

        private InternalThesaurusExtractResult(ThesaurusExtractDef thesaurusExtractDef, List<Entry> entryList) {
            this.thesaurusExtractDef = thesaurusExtractDef;
            this.entryList = entryList;
        }

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

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

    }


    private static class InternalMotcleExtractInfo implements MotcleExtractInfo {

        private final Motcle motcle;
        private final MotcleFilter motcleFilter;
        private final Croisement croisement;

        private InternalMotcleExtractInfo(Motcle motcle, MotcleFilter motcleFilter, Croisement croisement) {
            this.motcle = motcle;
            this.motcleFilter = motcleFilter;
            this.croisement = croisement;
        }

        @Override
        public Motcle getMotcle() {
            return motcle;
        }

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

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

    }


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

        private final ThesaurusExtractResult.Entry[] array;

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

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

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

    }


    private static class MotcleExtractInfoList extends AbstractList<MotcleExtractInfo> implements RandomAccess {

        private final MotcleExtractInfo[] array;

        private MotcleExtractInfoList(MotcleExtractInfo[] array) {
            this.array = array;
        }

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

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

    }

}
