/*
 *
 *  Copyright (C) 2023 Andrew Gegg
 *
 * 	This file is part of the Gardeners Notebook application
 *
 *  The Gardeners Notebook application is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/gpl.html>.
 *
 *
 */

/*
	Change log

	3.2.1   Support fetch by location
	        Support fetch with from/to dates.
*/

package uk.co.gardennotebook.fxbean;

import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.EntryMessage;
import uk.co.gardennotebook.spi.*;
import uk.co.gardennotebook.util.StoryLineTree;

import java.time.LocalDate;
import java.util.List;

/**
 *	Storyline events for a given PlantSpecies or PlantVarieties of the SAME species for comparison.
 *
 *	@author	Andy Gegg
 *	@version	3.2.1
 *	@since	3.2.0
 */
final public class LifecycleAnalysisBean
{
    private static final Logger LOGGER = LogManager.getLogger();

    private ILifecycleAnalysis baseItem = null;

    private final ReadOnlyObjectWrapper<NotebookEntryType> childTypeProperty = new ReadOnlyObjectWrapper<>(this, "childType", null);
    private final ReadOnlyObjectWrapper<NotebookEntryType> ancestorTypeProperty = new ReadOnlyObjectWrapper<>(this, "ancestorType", null);

    private final ReadOnlyObjectWrapper<HusbandryBean> ancestorHusbandryProperty = new ReadOnlyObjectWrapper<>(this, "ancestorHusbandry", null);
    private final ReadOnlyBooleanWrapper hasAncestorHusbandryProperty = new ReadOnlyBooleanWrapper(this, "hasAncestorHusbandry", false);
    private final ReadOnlyObjectWrapper<GroundworkBean> ancestorGroundworkProperty = new ReadOnlyObjectWrapper<>(this, "ancestorGroundwork", null);
    private final ReadOnlyBooleanWrapper hasAncestorGroundworkProperty = new ReadOnlyBooleanWrapper(this, "hasAncestorGroundwork", false);
    private final ReadOnlyObjectWrapper<AfflictionEventBean> ancestorAfflictionEventProperty = new ReadOnlyObjectWrapper<>(this, "ancestorAfflictionEvent", null);
    private final ReadOnlyBooleanWrapper hasAncestorAfflictionEventProperty = new ReadOnlyBooleanWrapper(this, "hasAncestorAfflictionEvent", false);

    /*
    *	Always required as Lifecycle always refers to a plant.
The activity is for plants of this species.
@apiNote
plantVarietyId may or may not be given; if absent the activity is for all (current) e.g. tomato varieties, e.g. for spraying.
This 'denormalises' the model but enables easy searches for e.g. 'all tomatoes'
    */
    private final ReadOnlyObjectWrapper<PlantSpeciesBean> parentPlantSpeciesProperty = new ReadOnlyObjectWrapper<>(this, "plantSpecies", null);

    /*
    *	The activity is for plants of this variety.
@apiNote
If present, plantSpeciesId must be given.  This 'denormalises' the model but enables easy searches for e.g. 'all tomatoes'
    */
    private final ReadOnlyObjectWrapper<PlantVarietyBean> parentPlantVarietyProperty = new ReadOnlyObjectWrapper<>(this, "plantVariety", null);
    private final ReadOnlyBooleanWrapper hasParentPlantVarietyProperty = new ReadOnlyBooleanWrapper(this, "hasPlantVariety", false);

    private final ReadOnlyObjectWrapper<LocationBean> parentLocationProperty = new ReadOnlyObjectWrapper<>(this, "location", null);
    private final ReadOnlyBooleanWrapper hasParentLocationProperty = new ReadOnlyBooleanWrapper(this, "hasLocation", false);

    private final ReadOnlyObjectWrapper<HusbandryBean> parentHusbandryProperty = new ReadOnlyObjectWrapper<>(this, "husbandry", null);
    private final ReadOnlyBooleanWrapper hasParentHusbandryProperty = new ReadOnlyBooleanWrapper(this, "hasHusbandry", false);

    private final ReadOnlyObjectWrapper<AfflictionEventBean> parentAfflictionEventProperty = new ReadOnlyObjectWrapper<>(this, "afflictionEvent", null);
    private final ReadOnlyBooleanWrapper hasParentAfflictionEventProperty = new ReadOnlyBooleanWrapper(this, "hasAfflictionEvent", false);

