/*
* Licensed under the Apache License, Version 2.0 (the "License");
*
* You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributions from 2013-2017 where performed either by US government
* employees, or under US Veterans Health Administration contracts.
*
* US Veterans Health Administration contributions by government employees
* are work of the U.S. Government and are not subject to copyright
* protection in the United States. Portions contributed by government
* employees are USGovWork (17USC ยง105). Not subject to copyright.
*
* Contribution by contractors to the US Veterans Health Administration
* during this period are contractually contributed under the
* Apache License, Version 2.0.
*
* See: https://www.usa.gov/government-works
*
* Contributions prior to 2013:
*
* Copyright (C) International Health Terminology Standards Development Organisation.
* Licensed under the Apache License, Version 2.0.
*
*/
package sh.isaac.model.observable;
//~--- JDK imports ------------------------------------------------------------
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.IntStream;
//~--- non-JDK imports --------------------------------------------------------
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.apache.mahout.math.map.OpenShortObjectHashMap;
import sh.isaac.api.Get;
import sh.isaac.api.LookupService;
import sh.isaac.api.chronicle.LatestVersion;
import sh.isaac.api.chronicle.ObjectChronology;
import sh.isaac.api.commit.ChronologyChangeListener;
import sh.isaac.api.commit.CommitRecord;
import sh.isaac.api.commit.CommitStates;
import sh.isaac.api.commit.CommittableComponent;
import sh.isaac.api.component.concept.ConceptChronology;
import sh.isaac.api.component.sememe.SememeChronology;
import sh.isaac.api.component.sememe.version.SememeVersion;
import sh.isaac.api.coordinate.StampCoordinate;
import sh.isaac.api.identity.StampedVersion;
import sh.isaac.api.observable.ObservableChronology;
import sh.isaac.api.observable.ObservableChronologyService;
import sh.isaac.api.observable.sememe.ObservableSememeChronology;
import sh.isaac.api.observable.sememe.version.ObservableSememeVersion;
import sh.isaac.api.snapshot.calculator.RelativePositionCalculator;
import sh.isaac.model.ObjectVersionImpl;
import sh.isaac.model.observable.version.ObservableVersionImpl;
//~--- classes ----------------------------------------------------------------
/**
* The Class ObservableChronologyImpl.
*
* @author kec
* @param <OV> ofType of the observable version
* @param <C> ofType of the unobservable (base) chronicle
*/
public abstract class ObservableChronologyImpl<OV extends ObservableVersionImpl, C extends ObjectChronology<?>>
implements ObservableChronology<OV>, ChronologyChangeListener, CommittableComponent {
/** The Constant ocs. */
private static final ObservableChronologyService ocs = LookupService.getService(ObservableChronologyService.class);
//~--- fields --------------------------------------------------------------
/** The version list. */
private ObservableList<? extends OV> versionList = null;
/** The version list property. */
private ListProperty<? extends OV> versionListProperty;
/** The nid property. */
private IntegerProperty nidProperty;
/** The primordial uuid property. */
private ObjectProperty<UUID> primordialUuidProperty;
/** The uuid list property. */
private ListProperty<UUID> uuidListProperty;
/** The commit state property. */
private ObjectProperty<CommitStates> commitStateProperty;
/** The sememe list property. */
private ListProperty<ObservableSememeChronology<? extends ObservableSememeVersion<?>>> sememeListProperty;
/** The chronicled object local. */
protected C chronicledObjectLocal;
//~--- constructors --------------------------------------------------------
/**
* Instantiates a new observable chronology impl.
*
* @param chronicledObjectLocal the chronicled object local
*/
public ObservableChronologyImpl(C chronicledObjectLocal) {
this.chronicledObjectLocal = chronicledObjectLocal;
}
//~--- methods -------------------------------------------------------------
/**
* Commit state property.
*
* @return the object property
*/
@Override
public final ObjectProperty<CommitStates> commitStateProperty() {
if (this.commitStateProperty == null) {
final ObjectBinding<CommitStates> binding = new ObjectBinding<CommitStates>() {
@Override
protected CommitStates computeValue() {
if (getVersionList().stream()
.anyMatch((version) -> version.getCommitState() == CommitStates.UNCOMMITTED)) {
return CommitStates.UNCOMMITTED;
}
return CommitStates.COMMITTED;
}
};
this.commitStateProperty = new SimpleObjectProperty(this,
ObservableFields.COMMITTED_STATE_FOR_CHRONICLE.toExternalString(),
binding.get());
this.commitStateProperty.bind(binding);
}
return this.commitStateProperty;
}
/**
* Handle change.
*
* @param cc the cc
*/
@Override
public final void handleChange(ConceptChronology<? extends StampedVersion> cc) {
if (this.getNid() == cc.getNid()) {
updateChronicle((C) cc);
// update descriptions...
throw new UnsupportedOperationException();
}
}
/**
* Handle change.
*
* @param sc the sc
*/
@Override
public final void handleChange(SememeChronology<? extends SememeVersion<?>> sc) {
if (this.getNid() == sc.getNid()) {
updateChronicle((C) sc);
}
if (sc.getReferencedComponentNid() == this.getNid()) {
if (this.sememeListProperty != null) {
// check to be sure sememe is in list, if not, add it.
if (this.sememeListProperty.get()
.stream()
.noneMatch((element) -> element.getNid() == sc.getNid())) {
this.sememeListProperty.get()
.add(
(ObservableSememeChronology<? extends ObservableSememeVersion<?>>) ocs.getObservableSememeChronology(
sc.getNid()));
}
}
// else, nothing to do, since no one is looking...
}
}
/**
* Handle commit.
*
* @param commitRecord the commit record
*/
@Override
public void handleCommit(CommitRecord commitRecord) {
// TODO implement handle commit...
}
/**
* Nid property.
*
* @return the integer property
*/
@Override
public final IntegerProperty nidProperty() {
if (this.nidProperty == null) {
this.nidProperty = new CommitAwareIntegerProperty(this,
ObservableFields.NATIVE_ID_FOR_CHRONICLE.toExternalString(),
getNid());
}
return this.nidProperty;
}
/**
* Primordial uuid property.
*
* @return the object property
*/
@Override
public final ObjectProperty<UUID> primordialUuidProperty() {
if (this.primordialUuidProperty == null) {
this.primordialUuidProperty = new CommitAwareObjectProperty<>(this,
ObservableFields.PRIMORDIAL_UUID_FOR_CHRONICLE.toExternalString(),
getPrimordialUuid());
}
return this.primordialUuidProperty;
}
/**
* Sememe list property.
*
* @return the list property< observable sememe chronology<? extends observable sememe version<?>>>
*/
@Override
public final ListProperty<ObservableSememeChronology<? extends ObservableSememeVersion<?>>> sememeListProperty() {
if (this.sememeListProperty == null) {
final ObservableList<ObservableSememeChronology<? extends ObservableSememeVersion>> sememeList =
FXCollections.emptyObservableList();
Get.sememeService()
.getSememeSequencesForComponent(getNid())
.stream()
.forEach((sememeSequence) -> sememeList.add(ocs.getObservableSememeChronology(sememeSequence)));
this.sememeListProperty = new SimpleListProperty(this,
ObservableFields.SEMEME_LIST_FOR_CHRONICLE.toExternalString(),
sememeList);
}
return this.sememeListProperty;
}
/**
* To user string.
*
* @return the string
*/
@Override
public final String toUserString() {
return this.chronicledObjectLocal.toUserString();
}
/**
* Uuid list property.
*
* @return the list property
*/
@Override
public final ListProperty<UUID> uuidListProperty() {
if (this.uuidListProperty == null) {
this.uuidListProperty = new SimpleListProperty<>(this,
ObservableFields.UUID_LIST_FOR_CHRONICLE.toExternalString(),
FXCollections.observableList(getUuidList()));
}
return this.uuidListProperty;
}
/**
* Version list property.
*
* @return the list property<? extends O v>
*/
@Override
public final ListProperty<? extends OV> versionListProperty() {
if (this.versionListProperty == null) {
this.versionListProperty = new SimpleListProperty<>(this,
ObservableFields.VERSION_LIST_FOR_CHRONICLE.toExternalString(),
getVersionList());
}
return this.versionListProperty;
}
/**
* Update chronicle.
*
* @param chronicledObjectLocal the chronicled object local
*/
protected final void updateChronicle(C chronicledObjectLocal) {
this.chronicledObjectLocal = chronicledObjectLocal;
if (this.versionList != null) {
final OpenShortObjectHashMap<OV> observableVersionMap = new OpenShortObjectHashMap<>(this.versionList.size());
this.versionList.stream()
.forEach((ov) -> observableVersionMap.put(ov.getVersionSequence(), ov));
chronicledObjectLocal.getVersionList().stream().forEach((sv) -> {
final OV observableVersion =
observableVersionMap.get(((ObjectVersionImpl) sv).getVersionSequence());
if (observableVersion == null) {
// add new version to list
} else {}
});
// update versions...
throw new UnsupportedOperationException();
}
// else, nothing to do, since no one is looking...
}
;
//~--- get methods ---------------------------------------------------------
/**
* Gets the commit state.
*
* @return the commit state
*/
@Override
public final CommitStates getCommitState() {
if (this.commitStateProperty != null) {
return this.commitStateProperty.get();
}
return this.chronicledObjectLocal.getCommitState();
}
/**
* Gets the latest version.
*
* @param type the type
* @param coordinate the coordinate
* @return the latest version
*/
@Override
public Optional<LatestVersion<OV>> getLatestVersion(Class<OV> type, StampCoordinate coordinate) {
final RelativePositionCalculator calculator = RelativePositionCalculator.getCalculator(coordinate);
return calculator.getLatestVersion(this);
}
/**
* Gets the listener uuid.
*
* @return the listener uuid
*/
@Override
public final UUID getListenerUuid() {
return getPrimordialUuid();
}
/**
* Gets the nid.
*
* @return the nid
*/
@Override
public final int getNid() {
if (this.nidProperty != null) {
return this.nidProperty.get();
}
return this.chronicledObjectLocal.getNid();
}
/**
* Gets the observable version list.
*
* @return the observable version list
*/
protected abstract ObservableList<? extends OV> getObservableVersionList();
/**
* Gets the primordial uuid.
*
* @return the primordial uuid
*/
@Override
public final UUID getPrimordialUuid() {
if (this.primordialUuidProperty != null) {
return this.primordialUuidProperty.get();
}
return this.chronicledObjectLocal.getPrimordialUuid();
}
/**
* Gets the sememe list.
*
* @return the sememe list
*/
@Override
public final ObservableList<? extends ObservableSememeChronology<? extends ObservableSememeVersion<?>>> getSememeList() {
return sememeListProperty().get();
}
/**
* Gets the sememe list from assemblage.
*
* @param assemblageSequence the assemblage sequence
* @return the sememe list from assemblage
*/
@Override
public List<? extends ObservableSememeChronology<? extends SememeVersion<?>>> getSememeListFromAssemblage(
int assemblageSequence) {
throw new UnsupportedOperationException(
"Not supported yet."); // To change body of generated methods, choose Tools | Templates.
}
/**
* Gets the sememe list from assemblage of type.
*
* @param <SV> the generic type
* @param assemblageSequence the assemblage sequence
* @param type the type
* @return the sememe list from assemblage of type
*/
@Override
public <SV extends ObservableSememeVersion> List<? extends ObservableSememeChronology<SV>> getSememeListFromAssemblageOfType(
int assemblageSequence,
Class<SV> type) {
throw new UnsupportedOperationException(
"Not supported yet."); // To change body of generated methods, choose Tools | Templates.
}
/**
* Gets the uuid list.
*
* @return the uuid list
*/
@Override
public final List<UUID> getUuidList() {
return this.chronicledObjectLocal.getUuidList();
}
/**
* Gets the version list.
*
* @return the version list
*/
@Override
public final ObservableList<? extends OV> getVersionList() {
if (this.versionListProperty != null) {
return this.versionListProperty.get();
}
if (this.versionList == null) {
this.versionList = getObservableVersionList();
}
return this.versionList;
}
/**
* Gets the version stamp sequences.
*
* @return the version stamp sequences
*/
@Override
public final IntStream getVersionStampSequences() {
return this.chronicledObjectLocal.getVersionStampSequences();
}
}