/* 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.util.List;
import net.fichotheque.ExistingIdException;
import net.fichotheque.FichothequeEditor;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.CorpusEditor;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.corpus.NoMasterIdException;
import net.fichotheque.corpus.fiche.Fiche;
import net.fichotheque.corpus.fiche.Section;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.croisement.CroisementEditor;
import net.fichotheque.eligibility.SubsetEligibility;
import net.fichotheque.tools.corpus.CorpusTools;
import net.fichotheque.tools.corpus.PurgeEngine;
import net.fichotheque.utils.EligibilityUtils;
import net.mapeadores.util.exceptions.ShouldNotOccurException;
import net.mapeadores.util.exceptions.SwitchException;
import net.fichotheque.corpus.fiche.Prop;
import net.fichotheque.corpus.fiche.Info;


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

    private final DuplicationParameters duplicationParameters;
    private final CroisementEditor croisementEditor;
    private final FichothequeEditor fichothequeEditor;
    private Corpus originCorpus;
    private Corpus destinationCorpus;

    private DuplicationEngine(FichothequeEditor fichothequeEditor, DuplicationParameters duplicationParameters) {
        this.fichothequeEditor = fichothequeEditor;
        this.croisementEditor = fichothequeEditor.getCroisementEditor();
        this.duplicationParameters = duplicationParameters;
    }

    public static SubsetMatch run(DuplicationParameters duplicationParameters, FichothequeEditor fichothequeEditor) {
        DuplicationEngine duplicationEngine = new DuplicationEngine(fichothequeEditor, duplicationParameters);
        return duplicationEngine.run();
    }

    private SubsetMatch run() {
        PurgeEngine purgeEngine = getPurgeEngine();
        List<DuplicationParameters.FieldMatching> matchingList = duplicationParameters.getFieldMatchingList();
        originCorpus = duplicationParameters.getOriginCorpus();
        destinationCorpus = duplicationParameters.getDestinationCorpus();
        CorpusEditor destinationEditor = fichothequeEditor.getCorpusEditor(destinationCorpus);
        SubsetMatch subsetMatch = new SubsetMatch(originCorpus, destinationCorpus);
        for (DuplicationParameters.Entry entry : duplicationParameters.getEntryList()) {
            FicheMeta origin = entry.getOrigin();
            FicheMeta destination = createDestination(destinationEditor, entry.getDestinationId());
            Fiche fiche = origin.getCorpus().getFiche(origin);
            if (purgeEngine != null) {
                purgeEngine.purge(fiche);
            }
            if (!matchingList.isEmpty()) {
                convertFiche(fiche, matchingList);
            }
            CorpusTools.copy(destinationEditor, origin, destination, fiche);
            subsetMatch.add(origin, destination);
        }
        SubsetEligibility subsetEligibility = getSubsetEligibility();
        if (subsetEligibility != null) {
            DuplicationUtils.copyCroisements(croisementEditor, subsetMatch, subsetEligibility);
            if (subsetEligibility.accept(originCorpus)) {
                DuplicationUtils.replicateLinks(croisementEditor, subsetMatch);
            }
        }
        if (duplicationParameters.withLinkToOrigin()) {
            DuplicationUtils.linkToOrigin(croisementEditor, subsetMatch, duplicationParameters.getLinkToOriginMode(), duplicationParameters.getLinkToOriginWeight());
        }
        return subsetMatch;
    }

    private FicheMeta createDestination(CorpusEditor destinationEditor, int id) {
        FicheMeta destination = null;
        try {
            destination = destinationEditor.createFiche(id);
        } catch (ExistingIdException eie) {
            throw new ShouldNotOccurException("ExistingId test done before");
        } catch (NoMasterIdException eie) {
            throw new ShouldNotOccurException("NoMasterId test done before");
        }
        return destination;
    }

    private SubsetEligibility getSubsetEligibility() {
        switch (duplicationParameters.getFilterType()) {
            case DuplicationParameters.ONLY_FICHE_FILTER:
                return null;
            case DuplicationParameters.CUSTOM_FILTER:
                return duplicationParameters.getCustomFilter().getSubsetEligibility();
            case DuplicationParameters.ALL_FILTER:
                return EligibilityUtils.ALL_SUBSET_ELIGIBILITY;
            default:
                throw new SwitchException("Unknown type: " + duplicationParameters.getFilterType());
        }
    }

    private PurgeEngine getPurgeEngine() {
        switch (duplicationParameters.getFilterType()) {
            case DuplicationParameters.CUSTOM_FILTER:
                return new PurgeEngine(duplicationParameters.getCustomFilter().getFieldPredicate());
            default:
                return null;
        }
    }

    private void convertFiche(Fiche fiche, List<DuplicationParameters.FieldMatching> matchingList) {
        for (DuplicationParameters.FieldMatching fieldMatching : matchingList) {
            FieldKey originKey = fieldMatching.getOriginKey();
            FieldKey destinationKey = fieldMatching.getDestinationKey();
            if (originKey.isProp()) {
                Prop prop = fiche.getProp(originKey);
                if (prop != null) {
                    fiche.setProp(destinationKey, prop.getFicheItem());
                    fiche.setProp(originKey, null);
                }
            } else if (originKey.isInfo()) {
                Info info = fiche.getInfo(originKey);
                if (info != null) {
                    fiche.appendInfo(destinationKey, info);
                    fiche.setInfo(originKey, null);
                }
            } else if (originKey.isSection()) {
                Section section = fiche.getSection(originKey);
                if (section != null) {
                    fiche.appendSection(destinationKey, section);
                    fiche.setSection(originKey, null);
                }
            }
        }
    }


}
