/* FichothequeLib_Xml - Copyright (c) 2021-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.xml.storage;

import java.io.IOException;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.fiche.DateItem;
import net.fichotheque.corpus.fiche.EmailItem;
import net.fichotheque.corpus.fiche.FicheItem;
import net.fichotheque.corpus.fiche.FicheItems;
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.AmountItem;
import net.fichotheque.corpus.fiche.NumberItem;
import net.fichotheque.corpus.fiche.ParaItem;
import net.fichotheque.corpus.fiche.CountryItem;
import net.fichotheque.corpus.fiche.PersonItem;
import net.fichotheque.utils.SphereUtils;
import net.mapeadores.util.models.EmailCore;
import net.mapeadores.util.models.PersonCore;
import net.mapeadores.util.primitives.Decimal;
import net.mapeadores.util.primitives.DegreDecimal;
import net.mapeadores.util.primitives.FuzzyDate;
import net.mapeadores.util.xml.XMLPart;
import net.mapeadores.util.xml.XMLWriter;


/**
 *
 * @author Vincent Calame
 */
public class FicheItemStorageXMLPart extends XMLPart {

    private final FicheBlockStorageXMLPart ficheBlockStorageXMLPart;

    public FicheItemStorageXMLPart(XMLWriter xmlWriter) {
        super(xmlWriter);
        ficheBlockStorageXMLPart = new FicheBlockStorageXMLPart(xmlWriter);
    }

    public void addFicheItems(FicheItems ficheItems) throws IOException {
        int size = ficheItems.size();
        for (int i = 0; i < size; i++) {
            addFicheItem(ficheItems.get(i), null);
        }
    }

    public void addFicheItems(FicheItems ficheItems, Object fieldOptionObject) throws IOException {
        int size = ficheItems.size();
        for (int i = 0; i < size; i++) {
            addFicheItem(ficheItems.get(i), fieldOptionObject);
        }
    }

    public void addFicheItem(FicheItem ficheItem) throws IOException {
        addFicheItem(ficheItem, null);
    }

    public void addFicheItem(FicheItem ficheItem, Object fieldOptionObject) throws IOException {
        if (ficheItem instanceof Item) {
            addItem((Item) ficheItem);
        } else if (ficheItem instanceof PersonItem) {
            addPerson((PersonItem) ficheItem);
        } else if (ficheItem instanceof DateItem) {
            addDate((DateItem) ficheItem, fieldOptionObject);
        } else if (ficheItem instanceof LanguageItem) {
            addLanguage((LanguageItem) ficheItem);
        } else if (ficheItem instanceof CountryItem) {
            addCountry((CountryItem) ficheItem);
        } else if (ficheItem instanceof LinkItem) {
            addLink((LinkItem) ficheItem, fieldOptionObject);
        } else if (ficheItem instanceof EmailItem) {
            addEmail((EmailItem) ficheItem);
        } else if (ficheItem instanceof AmountItem) {
            addAmount((AmountItem) ficheItem, fieldOptionObject);
        } else if (ficheItem instanceof NumberItem) {
            addNumber((NumberItem) ficheItem);
        } else if (ficheItem instanceof GeopointItem) {
            addGeopoint((GeopointItem) ficheItem);
        } else if (ficheItem instanceof ParaItem) {
            addPara((ParaItem) ficheItem);
        } else if (ficheItem instanceof ImageItem) {
            addImage((ImageItem) ficheItem, fieldOptionObject);
        } else {
            throw new ClassCastException("unknown instance of FicheItem = " + ficheItem.getClass().getName());
        }
    }

    public void addItem(Item item) throws IOException {
        addSimpleElement("item", item.getValue());
    }

    public void addEmail(EmailItem emailItem) throws IOException {
        EmailCore emailCore = emailItem.getEmailCore();
        String addrSpec = emailCore.getAddrSpec();
        startOpenTag("courriel");
        addAttribute("addr-spec", addrSpec);
        String realName = emailCore.getRealName();
        if (realName.length() > 0) {
            addAttribute("real-name", realName);
        }
        closeEmptyTag();
    }

