/* FichothequeLib_Tools - Copyright (c) 2024-2025 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.thesaurus.sync;

import java.util.HashMap;
import java.util.Map;
import net.fichotheque.FichothequeConstants;
import net.fichotheque.thesaurus.Motcle;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.thesaurus.sync.MotcleSync;
import net.fichotheque.thesaurus.sync.ThesaurusSync;
import net.fichotheque.tools.importation.thesaurus.EditMotcleImportBuilder;
import net.fichotheque.tools.importation.thesaurus.EditThesaurusImportBuilder;
import net.mapeadores.util.attr.AttributeChange;
import net.mapeadores.util.attr.AttributeUtils;
import net.mapeadores.util.text.LabelChange;


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

    private final Thesaurus destinationThesaurus;
    private final ThesaurusSync originThesaurus;
    private final Map<String, Motcle> missingIdalpha = new HashMap<String, Motcle>();
    private final EditThesaurusImportBuilder changeBuilder;
    private final EditThesaurusImportBuilder creationBuilder;

    private SyncScan(ThesaurusSync originThesaurus, Thesaurus destinationThesaurus) {
        this.originThesaurus = originThesaurus;
        this.destinationThesaurus = destinationThesaurus;
        this.changeBuilder = new EditThesaurusImportBuilder(destinationThesaurus);
        this.creationBuilder = new EditThesaurusImportBuilder(destinationThesaurus);
    }

    private void run() {
        for (Motcle motcle : destinationThesaurus.getMotcleList()) {
            missingIdalpha.put(motcle.getIdalpha(), motcle);
        }
        for (MotcleSync originMotcle : originThesaurus.getMotcleSyncList()) {
            String idalpha = originMotcle.getIdalpha();
            Motcle destinationMotcle = destinationThesaurus.getMotcleByIdalpha(idalpha);
            if (destinationMotcle != null) {
                missingIdalpha.remove(idalpha);
                sync(originMotcle, destinationMotcle);
            } else {
                create(originMotcle);
            }
        }
        checkRemoved();
    }

    private void create(MotcleSync origin) {
        String newIdalpha = origin.getIdalpha();
        EditMotcleImportBuilder motcleImportBuilder = creationBuilder.getEditMotcleImportBuilder(-1, newIdalpha);
        motcleImportBuilder.setNewStatus(origin.getStatus());
        LabelChange labelChange = origin.getLabelChange();
        if (labelChange != null) {
            motcleImportBuilder.getLabelChangeBuilder().putLabels(labelChange.getChangedLabels());
        }
        AttributeChange attributeChange = origin.getAttributeChange();
        if (attributeChange != null) {
            motcleImportBuilder.getAttributeChangeBuilder().changeAttributes(attributeChange);
        }
    }

    private void sync(MotcleSync origin, Motcle destination) {
        EditMotcleImportBuilder motcleImportBuilder = changeBuilder.getEditMotcleImportBuilder(destination);
        if (!origin.getStatus().equals(destination.getStatus())) {
            motcleImportBuilder.setNewStatus(origin.getStatus());
        }
        LabelChange labelChange = origin.getLabelChange();
        if (labelChange != null) {
            motcleImportBuilder.getLabelChangeBuilder().filterRealChanges(destination.getLabels(), labelChange);
        }
        AttributeChange attributeChange = origin.getAttributeChange();
        if (attributeChange != null) {
            motcleImportBuilder.getAttributeChangeBuilder().filterRealChanges(destination.getAttributes(), attributeChange, AttributeUtils.NONE_PREDICATE);
        }
    }

    private void checkRemoved() {
        for (Map.Entry<String, Motcle> entry : missingIdalpha.entrySet()) {
            Motcle motcle = entry.getValue();
            if (!motcle.getStatus().equals(FichothequeConstants.OBSOLETE_STATUS)) {
                EditMotcleImportBuilder motcleImportBuilder = changeBuilder.getEditMotcleImportBuilder(motcle);
                motcleImportBuilder.setNewStatus(FichothequeConstants.OBSOLETE_STATUS);
            }
        }
    }

    private SyncScanResult computeResult() {
        return SyncScanResult.init()
                .setChangeImport(changeBuilder.toThesaurusImport())
                .setCreationImport(creationBuilder.toThesaurusImport());
    }

    public static SyncScanResult scanThesaurusImport(ThesaurusSync originThesaurus, Thesaurus destinationThesaurus) {
        SyncScan engine = new SyncScan(originThesaurus, destinationThesaurus);
        engine.run();
        return engine.computeResult();
    }

}
