package org.codefx.libfx.nesting;
import java.util.Optional;
import javafx.beans.Observable;
import javafx.beans.property.ReadOnlyProperty;
import javafx.beans.value.ObservableValue;
/**
* <p>
* A nesting encapsulates a hierarchy of nested {@link ObservableValue ObservableValues}.
* <p>
* Its {@link #innerObservableProperty() innerObservable} property always contains the current innermost
* {@code Observable} in that hierarchy as an {@link Optional}. A {@code Nesting} can be used as a basic building block
* for other nested functionality.
* <h2>Nesting Hierarchy</h2> A nesting hierarchy is composed of some {@code ObservableValues}, often simply called
* <b>observables</b>, and <b>nesting steps</b> which lead from one observable to the next.
* <p>
* At the top of the hierarchy stands one of the observables, the so called <b>outer observable</b>. A nesting step will
* use its value to return the next observable. The next step will use that observable's value to return the next
* observable and so on. All observables returned by nesting steps are called <b>nested observables</b>. Finally and
* perhaps most importantly, the last step will lead to the hierarchy's <b>inner observable</b>.
* <p>
* As nesting steps require a value to be accessible, all observables on which a step is used must provide a value.
* Hence they must all implement {@link ObservableValue ObservableValue}. No step is used on the inner observable so it
* suffices that it implements {@link Observable}.
* <h3>Example</h3> Consider a class {@code Employee} which has an {@code Property<Address> address}, where
* {@code Address} has a {@code StringProperty streetName}. There might be a {@code Property<Employee> currentEmployee},
* which always holds the current employee.
* <p>
* In this case the hierarchy would be {@code currentEmployee -> address -> streetName} where {@code currentEmployee} is
* the outer observable and {@code address} and {@code streetName} are nested observables. Additionally,
* {@code streetName} is the inner observable.
* <h2>Present or Missing Inner Observable</h2> If all steps return non-null observables and none of them contains null,
* the inner observable can be accessed and will be contained in the {@link #innerObservableProperty() innerObservable}
* property. In this case it is said to be <b>present</b>. The same is true if only the inner observable contains null.
* <p>
* If any nesting step returns null or any observable except the inner contains null as a value, the nesting hierarchy
* can not be fully accessed. The inner observable is said to be <b>missing</b> and the {@code innerObservable} property
* contains {@link Optional#empty()}.
* <h2>Evaluation</h2> Nestings will usually be implemented such that they eagerly evaluate the nested observables.
* <h2>Build</h2> Instances of {@code Nesting} can be created with dedicated builders. These can be obtained by starting
* with one of the methods in {@link Nestings}. More details can be found there.
* <p>
* Nestings are also an important building block for creating other nested instances like
* {@link org.codefx.libfx.nesting.property.NestedProperty NestedProperty}. A
* {@link org.codefx.libfx.nesting.NestingObserver NestingObserver} provides a convenient way to work directly with a
* {@code Nesting}.
*
* @see Nestings
* @param <O>
* the type of the nesting hierarchy's inner {@link Observable}
*/
public interface Nesting<O extends Observable> {
/**
* A property holding the current inner observable in the hierarchy as an optional. If some observable or its value
* were null, this contains {@link Optional#empty()}.
*
* @return the inner {@link Observable} in an {@link Optional}
*/
ReadOnlyProperty<Optional<O>> innerObservableProperty();
}