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

import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.fichotheque.ExistingIdException;
import net.fichotheque.Subset;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.corpus.NoMasterIdException;
import net.fichotheque.corpus.metadata.FieldKey;
import net.mapeadores.util.text.StringUtils;


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

    public final static short ALL_FILTER = 1;
    public final static short ONLY_FICHE_FILTER = 2;
    public final static short CUSTOM_FILTER = 3;
    private final Set<Integer> idSet = new LinkedHashSet<Integer>();
    private final Corpus originCorpus;
    private final Corpus destinationCorpus;
    private final Map<Integer, Entry> entryMap = new LinkedHashMap<Integer, Entry>();
    private final Map<FieldKey, FieldMatching> matchingMap = new LinkedHashMap<FieldKey, FieldMatching>();
    private final Set<Integer> destinationIdSet = new HashSet<Integer>();
    private final Subset destinationMaster;
    private short filterType = ALL_FILTER;
    private DuplicationFilter customFilter;
    private boolean linkToOrigin = false;
    private String linkToOriginMode = "";
    private int linkToOriginWeight = -1;


    public DuplicationParameters(Corpus originCorpus, Corpus destinationCorpus) {
        this.originCorpus = originCorpus;
        this.destinationCorpus = destinationCorpus;
        this.destinationMaster = destinationCorpus.getMasterSubset();
    }

    public Corpus getOriginCorpus() {
        return originCorpus;
    }

    public Corpus getDestinationCorpus() {
        return destinationCorpus;
    }

    public short getFilterType() {
        return filterType;
    }

    public DuplicationParameters setFicheFilter(short filterType, DuplicationFilter customFilter) {
        this.filterType = filterType;
        if (filterType == CUSTOM_FILTER) {
            if (customFilter == null) {
                throw new IllegalArgumentException("Custom filter is null");
            }
            this.customFilter = customFilter;
        } else {
            this.customFilter = null;
        }
        return this;
    }

    public DuplicationParameters setLinkWithOrigin(String mode, int weight) throws ParseException {
        if (mode.length() > 0) {
            StringUtils.checkTechnicalName(mode, false);
        }
        if (weight < 1) {
            weight = 1;
        }
        this.linkToOrigin = true;
        this.linkToOriginMode = mode;
        this.linkToOriginWeight = weight;
        return this;
    }

    public boolean withLinkToOrigin() {
        return linkToOrigin;
    }

    public int getLinkToOriginWeight() {
        return linkToOriginWeight;
    }

    public String getLinkToOriginMode() {
        return linkToOriginMode;
    }

    public DuplicationParameters addFicheMeta(FicheMeta origin) {
        if (destinationMaster != null) {
            throw new IllegalStateException("this method cannot be used when destination is a satellite corpus");
        }
        if (!entryMap.containsKey(origin.getId())) {
            entryMap.put(origin.getId(), new Entry(origin, -1));
        }
        return this;
    }

    public DuplicationParameters addFicheMeta(FicheMeta origin, int destinationId) throws ExistingIdException, NoMasterIdException {
        if (entryMap.containsKey(origin.getId())) {
            return this;
        }
        if (destinationId < 1) {
            return addFicheMeta(origin);
        }
        if (destinationCorpus.getFicheMetaById(destinationId) != null) {
            throw new ExistingIdException();
        }
        if (destinationIdSet.contains(destinationId)) {
            throw new ExistingIdException();
        } else {
            destinationIdSet.add(destinationId);
        }
        if (destinationMaster != null) {
            if (destinationMaster.getSubsetItemById(destinationId) == null) {
                throw new NoMasterIdException();
            }
        }
        entryMap.put(origin.getId(), new Entry(origin, destinationId));
        return this;
    }

    public void addOriginId(int id) {
        if (id < 1) {
            throw new IllegalArgumentException("id < 1");
        }
        if (!idSet.contains(id)) {
            idSet.add(id);
        }
    }

    public List<Entry> getEntryList() {
        return new ArrayList(entryMap.values());
    }

    public DuplicationFilter getCustomFilter() {
        return customFilter;
    }

    public void addFieldMatching(FieldKey originKey, FieldKey destinationKey) {
        matchingMap.put(originKey, new FieldMatching(originKey, destinationKey));
    }

    public List<FieldMatching> getFieldMatchingList() {
        return new ArrayList(matchingMap.values());
    }


    public static class Entry {

        private final FicheMeta origin;
        private final int destinationId;

        private Entry(FicheMeta origin, int destinationId) {
            this.origin = origin;
            this.destinationId = destinationId;
        }

        public FicheMeta getOrigin() {
            return origin;
        }

        public int getDestinationId() {
            return destinationId;
        }

    }


    public static class FieldMatching {

        private final FieldKey originKey;
        private final FieldKey destinationKey;

        private FieldMatching(FieldKey originKey, FieldKey destinationKey) {
            this.originKey = originKey;
            this.destinationKey = destinationKey;
        }

        public FieldKey getOriginKey() {
            return originKey;
        }

        public FieldKey getDestinationKey() {
            return destinationKey;
        }

    }


}
