/* FichothequeLib_Tools - Copyright (c) 2013-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.importation.parsers;

import java.text.ParseException;
import java.util.List;
import net.fichotheque.Fichotheque;
import net.fichotheque.Subset;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.importation.LiensImport.LienImport;
import net.fichotheque.include.IncludeKey;
import net.fichotheque.thesaurus.Motcle;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.thesaurus.metadata.ThesaurusLangChecker;
import net.fichotheque.thesaurus.policies.DynamicEditPolicy;
import net.fichotheque.thesaurus.policies.PolicyProvider;
import net.fichotheque.tools.croisement.LienBuffer;
import net.fichotheque.tools.importation.ImportationUtils;
import net.fichotheque.tools.importation.LiensImportBuilder;
import net.fichotheque.tools.parsers.croisement.LienBufferParser;
import net.fichotheque.tools.parsers.croisement.WeightMotcleToken;
import net.fichotheque.utils.ThesaurusUtils;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.text.CleanedString;
import net.mapeadores.util.text.Label;
import net.mapeadores.util.text.LabelUtils;
import net.mapeadores.util.text.StringUtils;


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

    private final LiensImportBuilder liensImportBuilder;
    private final Lang workingLang;
    private final Subset defaultSubset;
    private final Fichotheque fichotheque;
    private final PolicyProvider policyProvider;
    private final ThesaurusLangChecker thesaurusLangChecker;

    public LiensParser(Subset mainSubset, LiensImportBuilder liensImportBuilder, Lang workingLang, PolicyProvider policyProvider, ThesaurusLangChecker thesaurusLangChecker) {
        this.liensImportBuilder = liensImportBuilder;
        this.workingLang = workingLang;
        this.fichotheque = mainSubset.getFichotheque();
        if (mainSubset instanceof Corpus) {
            this.defaultSubset = mainSubset;
        } else {
            this.defaultSubset = null;
        }
        this.policyProvider = policyProvider;
        this.thesaurusLangChecker = thesaurusLangChecker;
    }

    public void checkReplaceIncludeKey(IncludeKey includeKey) {
        liensImportBuilder.addRemovedIncludeKey(includeKey);
    }

    public void checkReplaceLiage() {
        liensImportBuilder.setLiageRemoved();
    }

    public void add(IncludeKey includeKey, String value, boolean replace, boolean idalpha) {
        SubsetKey subsetKey = includeKey.getSubsetKey();
        Subset otherSubset = fichotheque.getSubset(subsetKey);
        if (otherSubset != null) {
            if ((idalpha) && (subsetKey.isThesaurusSubset()) && (((Thesaurus) otherSubset)).isIdalphaType()) {
                parseIdalpha((Thesaurus) otherSubset, includeKey, value, replace);
            } else if ((defaultSubset != null) && (subsetKey.isThesaurusSubset())) {
                Thesaurus thesaurus = (Thesaurus) otherSubset;
                Lang thesaurusLang = ThesaurusUtils.checkDisponibility(thesaurusLangChecker, thesaurus, workingLang);
                DynamicEditPolicy dynamicEditPolicy = getDynamicEditPolicy(thesaurus);
                parseMotcle(thesaurus, includeKey, value, thesaurusLang, dynamicEditPolicy, replace);
            } else {
                parseId(otherSubset, includeKey, value, replace);
            }
        }
    }

    public void add(IncludeKey includeKey, List<String> values, boolean replace, boolean idalpha) {
        SubsetKey subsetKey = includeKey.getSubsetKey();
        Subset otherSubset = fichotheque.getSubset(subsetKey);
        if (otherSubset != null) {
            if ((idalpha) && (subsetKey.isThesaurusSubset()) && (((Thesaurus) otherSubset)).isIdalphaType()) {
                for (String value : values) {
                    parseIdalpha((Thesaurus) otherSubset, includeKey, value, replace);
                }
            } else if ((defaultSubset != null) && (subsetKey.isThesaurusSubset())) {
                Thesaurus thesaurus = (Thesaurus) otherSubset;
                Lang thesaurusLang = ThesaurusUtils.checkDisponibility(thesaurusLangChecker, thesaurus, workingLang);
                DynamicEditPolicy dynamicEditPolicy = getDynamicEditPolicy(thesaurus);
                for (String value : values) {
                    parseMotcle(thesaurus, includeKey, value, thesaurusLang, dynamicEditPolicy, replace);
                }
            } else {
                for (String value : values) {
                    parseId(otherSubset, includeKey, value, replace);
                }
            }
        }
    }

    public void addLiage(String value, boolean replace) {
        String[] tokens = StringUtils.getTechnicalTokens(value, false);
        for (String token : tokens) {
            try {
                LienBuffer lienBuffer = LienBufferParser.parse(fichotheque, token, SubsetKey.CATEGORY_CORPUS, defaultSubset, "");
                LienImport lienImport = ImportationUtils.toLiageLienImport(lienBuffer.getSubsetItem(), lienBuffer.getWeight());
                if (replace) {
                    liensImportBuilder.addReplaceLienImport(lienImport);
                } else {
                    liensImportBuilder.addAppendLienImport(lienImport);
                }
            } catch (ParseException pe) {
            }
        }
    }

    public void addLiage(List<String> values, boolean replace) {
        for (String value : values) {
            addLiage(value, replace);
        }
    }

    private void parseId(Subset otherSubset, IncludeKey includeKey, String value, boolean replace) {
        int weightFilter = includeKey.getWeightFilter();
        String mode = includeKey.getMode();
        String[] tokens = StringUtils.getTechnicalTokens(value, false);
        for (String token : tokens) {
            try {
                LienBuffer lienBuffer = LienBufferParser.parseId(otherSubset, token, mode, weightFilter);
                LienImport lienImport = ImportationUtils.toLienImport(includeKey, lienBuffer.getSubsetItem(), lienBuffer.getWeight());
                if (replace) {
                    liensImportBuilder.addReplaceLienImport(lienImport);
                } else {
                    liensImportBuilder.addAppendLienImport(lienImport);
                }
            } catch (ParseException pe) {
            }
        }
    }

    private void parseIdalpha(Thesaurus thesaurus, IncludeKey includeKey, String value, boolean replace) {
        int weightFilter = includeKey.getWeightFilter();
        String mode = includeKey.getMode();
        String[] tokens = StringUtils.getTechnicalTokens(value, false);
        for (String token : tokens) {
            try {
                LienBuffer lienBuffer = LienBufferParser.parseIdalpha(thesaurus, token, mode, weightFilter);
                LienImport lienImport = ImportationUtils.toLienImport(includeKey, lienBuffer.getSubsetItem(), lienBuffer.getWeight());
                if (replace) {
                    liensImportBuilder.addReplaceLienImport(lienImport);
                } else {
                    liensImportBuilder.addAppendLienImport(lienImport);
                }
            } catch (ParseException pe) {
            }
        }
    }

    private void parseMotcle(Thesaurus thesaurus, IncludeKey includeKey, String value, Lang thesaurusLang, DynamicEditPolicy dynamicEditPolicy, boolean replace) {
        boolean withIdalpha = thesaurus.isIdalphaType();
        int weightFilter = includeKey.getWeightFilter();
        String mode = includeKey.getMode();
        String[] tokens = StringUtils.getTechnicalTokens(value, ';', false);
        for (String token : tokens) {
            WeightMotcleToken motcleToken = WeightMotcleToken.parse(token, withIdalpha, weightFilter);
            if (motcleToken != null) {
                int weight = motcleToken.getWeight();
                CleanedString labelText = motcleToken.getText();
                Motcle motcle = WeightMotcleToken.getMotcle(motcleToken, thesaurus, thesaurusLang);
                if (motcle != null) {
                    LienImport lienImport = ImportationUtils.toLienImport(includeKey, motcle, weight);
                    if (replace) {
                        liensImportBuilder.addReplaceLienImport(lienImport);
                    } else {
                        liensImportBuilder.addAppendLienImport(lienImport);
                    }
                } else if ((dynamicEditPolicy != null) && (!withIdalpha) && (!motcleToken.isIdBundle())) {
                    if (dynamicEditPolicy instanceof DynamicEditPolicy.Allow) {
                        Label label = toLabel(thesaurusLang, labelText);
                        if (label != null) {
                            LienImport lienImport = ImportationUtils.toLienImport(includeKey, thesaurus, label, weight);
                            if (replace) {
                                liensImportBuilder.addReplaceLienImport(lienImport);
                            } else {
                                liensImportBuilder.addAppendLienImport(lienImport);
                            }
                        }
                    } else if (dynamicEditPolicy instanceof DynamicEditPolicy.Transfer) {
                        Thesaurus transferThesaurus = ThesaurusUtils.getTransferThesaurus(fichotheque, dynamicEditPolicy);
                        Motcle transferMotcle = getMotcle(transferThesaurus, thesaurusLang, labelText);
                        IncludeKey transferIncludeKey = IncludeKey.newInstance(transferThesaurus.getSubsetKey(), mode, weightFilter);
                        if (transferMotcle == null) {
                            Label label = toLabel(thesaurusLang, labelText);
                            liensImportBuilder.addAppendLienImport(ImportationUtils.toLienImport(transferIncludeKey, transferThesaurus, label, weight));
                        } else {
                            liensImportBuilder.addAppendLienImport(ImportationUtils.toLienImport(transferIncludeKey, transferMotcle, weight));
                        }
                    } else if (dynamicEditPolicy instanceof DynamicEditPolicy.Check) {
                        Thesaurus[] checkThesaurusArray = ThesaurusUtils.getCheckThesaurusArray(fichotheque, dynamicEditPolicy);
                        boolean done = false;
                        for (Thesaurus checkThesaurus : checkThesaurusArray) {
                            Motcle verifMotcle = getMotcle(checkThesaurus, thesaurusLang, labelText);
                            if (motcle != null) {
                                IncludeKey verifIncludeKey = IncludeKey.newInstance(checkThesaurus.getSubsetKey(), mode, weightFilter);
                                liensImportBuilder.addAppendLienImport(ImportationUtils.toLienImport(verifIncludeKey, verifMotcle, weight));
                                done = true;
                                break;
                            }
                        }
                        if (!done) {
                            Label label = toLabel(thesaurusLang, labelText);
                            if (label != null) {
                                LienImport lienImport = ImportationUtils.toLienImport(includeKey, thesaurus, label, weight);
                                if (replace) {
                                    liensImportBuilder.addReplaceLienImport(lienImport);
                                } else {
                                    liensImportBuilder.addAppendLienImport(lienImport);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private Label toLabel(Lang thesaurusLang, CleanedString labelString) {
        if (labelString != null) {
            return LabelUtils.toLabel(thesaurusLang, labelString);
        } else {
            return null;
        }

    }

    private Motcle getMotcle(Thesaurus thesaurus, Lang thesaurusLang, CleanedString labelString) {
        if (labelString == null) {
            return null;
        }
        Lang lang = ThesaurusUtils.checkDisponibility(thesaurusLangChecker, thesaurus, thesaurusLang);
        return thesaurus.seekMotcleByLabel(labelString.toString(), lang);
    }

    private DynamicEditPolicy getDynamicEditPolicy(Thesaurus thesaurus) {
        DynamicEditPolicy dynamicEditPolicy = null;
        if (policyProvider != null) {
            dynamicEditPolicy = policyProvider.getDynamicEditPolicy(thesaurus);
            if (dynamicEditPolicy instanceof DynamicEditPolicy.None) {
                dynamicEditPolicy = null;
            }
        }
        return dynamicEditPolicy;
    }

}