    private final ReadOnlyObjectWrapper<GroundworkBean> parentGroundworkProperty = new ReadOnlyObjectWrapper<>(this, "groundwork", null);
    private final ReadOnlyBooleanWrapper hasParentGroundworkProperty = new ReadOnlyBooleanWrapper(this, "hasGroundwork", false);

    private final ReadOnlyObjectWrapper<LocalDate> dateProperty = new ReadOnlyObjectWrapper<>(this, "date", LocalDate.now());

//    private final ReadOnlyIntegerWrapper weekOfYearProperty = new ReadOnlyIntegerWrapper(this, "weekOfYear", 0);

//    private final ReadOnlyStringWrapper monthOfYearProperty = new ReadOnlyStringWrapper(this, "month", ""); //  Localised text

    private final ReadOnlyIntegerWrapper monthNumberProperty = new ReadOnlyIntegerWrapper(this, "monthNumber", 0);  // 1 to 12

    private final IntegerProperty indexedMonthProperty = new ReadOnlyIntegerWrapper(this, "indexedMonth", 0);

//    private final ReadOnlyIntegerWrapper dayOfMonthProperty = new ReadOnlyIntegerWrapper(this, "dayOfMonth", 0);    // 1 to 31

    private final ReadOnlyIntegerWrapper yearProperty = new ReadOnlyIntegerWrapper(this, "year", -1);

    public LifecycleAnalysisBean(final ILifecycleAnalysis initialValue)
    {
        LOGGER.debug("constructor: initialValue: {}", initialValue);
        baseItem = initialValue;

        setValues();

    }

    /**
     * Return a list of Lifecycle events for all storylines which cross this Location and only those.
     *
      * @param loc  the Location to match
     * @return  a list of Lifecycle events
     * @throws GNDBException
     */
    public  static ObservableList<LifecycleAnalysisBean> fetch(LocationBean loc) throws GNDBException
    {
        if (loc == null)
        {
            return FXCollections.emptyObservableList();
        }
        return fetch(null, null, loc);
    }

    /**
     * Return a list of Lifecycle events for all storylines for this plant species and variety and only those.
     *
     * @param ps  the plant species to match, if null only the plant variety specified
     * @param pv the plant variety to match, if null all varieties for the species.  If present, must be a variety of the plant species represented by ps.
     * @return  a list of Lifecycle events
     * @throws GNDBException
     */
    public static ObservableList<LifecycleAnalysisBean> fetch(PlantSpeciesBean ps, PlantVarietyBean pv) throws GNDBException
    {
        if (ps == null && pv == null)
        {
            return FXCollections.emptyObservableList();
        }
        return fetch(ps, pv, null);
    }

    /**
     * Return a list of Lifecycle events for all storylines for this plant species and variety which cross the given location and only those.
     *
     * @param ps  the plant species to match
     * @param pv the plant variety to match (may be null).  If present, must be a variety of the plant species represented by ps.
     * @param loc  the Location to match
     * @return  a list of Lifecycle events
     * @throws GNDBException
     */
    public static ObservableList<LifecycleAnalysisBean> fetch(PlantSpeciesBean ps, PlantVarietyBean pv, LocationBean loc) throws GNDBException
    {
        if (ps == null && pv == null && loc == null)
        {
            return FXCollections.emptyObservableList();
        }
        return fetch(ps, pv, loc, null, null);
    }

    /**
     * Return a list of Lifecycle events for all storylines matching the given criteria.
     * At least one of ps, pv, loc must be non-null.
     *
     * @param ps  the plant species to match, null to match only the given plant species or all species if a location is specified.
     * @param pv the plant variety to match, null to match all varieties of the given plant species.
     * @param loc  the Location to match, null to match all locations.
     * @param fromDate only select storylines after this date (null for no early limit)
     * @param toDate only select storylines before this date(null for no late cut-off)
     * @return  a list of Lifecycle events
     * @throws GNDBException
     */
    public static ObservableList<LifecycleAnalysisBean> fetch(PlantSpeciesBean ps, PlantVarietyBean pv, LocationBean loc, LocalDate fromDate, LocalDate toDate) throws GNDBException
    {
        EntryMessage log4jEntryMsg = LOGGER.traceEntry("fetch: ps: {}, pv: {}, loc: {}, fromDate: {}, toDate: {}", ps, pv, loc, fromDate, toDate);

        if (ps == null && pv == null && loc == null)
        {
            return FXCollections.emptyObservableList();
        }
        if ( fromDate != null && toDate != null && fromDate.isAfter(toDate))
        {
            return FXCollections.emptyObservableList();
        }

        ITrug server = TrugServer.getTrugServer().getTrug();
		ILifecycleAnalysisLister lal = server.getLifecycleAnalysisLister();
        if (ps != null)
        {
            lal.plantSpecies(ps.getValue().orElse(null));
        }
        if (pv != null)
        {
            lal.plantVariety(pv.getValue().orElse(null));
        }
//        }
        if (loc != null)
        {
            lal.location(loc.getValue().orElse(null));
        }
        if (fromDate != null)
        {
            lal.fromDate(fromDate);
        }
        if (toDate != null)
        {
            lal.toDate(toDate);
        }
        List<LifecycleAnalysisBean> ll = lal.fetch().stream().map(LifecycleAnalysisBean::new).toList();
        LOGGER.traceExit();
        return FXCollections.observableArrayList(ll);
    }

