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

import java.util.function.Consumer;
import net.fichotheque.Fichotheque;
import net.fichotheque.FichothequeConstants;
import net.fichotheque.importation.ThesaurusImport;
import net.fichotheque.thesaurus.Motcle;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.tools.importation.thesaurus.EditMotcleImportBuilder;
import net.fichotheque.tools.importation.thesaurus.EditThesaurusImportBuilder;
import net.fichotheque.tools.importation.thesaurus.MergeThesaurusImportBuilder;
import net.fichotheque.tools.importation.thesaurus.MoveThesaurusImportBuilder;
import net.fichotheque.tools.importation.thesaurus.RemoveThesaurusImportBuilder;
import net.fichotheque.tools.importation.thesaurus.ThesaurusImportBuilder;
import net.fichotheque.utils.ParentChangeUtils;
import net.mapeadores.util.exceptions.SwitchException;
import net.mapeadores.util.text.CleanedString;
import net.mapeadores.util.xml.DOMUtils;
import org.w3c.dom.Element;


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

    private final ThesaurusImportBuilder thesaurusImportBuilder;
    private final Thesaurus thesaurus;
    private final Fichotheque fichotheque;


    public ThesaurusImportDOMReader(ThesaurusImportBuilder thesaurusImportBuilder) {
        this.thesaurusImportBuilder = thesaurusImportBuilder;
        this.thesaurus = thesaurusImportBuilder.getThesaurus();
        this.fichotheque = thesaurus.getFichotheque();
    }

    public ThesaurusImportDOMReader read(Element element) {
        Consumer<Element> elementConsumer;
        String type = thesaurusImportBuilder.getType();
        switch (type) {
            case ThesaurusImport.EDIT_TYPE:
                elementConsumer = new EditConsumer((EditThesaurusImportBuilder) thesaurusImportBuilder);
                break;
            case ThesaurusImport.MERGE_TYPE:
                elementConsumer = new MergeConsumer((MergeThesaurusImportBuilder) thesaurusImportBuilder);
                break;
            case ThesaurusImport.MOVE_TYPE:
                elementConsumer = new MoveConsumer((MoveThesaurusImportBuilder) thesaurusImportBuilder);
                break;
            case ThesaurusImport.REMOVE_TYPE:
                elementConsumer = new RemoveConsumer((RemoveThesaurusImportBuilder) thesaurusImportBuilder);
                break;
            default:
                throw new SwitchException("Unknown type: " + type);
        }
        DOMUtils.readChildren(element, elementConsumer);
        return this;
    }


    public static ThesaurusImportDOMReader init(ThesaurusImportBuilder thesaurusImportBuilder) {
        return new ThesaurusImportDOMReader(thesaurusImportBuilder);
    }


    private class EditConsumer implements Consumer<Element> {

        private final EditThesaurusImportBuilder editThesaurusImportBuilder;

        private EditConsumer(EditThesaurusImportBuilder editThesaurusImportBuilder) {
            this.editThesaurusImportBuilder = editThesaurusImportBuilder;
        }

        @Override
        public void accept(Element element) {
            String tagName = element.getTagName();
            switch (tagName) {
                case "motcleimport":
                    String idString = element.getAttribute("id");
                    String idalpha = getIdalpha(element);
                    if (idString.isEmpty()) {
                        boolean isChange = false;
                        if (idalpha != null) {
                            Motcle motcle = thesaurus.getMotcleByIdalpha(idalpha);
                            if (motcle != null) {
                                readChange(motcle, element, null);
                                isChange = true;
                            }
                        }
                        if (!isChange) {
                            readCreation(-1, idalpha, element);
                        }
                    } else {
                        try {
                            int id = Integer.parseInt(idString);
                            Motcle motcle = thesaurus.getMotcleById(id);
                            if (motcle != null) {
                                readChange(motcle, element, idalpha);
                            } else {
                                readCreation(id, idalpha, element);
                            }
                        } catch (NumberFormatException nfe) {
                        }
                    }
                    break;
            }
        }

        private String getIdalpha(Element element) {
            IdalphaConsumer idalphaConsumer = new IdalphaConsumer();
            DOMUtils.readChildren(element, idalphaConsumer);
            return idalphaConsumer.idalpha;
        }

        private void readChange(Motcle motcle, Element element, String newIdalpha) {
            EditMotcleImportBuilder builder = editThesaurusImportBuilder.getEditMotcleImportBuilder(motcle);
            if (newIdalpha != null) {
                builder.setNewIdalpha(newIdalpha);
            }
            DOMUtils.readChildren(element, new EditMotcleConsumer(builder));
        }

        private void readCreation(int newId, String idalpha, Element element) {
            EditMotcleImportBuilder builder = editThesaurusImportBuilder.getEditMotcleImportBuilder(newId, idalpha);
            DOMUtils.readChildren(element, new EditMotcleConsumer(builder));
        }

    }


    private class MergeConsumer implements Consumer<Element> {

        private final MergeThesaurusImportBuilder mergeThesaurusImportBuilder;

        private MergeConsumer(MergeThesaurusImportBuilder mergeThesaurusImportBuilder) {
            this.mergeThesaurusImportBuilder = mergeThesaurusImportBuilder;
        }

        @Override
        public void accept(Element element) {
            String tagName = element.getTagName();
            switch (tagName) {
                case "motcleimport":
                    String idString = element.getAttribute("id");
                    String destinationString = element.getAttribute("destination");
                    try {
                        int id = Integer.parseInt(idString);
                        int destinationId = Integer.parseInt(destinationString);
                        Motcle motcle = thesaurus.getMotcleById(id);
                        Motcle destinationMotcle = thesaurusImportBuilder.getDestinationThesaurus().getMotcleById(destinationId);
                        if ((motcle != null) && (destinationMotcle != null)) {
                            mergeThesaurusImportBuilder.add(motcle, destinationMotcle);
                        }
                    } catch (NumberFormatException nfe) {
                    }
                    break;
            }
        }

    }


    private class MoveConsumer implements Consumer<Element> {

        private final MoveThesaurusImportBuilder moveThesaurusImportBuilder;

        private MoveConsumer(MoveThesaurusImportBuilder moveThesaurusImportBuilder) {
            this.moveThesaurusImportBuilder = moveThesaurusImportBuilder;
        }

        @Override
        public void accept(Element element) {
            String tagName = element.getTagName();
            switch (tagName) {
                case "motcleimport":
                    String idString = element.getAttribute("id");
                    try {
                        int id = Integer.parseInt(idString);
                        Motcle motcle = thesaurus.getMotcleById(id);
                        if (motcle != null) {
                            moveThesaurusImportBuilder.add(motcle);
                        }
                    } catch (NumberFormatException nfe) {
                    }
                    break;
            }
        }

    }


    private class RemoveConsumer implements Consumer<Element> {

        private final RemoveThesaurusImportBuilder removeThesaurusImportBuilder;

        private RemoveConsumer(RemoveThesaurusImportBuilder removeThesaurusImportBuilder) {
            this.removeThesaurusImportBuilder = removeThesaurusImportBuilder;
        }

        @Override
        public void accept(Element element) {
            String tagName = element.getTagName();
            switch (tagName) {
                case "motcleimport":
                    String idString = element.getAttribute("id");
                    try {
                        int id = Integer.parseInt(idString);
                        Motcle motcle = thesaurus.getMotcleById(id);
                        if (motcle != null) {
                            removeThesaurusImportBuilder.add(motcle);
                        }
                    } catch (NumberFormatException nfe) {
                    }
                    break;
            }
        }

    }


    private class EditMotcleConsumer implements Consumer<Element> {

        private final EditMotcleImportBuilder builder;

        private EditMotcleConsumer(EditMotcleImportBuilder builder) {
            this.builder = builder;
        }


        @Override
        public void accept(Element element) {
            String tagName = element.getTagName();
            switch (tagName) {
                case "attr":
                    ImportationDomUtils.readAttrElement(element, builder.getAttributeChangeBuilder());
                    break;
                case "label":
                case "lib":
                    ImportationDomUtils.readLabelElement(element, builder.getLabelChangeBuilder());
                    break;
                case "idalpha":
                    break;
                case "parent":
                    String idString = element.getAttribute("id");
                    if (idString.isEmpty()) {
                        String idalphaParent = element.getAttribute("idalpha");
                        if (idalphaParent.isEmpty()) {
                            builder.setParent(ParentChangeUtils.THESAURUS);
                        } else {
                            builder.setParent(ParentChangeUtils.toIdalphaParentChange(idalphaParent));
                        }
                    } else {
                        try {
                            int parentId = Integer.parseInt(idString);
                            builder.setParent(ParentChangeUtils.toIdParentChange(parentId));
                        } catch (NumberFormatException nfe) {
                        }
                    }
                    break;
                case "status":
                    String statusValue = DOMUtils.readSimpleElement(element);
                    try {
                        builder.setNewStatus(FichothequeConstants.checkMotcleStatus(statusValue));
                    } catch (IllegalArgumentException iae) {

                    }
                    break;
                case "ties":
                case "liens":
                    String type = element.getAttribute("type");
                    TiesImportDOMReader.init(fichotheque, builder.getTiesImportBuilder(), type)
                            .read(element);
                    break;
            }
        }

    }


    private class IdalphaConsumer implements Consumer<Element> {

        private String idalpha = null;

        private IdalphaConsumer() {

        }

        @Override
        public void accept(Element element) {
            String tagName = element.getTagName();
            switch (tagName) {
                case "idalpha":
                    CleanedString idalphaString = DOMUtils.contentToCleanedString(element);
                    if (idalphaString != null) {
                        idalpha = idalphaString.toString();
                    }
                    break;
            }
        }

    }

}
