/*
* 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.mapping.data;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
//~--- non-JDK imports --------------------------------------------------------
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sh.isaac.api.Get;
import sh.isaac.api.component.sememe.version.DynamicSememe;
import sh.isaac.api.component.sememe.version.dynamicSememe.DynamicSememeData;
import sh.isaac.api.component.sememe.version.dynamicSememe.dataTypes.DynamicSememeUUID;
import sh.isaac.api.coordinate.EditCoordinate;
import sh.isaac.api.coordinate.StampCoordinate;
import sh.isaac.api.util.StringUtils;
import sh.isaac.utility.Frills;
//~--- classes ----------------------------------------------------------------
/**
* {@link MappingItem}.
*
* @author <a href="mailto:daniel.armbrust.list@gmail.com">Dan Armbrust</a>
*/
public class MappingItem
extends MappingObject {
/** The Constant LOG. */
private static final Logger LOG = LoggerFactory.getLogger(MappingItem.class);
/** The Constant NO_MAP_NAME. */
private static final String NO_MAP_NAME = "(not mapped)";
/** The Constant sourceComparator. */
public static final Comparator<MappingItem> sourceComparator =
(o1, o2) -> StringUtils.compareStringsIgnoreCase(o1.getSourceConceptProperty()
.get(),
o2.getSourceConceptProperty()
.get());
/** The Constant targetComparator. */
public static final Comparator<MappingItem> targetComparator =
(o1, o2) -> StringUtils.compareStringsIgnoreCase(o1.getTargetConceptProperty()
.get(),
o2.getTargetConceptProperty()
.get());
/** The Constant qualifierComparator. */
public static final Comparator<MappingItem> qualifierComparator =
(o1, o2) -> StringUtils.compareStringsIgnoreCase(o1.getQualifierConceptProperty()
.get(),
o2.getQualifierConceptProperty()
.get());
//~--- fields --------------------------------------------------------------
/** The lazy load complete. */
private transient boolean lazyLoadComplete = false;
/** The source concept property. */
private transient final SimpleStringProperty sourceConceptProperty = new SimpleStringProperty();
/** The target concept property. */
private transient final SimpleStringProperty targetConceptProperty = new SimpleStringProperty();
/** The qualifier concept property. */
private transient final SimpleStringProperty qualifierConceptProperty = new SimpleStringProperty();
/** The comments property. */
private transient final SimpleStringProperty commentsProperty = new SimpleStringProperty();
/** The uuids. */
private List<UUID> uuids;
/** The mapping set sequence. */
private int sourceConceptNid, mappingSetSequence;
/** The target concept. */
private UUID qualifierConcept, targetConcept;
/** The data. */
private DynamicSememeData[] data;
/** The source concept. */
private transient UUID mappingSetIDConcept, sourceConcept;
/** The qualifier concept nid. */
private transient int targetConceptNid, qualifierConceptNid;
//~--- constructors --------------------------------------------------------
/**
* Instantiates a new mapping item.
*
* @param sememe the sememe
* @throws RuntimeException the runtime exception
*/
protected MappingItem(DynamicSememe<?> sememe)
throws RuntimeException {
read(sememe);
}
//~--- methods -------------------------------------------------------------
/**
* Add a comment to this mapping set.
*
* @param commentText - the text of the comment
* @param stampCoord the stamp coord
* @param editCoord the edit coord
* @return - the added comment
* @throws IOException Signals that an I/O exception has occurred.
*/
public MappingItemComment addComment(String commentText,
StampCoordinate stampCoord,
EditCoordinate editCoord)
throws IOException {
// TODO do we want to utilize the other comment field (don't have to)
return MappingItemCommentDAO.createMappingItemComment(this.getPrimordialUUID(),
commentText,
null,
stampCoord,
editCoord);
}
/**
* Refresh comments property.
*
* @param stampCoord the stamp coord
*/
public void refreshCommentsProperty(StampCoordinate stampCoord) {
Get.workExecutors().getExecutor().execute(() -> {
final StringBuilder commentValue = new StringBuilder();
try {
final List<MappingItemComment> comments = getComments(stampCoord);
if (comments.size() > 0) {
commentValue.append(comments.get(0)
.getCommentText());
}
if (comments.size() > 1) {
commentValue.append(" (+" + Integer.toString(comments.size() - 1) + " more)");
}
} catch (final IOException e) {
LOG.error("Error reading comments!", e);
}
Platform.runLater(() -> {
this.commentsProperty.set(commentValue.toString());
});
});
}
/**
* Lazy load.
*/
private void lazyLoad() {
if (!this.lazyLoadComplete) {
this.mappingSetIDConcept = Get.identifierService()
.getUuidPrimordialForNid(this.mappingSetSequence)
.get();
setSourceConcept(Get.identifierService()
.getUuidPrimordialForNid(this.sourceConceptNid)
.get());
// TODO remove this
setEditorStatusConcept((((this.data != null) &&
(this.data.length > 2) &&
(this.data[2] != null)) ? ((DynamicSememeUUID) this.data[2]).getDataUUID()
: null));
this.targetConceptNid = getNidForUuidSafe(this.targetConcept);
this.qualifierConceptNid = getNidForUuidSafe(this.qualifierConcept);
}
this.lazyLoadComplete = true;
}
/**
* Read.
*
* @param sememe the sememe
* @throws RuntimeException the runtime exception
*/
private void read(DynamicSememe<?> sememe)
throws RuntimeException {
readStampDetails(sememe);
this.mappingSetSequence = sememe.getAssemblageSequence();
this.sourceConceptNid = sememe.getReferencedComponentNid();
this.uuids = sememe.getUuidList();
this.data = sememe.getData();
setTargetConcept((((this.data != null) &&
(this.data.length > 0) &&
(this.data[0] != null)) ? ((DynamicSememeUUID) this.data[0]).getDataUUID()
: null));
setQualifierConcept((((this.data != null) &&
(this.data.length > 1) &&
(this.data[1] != null)) ? ((DynamicSememeUUID) this.data[1]).getDataUUID()
: null));
}
//~--- get methods ---------------------------------------------------------
/**
* Gets the comments.
*
* @param stampCoord the stamp coord
* @return Any comments attached to this mapping set.
* @throws IOException Signals that an I/O exception has occurred.
*/
public List<MappingItemComment> getComments(StampCoordinate stampCoord)
throws IOException {
return MappingItemCommentDAO.getComments(getPrimordialUUID(), stampCoord);
}
/**
* Gets the comments property.
*
* @param stampCoord the stamp coord
* @return the comments property
*/
public SimpleStringProperty getCommentsProperty(StampCoordinate stampCoord) {
refreshCommentsProperty(stampCoord);
return this.sourceConceptProperty;
}
/**
* Gets the map set sequence.
*
* @return the map set sequence
*/
public int getMapSetSequence() {
return this.mappingSetSequence;
}
/**
* Gets the mapping set ID concept.
*
* @return the mapping set ID concept
*/
public UUID getMappingSetIDConcept() {
lazyLoad();
return this.mappingSetIDConcept;
}
/**
* Gets the primordial UUID.
*
* @return the primordialUUID of this Mapping Item. Note that this doesn't uniquely identify a mapping item within the system
* as changes to the mapping item will retain the same ID - there will now be multiple versions. They will differ by date.
*/
public UUID getPrimordialUUID() {
return this.uuids.get(0);
}
/**
* Gets the qualifier concept.
*
* @return the qualifier concept
*/
public UUID getQualifierConcept() {
return this.qualifierConcept;
}
//~--- set methods ---------------------------------------------------------
/**
* Sets the qualifier concept.
*
* @param qualifierConcept the new qualifier concept
*/
private void setQualifierConcept(UUID qualifierConcept) {
this.qualifierConcept = qualifierConcept;
propertyLookup(qualifierConcept, this.qualifierConceptProperty);
}
//~--- get methods ---------------------------------------------------------
/**
* Gets the qualifier concept nid.
*
* @return the qualifier concept nid
*/
public int getQualifierConceptNid() {
lazyLoad();
return this.qualifierConceptNid;
}
/**
* Gets the qualifier concept property.
*
* @return the qualifier concept property
*/
public SimpleStringProperty getQualifierConceptProperty() {
lazyLoad();
return this.qualifierConceptProperty;
}
/**
* Gets the source concept.
*
* @return the source concept
*/
public UUID getSourceConcept() {
lazyLoad();
return this.sourceConcept;
}
//~--- set methods ---------------------------------------------------------
/**
* Sets the source concept.
*
* @param sourceConcept the new source concept
*/
private void setSourceConcept(UUID sourceConcept) {
this.sourceConcept = sourceConcept;
propertyLookup(sourceConcept, this.sourceConceptProperty);
}
//~--- get methods ---------------------------------------------------------
/**
* Gets the source concept nid.
*
* @return the source concept nid
*/
public int getSourceConceptNid() {
return this.sourceConceptNid;
}
/**
* Gets the source concept property.
*
* @return the source concept property
*/
public SimpleStringProperty getSourceConceptProperty() {
lazyLoad();
return this.sourceConceptProperty;
}
/**
* Gets the summary.
*
* @return the summary
*/
public String getSummary() {
return (isActive() ? "Active "
: "Retired ") + "Mapping: " + Frills.getDescription(this.sourceConcept).get() + "-" +
Frills.getDescription(this.mappingSetIDConcept).get() + "-" +
((this.targetConcept == null) ? "not mapped"
: Frills.getDescription(this.targetConcept)
.get()) + "-" + ((this.qualifierConcept == null) ? "no qualifier"
: Frills.getDescription(this.qualifierConcept)
.get()) + "-" + ((this.editorStatusConcept == null) ? "no status"
: Frills.getDescription(this.editorStatusConcept)
.get()) + "-" + this.uuids.get(0).toString();
}
/**
* Gets the target concept.
*
* @return the target concept
*/
public UUID getTargetConcept() {
return this.targetConcept;
}
//~--- set methods ---------------------------------------------------------
/**
* Sets the target concept.
*
* @param targetConcept the new target concept
*/
private void setTargetConcept(UUID targetConcept) {
this.targetConcept = targetConcept;
if (targetConcept == null) {
this.targetConceptProperty.set(NO_MAP_NAME);
} else {
propertyLookup(targetConcept, this.targetConceptProperty);
}
}
//~--- get methods ---------------------------------------------------------
/**
* Gets the target concept nid.
*
* @return the target concept nid
*/
public int getTargetConceptNid() {
lazyLoad();
return this.targetConceptNid;
}
/**
* Gets the target concept property.
*
* @return the target concept property
*/
public SimpleStringProperty getTargetConceptProperty() {
lazyLoad();
return this.targetConceptProperty;
}
/**
* Gets the UUIDs.
*
* @return the UUIDs of this Mapping Item. Note that this doesn't uniquely identify a mapping item within the system
* as changes to the mapping item will retain the same ID - there will now be multiple versions. They will differ by date.
* There will typically be only one entry in this list (identical to the value of {@link #getPrimordialUUID}
*/
public List<UUID> getUUIDs() {
return this.uuids;
}
}