    /**
     * The underlying child item
     */
    public INotebookBean getChild()
    {
        return switch (getChildType())
        {
            case HUSBANDRY -> getHusbandry();
            case GROUNDWORK -> getGroundwork();
            case AFFLICTIONEVENT -> getAfflictionEvent();
            default -> throw new RuntimeException("unknown child type: "+getChildType());
        };
    }

    /**
     * The date of the Lifecycle event.
     *
     * @return  The date of the Lifecycle event.
     */
    public LocalDate getDate()
    {
        return dateProperty().get();
    }
    public ReadOnlyObjectProperty<LocalDate> dateProperty()
    {
        return dateProperty.getReadOnlyProperty();
    }

//    /**
//     * The name of the month of the year in which the Lifecycle event occurred; this ignores the actual year.
//     * Localised text.
//     *
//     * @return  The name of the month of the year in which the Lifecycle event occurred.
//     */
//    public String getMonthOfYear()
//    {
//        return monthOfYearProperty().get();
//    }
//    public ReadOnlyStringProperty monthOfYearProperty()
//    {
//        return monthOfYearProperty.getReadOnlyProperty();
//    }

    /**
     * The number of the month of the year in which the Lifecycle event occurred; this ignores the actual year.
     * 1 to 12
     *
     * @return  The month of the year in which the Lifecycle event occurred.
     */
    public int getMonthNumber()
    {
        return monthNumberProperty().get();
    }
    public ReadOnlyIntegerProperty monthNumberProperty()
    {
        return monthNumberProperty.getReadOnlyProperty();
    }

    /**
     * The indexed number of the month in which the Lifecycle event occurred.
     * The indexed month allows for histories which cross over a year boundary, so a story starting in September and
     * continuing to the following March would span indexed months 10, 11, 12, 13 (January+12), 14, 15.
     *
     * @return  The indexed month of the year in which the Lifecycle event occurred.
     */
    public int getIndexedMonth()
    {
        return indexedMonthProperty().get();
    }
    public IntegerProperty indexedMonthProperty()
    {
        return indexedMonthProperty;
    }

    public void setIndexedMonth(int indexedMonth)
    {
        int testMonth = indexedMonth%12;    //  December%12 -> 0 which is not a valid month number
        if (testMonth == 0) testMonth = 12;
//        if (indexedMonth%12 != getMonthNumber())
        if (testMonth != getMonthNumber())
        {
            throw new IllegalArgumentException("indexed month != month");
        }
        indexedMonthProperty().set(indexedMonth);
    }

    /**
     * The day of the month in which the Lifecycle event occurred; this ignores the actual year and month.
     * 1 to 31
     *
     * @return  The day of the month in which the Lifecycle event occurred.
     */
//    public int getDayOfMonth()
//    {
//        return dayOfMonthProperty().get();
//    }
//    public ReadOnlyIntegerProperty dayOfMonthProperty()
//    {
//        return dayOfMonthProperty.getReadOnlyProperty();
//    }

    /**
     * The year in which the Lifecycle event occurred.
     *
     * @return  The year in which the Lifecycle event occurred.
     */
    public int getYear()
    {
        return yearProperty().get();
    }
    public ReadOnlyIntegerProperty yearProperty()
    {
        return yearProperty.getReadOnlyProperty();
    }

    /**
     * Which type of Lifecycle event was the start of the storyline?
     * Husbandry (most usually), Groundwork or Affliction Event (improbable).
     *
      * @return The root Lifecycle event type
     */
    public NotebookEntryType getAncestorType()
    {
        return ancestorTypeProperty().get();
    }
    public ReadOnlyObjectProperty<NotebookEntryType> ancestorTypeProperty()
    {
        return ancestorTypeProperty.getReadOnlyProperty();
    }

