/* 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.parsers.croisement;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.fichotheque.SubsetItem;
import net.fichotheque.addenda.Addenda;
import net.fichotheque.croisement.CroisementChanges;
import net.fichotheque.croisement.CroisementEditor;
import net.fichotheque.croisement.Liaison;
import net.fichotheque.croisement.Lien;
import net.fichotheque.tools.croisement.CroisementChangeBuilder;
import net.fichotheque.tools.croisement.CroisementChangesBuilder;
import net.fichotheque.utils.CroisementUtils;


/**
 *
 * @author Vincent Calame
 */
class DocumentOrderManager {

    private final SubsetItem mainSubsetItem;
    private final Addenda addenda;
    private final String mode;
    private final int weight;
    private final List<Object> orderList = new ArrayList<Object>();

    DocumentOrderManager(SubsetItem mainSubsetItem, Addenda addenda, String mode, int weight) {
        this.mainSubsetItem = mainSubsetItem;
        this.addenda = addenda;
        this.mode = mode;
        this.weight = weight;
    }

    void add(Object orderObject) {
        orderList.add(orderObject);
    }

    void replace(String basename, int newDocumentId) {
        int idx = orderList.indexOf(basename);
        orderList.set(idx, newDocumentId);
    }

    void save(CroisementEditor croisementEditor) {
        EditEngine editEngine = new EditEngine();
        editEngine.initLiaisonInfos();
        editEngine.scanNewOrder(orderList);
        CroisementChanges croisementChanges = editEngine.toCroisementChanges();
        croisementEditor.updateCroisements(mainSubsetItem, croisementChanges);
    }


    private class EditEngine {

        private final List<LiaisonInfo> infoList = new ArrayList<LiaisonInfo>();
        private final Map<Integer, LiaisonInfo> infoByIdMap = new HashMap<Integer, LiaisonInfo>();

        private EditEngine() {

        }

        private void initLiaisonInfos() {
            Collection<Liaison> liaisons = CroisementUtils.filter(mainSubsetItem.getCroisements(addenda), mode, weight);
            int currentIndex = 0;
            for (Liaison liaison : liaisons) {
                LiaisonInfo liaisonInfo = new LiaisonInfo(liaison, currentIndex);
                infoList.add(liaisonInfo);
                infoByIdMap.put(liaison.getSubsetItem().getId(), liaisonInfo);
            }
        }

        private void scanNewOrder(List<Object> orderList) {
            int newIndex = 0;
            for (Object obj : orderList) {
                if (obj instanceof Integer) {
                    LiaisonInfo liaisonInfo = infoByIdMap.get((Integer) obj);
                    if (liaisonInfo != null) {
                        initPosition(liaisonInfo, newIndex);
                        newIndex++;
                    }
                }
            }
            for (LiaisonInfo liaisonInfo : infoList) {
                if (liaisonInfo.newIndex == -1) {
                    initPosition(liaisonInfo, newIndex);
                    newIndex++;
                }
            }
        }

        private void initPosition(LiaisonInfo liaisonInfo, int newIndex) {
            liaisonInfo.newIndex = newIndex;
            liaisonInfo.newPosition = infoList.get(newIndex).currentPosition;
        }

        private CroisementChanges toCroisementChanges() {
            CroisementChangesBuilder builder = new CroisementChangesBuilder();
            for (LiaisonInfo liaisonInfo : infoList) {
                CroisementChangeBuilder changeBuilder = new CroisementChangeBuilder();
                changeBuilder.addLien(liaisonInfo.getNewLien());
                builder.addEntry(liaisonInfo.liaison.getSubsetItem(), changeBuilder.toCroisementChange());
            }
            return builder.toCroisementChanges();
        }


    }


    private static class LiaisonInfo {

        private final Liaison liaison;
        private final int currentPosition;
        private final int currentIndex;
        private int newIndex = -1;
        private int newPosition = -1;

        private LiaisonInfo(Liaison liaison, int currentIndex) {
            this.liaison = liaison;
            this.currentPosition = liaison.getPosition();
            this.currentIndex = currentIndex;
        }

        private Lien getNewLien() {
            Lien lien = liaison.getLien();
            int position1;
            int position2;
            if (liaison.getPositionNumber() == 1) {
                position1 = newPosition;
                position2 = lien.getPosition2();
            } else {
                position1 = lien.getPosition1();
                position2 = newPosition;
            }
            return CroisementUtils.toLien(lien.getMode(), lien.getWeight(), position1, position2);
        }

    }

}