    public void addDate(DateItem dateItem, Object fieldOptionObject) throws IOException {
        FuzzyDate date = dateItem.getDate();
        startOpenTag("datation");
        addAttribute("a", String.valueOf(date.getYear()));
        switch (date.getType()) {
            case FuzzyDate.HALFYEAR_TYPE:
                addAttribute("type", "s");
                addAttribute("s", String.valueOf(date.getHalfYear()));
                break;
            case FuzzyDate.QUARTER_TYPE:
                addAttribute("type", "t");
                addAttribute("t", String.valueOf(date.getQuarter()));
                break;
            case FuzzyDate.MONTH_TYPE:
                addAttribute("type", "m");
                addAttribute("m", String.valueOf(date.getMonth()));
                break;
            case FuzzyDate.DAY_TYPE:
                addAttribute("type", "j");
                addAttribute("m", String.valueOf(date.getMonth()));
                addAttribute("j", String.valueOf(date.getDay()));
                break;
            default:
                addAttribute("type", "a");
        }
        closeEmptyTag();
    }

    public void addLanguage(LanguageItem languageItem) throws IOException {
        String code = languageItem.getLang().toString();
        startOpenTag("langue");
        addAttribute("lang", code);
        closeEmptyTag();
    }

    public void addNumber(NumberItem numberItem) throws IOException {
        startOpenTag("nombre");
        Decimal decimal = numberItem.getDecimal();
        addDecimalAttributes(decimal);
        closeEmptyTag();
    }

    public void addGeopoint(GeopointItem geopointItem) throws IOException {
        startOpenTag("geopoint");
        DegreDecimal latitude = geopointItem.getLatitude();
        DegreDecimal longitude = geopointItem.getLongitude();
        addAttribute("lat", latitude.toString());
        addAttribute("lon", longitude.toString());
        closeEmptyTag();
    }

    public void addAmount(AmountItem amountItem, Object fieldOptionObject) throws IOException {
        startOpenTag("montant");
        Decimal decimal = amountItem.getDecimal();
        addDecimalAttributes(decimal);
        addAttribute("cur", amountItem.getCurrency().getCurrencyCode());
        closeEmptyTag();
    }


    private void addDecimalAttributes(Decimal decimal) throws IOException {
        String partieEntiere = decimal.getPartieEntiereString();
        String partieDecimale = decimal.getPartieDecimaleString();
        String val = (partieDecimale.length() != 0) ? partieEntiere + "." + partieDecimale : partieEntiere;
        addAttribute("val", val);
    }

    public void addLink(LinkItem linkItem, Object fieldOptionObject) throws IOException {
        startOpenTag("link");
        addAttribute("href", linkItem.getHref());
        if (linkItem.hasHrefOnly()) {
            closeEmptyTag();
        } else {
            endOpenTag();
            addSimpleElement("title", linkItem.getTitle());
            addSimpleElement("comment", linkItem.getComment());
            closeTag("link");
        }
    }

    public void addImage(ImageItem imageItem, Object fieldOptionObject) throws IOException {
        startOpenTag("image");
        addAttribute("src", imageItem.getSrc());
        if (imageItem.hasSrcOnly()) {
            closeEmptyTag();
        } else {
            endOpenTag();
            addSimpleElement("alt", imageItem.getAlt());
            addSimpleElement("title", imageItem.getTitle());
            closeTag("image");
        }
    }

    public void addCountry(CountryItem countryItem) throws IOException {
        startOpenTag("pays");
        addAttribute("country", countryItem.getCountry().toString());
        closeEmptyTag();
    }


    public void addPerson(PersonItem personItem) throws IOException {
        startOpenTag("personne");
        String redacteurGlobalId = personItem.getRedacteurGlobalId();
        if (redacteurGlobalId != null) {
            try {
                SubsetKey sphereKey = SphereUtils.getSubsetKey(redacteurGlobalId);
                int id = SphereUtils.getId(redacteurGlobalId);
                addAttribute("sphere", sphereKey.getSubsetName());
                addAttribute("id", String.valueOf(id));
                closeEmptyTag();
            } catch (java.text.ParseException pe) {
                closeEmptyTag();
            }
        } else {
            endOpenTag();
            addPersonCore(personItem.getPersonCore());
            addSimpleElement("organism", personItem.getOrganism());
            closeTag("personne");
        }
    }

    private void addPersonCore(PersonCore personCore) throws IOException {
        String surname = personCore.getSurname();
        boolean surnameFirst = personCore.isSurnameFirst();
        if (surname.length() > 0) {
            startOpenTag("surname");
            if (surnameFirst) {
                addAttribute("surname-first", "true");
            }
            endOpenTag();
            addText(surname);
            closeTag("surname", false);
        }
        addSimpleElement("forename", personCore.getForename());
        addSimpleElement("nonlatin", personCore.getNonlatin());
    }

    public void addPara(ParaItem paraItem) throws IOException {
        startOpenTag("para");
        endOpenTag();
        ficheBlockStorageXMLPart.addTextContent(paraItem);
        closeTag("para", false);
    }

}