    /**
     *	Use this to check if the Husbandry parent of the originating Husbandry for this storyline can be retrieved.
     *  If the ancestorType is Husbandry, this must be available
     *
     *	@return	true if this Analysis is linked to a Husbandry root
     */
    public ReadOnlyBooleanProperty hasAncestorHusbandryProperty()
    {
        return hasAncestorHusbandryProperty.getReadOnlyProperty();
    }
    public HusbandryBean getAncestorHusbandry()
    {
        return ancestorHusbandryProperty().get();
    }
    public ReadOnlyObjectProperty<HusbandryBean> ancestorHusbandryProperty()
    {
        return ancestorHusbandryProperty.getReadOnlyProperty();
    }

    /**
     *	Use this to check if the AfflictionEvent parent of the originating AfflictionEvent for this storyline can be retrieved.
     *  If the ancestorType is AfflictionEvent, this must be available
     *
     *	@return	true if this Analysis is linked to a AfflictionEvent root
     */
    public ReadOnlyBooleanProperty hasAncestorAfflictionEventProperty()
    {
        return hasAncestorAfflictionEventProperty.getReadOnlyProperty();
    }
    public AfflictionEventBean getAncestorAfflictionEvent()
    {
        return ancestorAfflictionEventProperty().get();
    }
    public ReadOnlyObjectProperty<AfflictionEventBean> ancestorAfflictionEventProperty()
    {
        return ancestorAfflictionEventProperty.getReadOnlyProperty();
    }

    /**
     *	Use this to check if the Groundwork parent of the originating Groundwork for this storyline can be retrieved.
     *  If the ancestorType is Groundwork, this must be available
     *
     *	@return	true if this Analysis is linked to a Groundwork root
     */
    public ReadOnlyBooleanProperty hasAncestorGroundworkProperty()
    {
        return hasAncestorGroundworkProperty.getReadOnlyProperty();
    }
    public GroundworkBean getAncestorGroundwork()
    {
        return ancestorGroundworkProperty().get();
    }
    public ReadOnlyObjectProperty<GroundworkBean> ancestorGroundworkProperty()
    {
        return ancestorGroundworkProperty.getReadOnlyProperty();
    }

    /**
     * Compare two LifecycleAnalysisBean to check if they have the same ancestor
     *
     * @param item  the bean to compare with this bean.
     * @return  true if they have the same ancestor
     */
    public boolean hasSameAncestor(LifecycleAnalysisBean item)
    {
        if (item.getAncestorType() != baseItem.ancestorType())
        {
//            LOGGER.debug("different types");
            return false;
        }
        return switch (this.getAncestorType())
        {
            case null -> false;
            case HUSBANDRY -> item.getAncestorHusbandry().sameAs(this.getAncestorHusbandry());
            case GROUNDWORK -> item.getAncestorGroundwork().sameAs(this.getAncestorGroundwork());
            case AFFLICTIONEVENT -> item.getAncestorAfflictionEvent().sameAs(this.getAncestorAfflictionEvent());
            default -> throw new IllegalArgumentException("baseItem type unknown: "+baseItem);
        };
    }

    /**
     * Which type of Lifecycle event is the current activity?
     * Husbandry (most usually), Groundwork or Affliction Event.
     *
     * @return The current Lifecycle event type
     */
    public NotebookEntryType getChildType()
    {
        return childTypeProperty().get();
    }
    public ReadOnlyObjectProperty<NotebookEntryType> childTypeProperty()
    {
        return childTypeProperty.getReadOnlyProperty();
    }

    /**
     *	Use this to check if the Husbandry parent of the Analysis this Bean wraps is present
     *
     *	@return	true if this Analysis is linked to a Husbandry
     */
    public boolean hasHusbandry()
    {
        return hasHusbandryProperty().getValue();
    }
    public ReadOnlyBooleanProperty hasHusbandryProperty()
    {
        return hasParentHusbandryProperty.getReadOnlyProperty();
    }
    public HusbandryBean getHusbandry()
    {
        return husbandryProperty().get();
    }
    public ReadOnlyObjectProperty<HusbandryBean> husbandryProperty()
    {
        return parentHusbandryProperty.getReadOnlyProperty();
    }

