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

import java.text.ParseException;
import java.util.function.Consumer;
import net.fichotheque.FichothequeQuestioner;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.fiche.AmountItem;
import net.fichotheque.corpus.fiche.CountryItem;
import net.fichotheque.corpus.fiche.DateItem;
import net.fichotheque.corpus.fiche.EmailItem;
import net.fichotheque.corpus.fiche.FicheItem;
import net.fichotheque.corpus.fiche.GeopointItem;
import net.fichotheque.corpus.fiche.ImageItem;
import net.fichotheque.corpus.fiche.Item;
import net.fichotheque.corpus.fiche.LanguageItem;
import net.fichotheque.corpus.fiche.LinkItem;
import net.fichotheque.corpus.fiche.NumberItem;
import net.fichotheque.corpus.fiche.ParaItem;
import net.fichotheque.corpus.fiche.PersonItem;
import net.fichotheque.sphere.UserLoginException;
import net.fichotheque.utils.FichothequeUtils;
import net.mapeadores.util.localisation.Country;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.logging.MessageHandler;
import net.mapeadores.util.models.EmailCore;
import net.mapeadores.util.models.EmailCoreUtils;
import net.mapeadores.util.models.PersonCore;
import net.mapeadores.util.models.PersonCoreUtils;
import net.mapeadores.util.money.ExtendedCurrency;
import net.mapeadores.util.primitives.Decimal;
import net.mapeadores.util.primitives.DegreDecimal;
import net.mapeadores.util.date.FuzzyDate;
import net.mapeadores.util.text.StringUtils;
import net.mapeadores.util.xml.DOMUtils;
import net.mapeadores.util.xml.XMLUtils;
import org.w3c.dom.Element;


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

    private final FicheBlockDOMReader ficheBlockDOMReader;
    private final FichothequeQuestioner fichothequeQuestioner;
    private final MessageHandler messageHandler;

    public FicheItemDOMReader(FicheBlockDOMReader ficheBlockDOMReader, FichothequeQuestioner fichothequeQuestioner, MessageHandler messageHandler) {
        this.ficheBlockDOMReader = ficheBlockDOMReader;
        this.messageHandler = messageHandler;
        this.fichothequeQuestioner = fichothequeQuestioner;
    }

    public FicheItem readFicheItem(Element element) {
        switch (element.getTagName()) {
            case "item":
                String value = XMLUtils.getData(element);
                if (value.length() == 0) {
                    return null;
                } else {
                    return new Item(value);
                }
            case "person":
            case "personne":
                return readPerson(element);
            case "language":
            case "langue":
                return readLanguage(element);
            case "country":
            case "pays":
                return readCountry(element);
            case "date":
            case "datation":
                return readDate(element);
            case "link":
                return readLink(element);
            case "email":
            case "courriel":
                return readEmail(element);
            case "amount":
            case "montant":
                return readAmount(element);
            case "number":
            case "nombre":
                return readNumber(element);
            case "geopoint":
                return readGeopoint(element);
            case "para":
                return readPara(element);
            case "image":
                return readImage(element);
            case "user":
                return readUser(element);
            default:
                return null;
        }
    }

    public PersonItem readPerson(Element element) {
        String idString = element.getAttribute("id");
        if (idString.length() == 0) {
            idString = element.getAttribute("idsph");
        }
        String spherestring = element.getAttribute("sphere");
        if ((spherestring.length() != 0) && (idString.length() != 0)) {
            try {
                SubsetKey sphereKey = SubsetKey.parse(SubsetKey.CATEGORY_SPHERE, spherestring);
                int id = Integer.parseInt(idString);
                if (id > 0) {
                    return new PersonItem(FichothequeUtils.toGlobalId(sphereKey, id));
                }
            } catch (ParseException | NumberFormatException e) {
                return null;
            }
        }
        PersonConsumer personConsumer = new PersonConsumer();
        DOMUtils.readChildren(element, personConsumer);
        PersonCore personCore = PersonCoreUtils.toPersonCore(personConsumer.surname, personConsumer.forename, personConsumer.nonlatin, personConsumer.surnameFirst);
        return new PersonItem(personCore, personConsumer.organism);
    }


    public LanguageItem readLanguage(Element element) {
        String langString = element.getAttribute("lang");
        try {
            Lang lang = Lang.parse(langString);
            return new LanguageItem(lang);
        } catch (ParseException mcle) {
            return null;
        }
    }

    public CountryItem readCountry(Element element) {
        try {
            Country country = Country.parse(element.getAttribute("country"));
            return new CountryItem(country);
        } catch (ParseException pe) {
            return null;
        }
    }

    public NumberItem readNumber(Element element) {
        String valString = element.getAttribute("val");
        try {
            Decimal decimal = StringUtils.parseStrictDecimal(valString);
            return new NumberItem(decimal);
        } catch (NumberFormatException nfe) {
            return null;
        }
    }

    public GeopointItem readGeopoint(Element element) {
        String latitudeString = element.getAttribute("lat");
        String longitudeString = element.getAttribute("lon");
        if (longitudeString.length() == 0) {
            longitudeString = element.getAttribute("long"); //Ancienne version avant 0.9.8.7-beta07
        }
        try {
            Decimal latitude = StringUtils.parseStrictDecimal(latitudeString);
            Decimal longitude = StringUtils.parseStrictDecimal(longitudeString);
            return new GeopointItem(DegreDecimal.newInstance(latitude), DegreDecimal.newInstance(longitude));
        } catch (NumberFormatException nfe) {
            return null;
        }
    }

    public ParaItem readPara(Element element) {
        ParaItem.Builder builder = new ParaItem.Builder();
        ficheBlockDOMReader.readContentList(builder, element);
        return builder.toParaItem();
    }

    public AmountItem readAmount(Element element) {
        String valString = element.getAttribute("val");
        String curString = element.getAttribute("cur");
        try {
            Decimal decimal = StringUtils.parseStrictDecimal(valString);
            ExtendedCurrency currency = ExtendedCurrency.parse(curString);
            return new AmountItem(decimal, currency);
        } catch (NumberFormatException | ParseException e) {
            return null;
        }
    }

    public DateItem readDate(Element element) {
        String type = element.getAttribute("type");
        String yearString = element.getAttribute("a");
        if (yearString.isEmpty()) {
            yearString = element.getAttribute("y");
        }
        String halfyearString = element.getAttribute("s");
        String quarterString = element.getAttribute("t");
        if (quarterString.isEmpty()) {
            quarterString = element.getAttribute("q");
        }
        String monthString = element.getAttribute("m");
        String dayString = element.getAttribute("j");
        if (dayString.isEmpty()) {
            dayString = element.getAttribute("d");
        }
        FuzzyDate date;
        try {
            int year = Integer.parseInt(yearString);
            switch (type) {
                case "s":
                    int halfyear = Integer.parseInt(halfyearString);
                    date = FuzzyDate.fromHalfYear(year, halfyear);
                    break;
                case "t":
                case "q":
                    int quarter = Integer.parseInt(quarterString);
                    date = FuzzyDate.fromQuarter(year, quarter);
                    break;
                case "m":
                    int month = Integer.parseInt(monthString);
                    date = FuzzyDate.fromMonth(year, month);
                    break;
                case "j":
                case "d":
                    int daymonth = Integer.parseInt(monthString);
                    int day = Integer.parseInt(dayString);
                    date = FuzzyDate.fromDay(year, daymonth, day);
                    break;
                default:
                    date = FuzzyDate.fromYear(year);
            }
        } catch (IllegalArgumentException e) {
            return null;
        }
        return new DateItem(date);
    }

    public LinkItem readLink(Element element) {
        String href = element.getAttribute("href");
        LinkConsumer linkConsumer = new LinkConsumer();
        DOMUtils.readChildren(element, linkConsumer);
        return new LinkItem(href, linkConsumer.title, linkConsumer.comment);
    }

    public ImageItem readImage(Element element) {
        String src = element.getAttribute("src");
        ImageConsumer imageConsumer = new ImageConsumer();
        DOMUtils.readChildren(element, imageConsumer);
        return new ImageItem(src, imageConsumer.alt, imageConsumer.title);
    }

    public EmailItem readEmail(Element element) {
        String addrSpec = element.getAttribute("addr-spec");
        String realName = element.getAttribute("real-name");
        if (realName.length() == 0) {
            String strg = XMLUtils.getData(element);
            if (strg.length() > 0) {
                try {
                    EmailCore c2 = EmailCoreUtils.parse(strg);
                    realName = c2.getRealName();
                } catch (ParseException pe) {
                }
            }
        }
        try {
            EmailCore emailCore = EmailCoreUtils.parse(addrSpec, realName);
            return new EmailItem(emailCore);
        } catch (ParseException pe) {
            return null;
        }
    }

    public FicheItem readUser(Element element) {
        String login = element.getAttribute("login");
        if (login.isEmpty()) {
            return null;
        }
        String sphereName = element.getAttribute("sphere");
        SubsetKey defaultSphereKey = null;
        boolean sphereCorrect = true;
        if (!sphereName.isEmpty()) {
            try {
                defaultSphereKey = SubsetKey.parse(SubsetKey.CATEGORY_SPHERE, sphereName);
            } catch (ParseException pe) {
                sphereCorrect = false;
            }
        }
        if (sphereCorrect) {
            try {
                String userGlobalId = fichothequeQuestioner.getUserGlobalId(login, defaultSphereKey);
                return new PersonItem(userGlobalId);
            } catch (UserLoginException e) {

            }
        }
        String itemValue = login;
        if (!sphereName.isEmpty()) {
            itemValue = itemValue + "[" + sphereName + "]";
        }
        return new Item(itemValue);
    }


    private class LinkConsumer implements Consumer<Element> {

        private String title = "";
        private String comment = "";

        private LinkConsumer() {

        }

        @Override
        public void accept(Element element) {
            switch (element.getTagName()) {
                case "title":
                    title = XMLUtils.getData(element);
                    break;
                case "comment":
                    comment = XMLUtils.getData(element);
                    break;
            }
        }

    }


    private class ImageConsumer implements Consumer<Element> {

        String alt = "";
        String title = "";

        private ImageConsumer() {

        }

        @Override
        public void accept(Element element) {
            switch (element.getTagName()) {
                case "alt":
                    alt = XMLUtils.getData(element);
                    break;
                case "title":
                    title = XMLUtils.getData(element);
                    break;
            }
        }

    }


    private class PersonConsumer implements Consumer<Element> {

        private String surname = "";
        private String forename = "";
        private String nonlatin = "";
        private boolean surnameFirst = false;
        private String organism = "";

        private PersonConsumer() {

        }

        @Override
        public void accept(Element element) {
            switch (element.getTagName()) {
                case "surname":
                case "nom":
                    surname = XMLUtils.getData(element);
                    String surnameFirstString = element.getAttribute("surname-first");
                    if (surnameFirstString.length() == 0) {
                        surnameFirstString = element.getAttribute("avant");
                    }
                    if (surnameFirstString.equals("true")) {
                        surnameFirst = true;
                    }
                    break;
                case "forename":
                case "prenom":
                    forename = XMLUtils.getData(element);
                    break;
                case "nonlatin":
                case "original":
                    nonlatin = XMLUtils.getData(element);
                    break;
                case "organism":
                case "organisme":
                    organism = XMLUtils.getData(element);
                    break;
            }
        }

    }

}