    /**
     *	Use this to check if the AfflictionEvent parent of the Analysis this Bean wraps is present
     *
     *	@return	true if this Analysis is linked to an AfflictionEvent
     */
    public boolean hasAfflictionEvent()
    {
        return hasAfflictionEventProperty().getValue();
    }
    public ReadOnlyBooleanProperty hasAfflictionEventProperty()
    {
        return hasParentAfflictionEventProperty.getReadOnlyProperty();
    }
    public AfflictionEventBean getAfflictionEvent()
    {
        return afflictionEventProperty().get();
    }
    public ReadOnlyObjectProperty<AfflictionEventBean> afflictionEventProperty()
    {
        return parentAfflictionEventProperty.getReadOnlyProperty();
    }

    /**
     *	Use this to check if the Groundwork parent of the Analysis this Bean wraps is present
     *
     *	@return	true if this Analysis is linked to a Groundwork
     */
    public boolean hasGroundwork()
    {
        return hasGroundworkProperty().getValue();
    }
    public ReadOnlyBooleanProperty hasGroundworkProperty()
    {
        return hasParentGroundworkProperty.getReadOnlyProperty();
    }
    public GroundworkBean getGroundwork()
    {
        return groundworkProperty().get();
    }
    public ReadOnlyObjectProperty<GroundworkBean> groundworkProperty()
    {
        return parentGroundworkProperty.getReadOnlyProperty();
    }


    /**
     * The PlantSpecies of the current Lifecycle event.  Must be present.
     *
      * @return The PlantSpecies
     */
    public PlantSpeciesBean getPlantSpecies()
    {
        return plantSpeciesProperty().getValue();
    }
    public ReadOnlyObjectProperty<PlantSpeciesBean> plantSpeciesProperty()
    {
        return parentPlantSpeciesProperty.getReadOnlyProperty();
    }


    /**
     * Use this to check if a PlantVariety is present.
     *
     * @return True if there is a PlantVariety specified on this Lifecycle event.
     */
    public boolean hasPlantVariety()
    {
        return hasPlantVarietyProperty().getValue();
    }
    public ReadOnlyBooleanProperty hasPlantVarietyProperty()
    {
        return hasParentPlantVarietyProperty.getReadOnlyProperty();
    }
    public PlantVarietyBean getPlantVariety()
    {
        return plantVarietyProperty().getValue();
    }
    /**
     *	Returns the PlantVariety parent of the Lifecycle ANalysis this Bean wraps
     *	Call hasPlantVariety() first to check if this value is set
     *
     *	@return	the PlantVariety parent of the Husbandry this Bean wraps
     */
    public ReadOnlyObjectProperty<PlantVarietyBean> plantVarietyProperty()
    {
        return parentPlantVarietyProperty.getReadOnlyProperty();
    }

    /**
     * Use this to check if a Location is present.
     *
     * @return True if there is a Location specified on this Lifecycle event.
     */
    public boolean hasLocation()
    {
        return hasLocationProperty().getValue();
    }
    public ReadOnlyBooleanProperty hasLocationProperty()
    {
        return hasParentLocationProperty.getReadOnlyProperty();
    }
    /**
     * The location (if known) of the event.
     *
     * @return  the Location
     */
    public LocationBean getLocation()
    {
        return locationProperty().getValue();
    }
    public ReadOnlyObjectProperty<LocationBean> locationProperty()
    {
        return parentLocationProperty.getReadOnlyProperty();
    }

    public boolean isTargetLocation()
    {
        return baseItem.targetLocation();
    }


    public boolean hasAncestor()
    {
        boolean hasAncestor = false;
        try
        {
            hasAncestor = switch (getChildType())
            {
                case HUSBANDRY -> getHusbandry().hasAncestor();
                case AFFLICTIONEVENT -> getAfflictionEvent().hasAncestor();
                case GROUNDWORK -> getGroundwork().hasAncestor();
                default -> throw new RuntimeException("unknown item type: " + getChildType());
            };
        }
        catch (GNDBException e)
        {
            throw new RuntimeException(e);
        }

        return hasAncestor;
    }

    public StoryLineTree<? extends INotebookBean> getAncestors() throws GNDBException
    {
        EntryMessage log4jEntryMsg = LOGGER.traceEntry("getAncestors()");
        if (baseItem == null)
        {
            return StoryLineTree.emptyTree();
        }
        if (!hasAncestor())
        {
            return StoryLineTree.emptyTree();
        }
        StoryLineTree<? extends INotebookBean> beanTree = getChild().getAncestors();
        return LOGGER.traceExit(log4jEntryMsg, beanTree);
    }	//	getAncestors()

    public boolean hasDescendant()
    {
        boolean hasDescendant = false;
        try
        {
            hasDescendant = switch (getChildType())
            {
                case HUSBANDRY -> getHusbandry().hasDescendant();
                case AFFLICTIONEVENT -> getAfflictionEvent().hasDescendant();
                case GROUNDWORK -> getGroundwork().hasDescendant();
                default -> throw new RuntimeException("unknown item type: " + getChildType());
            };
        }
        catch (GNDBException e)
        {
            throw new RuntimeException(e);
        }

        return hasDescendant;
    }

    public StoryLineTree<? extends INotebookBean> getDescendants() throws GNDBException
    {
        EntryMessage log4jEntryMsg = LOGGER.traceEntry("getDescendants()");
        if (baseItem == null)
        {
            return StoryLineTree.emptyTree();
        }
        StoryLineTree<? extends INotebookBean> beanTree = getChild().getDescendants();
        return LOGGER.traceExit(log4jEntryMsg, beanTree);
    }	//	getDescendants()

    private void setValues()
    {
//        ancestorHusbandryProperty.setValue(new HusbandryBean(baseItem.ancestorHusbandry()));
        ancestorTypeProperty.set(baseItem.ancestorType());
        switch(baseItem.ancestorType())
        {
            case null -> {}
            case HUSBANDRY -> {
                ancestorHusbandryProperty.setValue(new HusbandryBean(baseItem.ancestorHusbandry().get()));
                hasAncestorHusbandryProperty.set(true);
            }
            case GROUNDWORK -> {
                ancestorGroundworkProperty.setValue(new GroundworkBean(baseItem.ancestorGroundwork().get()));
                hasAncestorGroundworkProperty.set(true);
            }
            case AFFLICTIONEVENT -> {
                ancestorAfflictionEventProperty.setValue(new AfflictionEventBean(baseItem.ancestorAfflictionEvent().get()));
                hasAncestorAfflictionEventProperty.set(true);
            }
            default -> {}
        }
        parentPlantSpeciesProperty.setValue(new PlantSpeciesBean(baseItem.plantSpecies()));
        if (baseItem.plantVariety().isPresent())
        {
            hasParentPlantVarietyProperty.set(true);
            parentPlantVarietyProperty.setValue(new PlantVarietyBean(baseItem.plantVariety().get()));
        }
        else
        {
            hasParentPlantVarietyProperty.set(false);
            parentPlantVarietyProperty.setValue(null);
        }

        if (baseItem.location().isPresent())
        {
            hasParentLocationProperty.set(true);
            parentLocationProperty.setValue(new LocationBean(baseItem.location().get()));
        }
        else
        {
            hasParentLocationProperty.set(false);
            parentLocationProperty.setValue(null);
        }

        childTypeProperty.set(baseItem.childType());
        switch(baseItem.childType())
        {
            case HUSBANDRY -> {
                parentHusbandryProperty.setValue(new HusbandryBean(baseItem.husbandry().get()));
                hasParentHusbandryProperty.set(true);
            }
            case GROUNDWORK -> {
                parentGroundworkProperty.setValue(new GroundworkBean(baseItem.groundwork().get()));
                hasParentGroundworkProperty.set(true);
            }
            case AFFLICTIONEVENT -> {
                parentAfflictionEventProperty.setValue(new AfflictionEventBean(baseItem.afflictionEvent().get()));
                hasParentAfflictionEventProperty.set(true);
            }
            default -> {}
        }
//        dateProperty.setValue(baseItem.date());
        LocalDate date = baseItem.date();
        dateProperty.setValue(date);
        /* Thanks to Meno Hochschild:
        * https://stackoverflow.com/questions/26012434/get-week-number-of-localdate-java-8
         */
//        TemporalField woy = WeekFields.of(Locale.getDefault()).weekOfWeekBasedYear();
//        weekOfYearProperty.set(date.get(woy));
//        monthOfYearProperty.setValue(date.getMonth().getDisplayName(TextStyle.SHORT, Locale.getDefault()));
        monthNumberProperty.setValue(date.getMonthValue());
//        dayOfMonthProperty.setValue(date.getDayOfMonth());
        yearProperty.setValue(date.getYear());

    }

    public String toString()
    {
        return "LifecycleAnalysisBean wrapping " + baseItem;
    }

}
