/*
* 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.concept;
//~--- JDK imports ------------------------------------------------------------
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
//~--- non-JDK imports --------------------------------------------------------
import sh.isaac.api.Get;
import sh.isaac.api.State;
import sh.isaac.api.chronicle.LatestVersion;
import sh.isaac.api.component.concept.ConceptChronology;
import sh.isaac.api.component.sememe.SememeChronology;
import sh.isaac.api.component.sememe.version.DescriptionSememe;
import sh.isaac.api.component.sememe.version.LogicGraphSememe;
import sh.isaac.api.component.sememe.version.SememeVersion;
import sh.isaac.api.coordinate.EditCoordinate;
import sh.isaac.api.coordinate.LanguageCoordinate;
import sh.isaac.api.coordinate.LogicCoordinate;
import sh.isaac.api.coordinate.PremiseType;
import sh.isaac.api.coordinate.StampCoordinate;
import sh.isaac.api.externalizable.ByteArrayDataBuffer;
import sh.isaac.api.externalizable.OchreExternalizable;
import sh.isaac.api.externalizable.OchreExternalizableObjectType;
import sh.isaac.api.logic.IsomorphicResults;
import sh.isaac.api.logic.LogicalExpression;
import sh.isaac.api.relationship.RelationshipVersionAdaptor;
import sh.isaac.model.ObjectChronologyImpl;
import sh.isaac.model.relationship.RelationshipAdaptorChronologyImpl;
import sh.isaac.model.sememe.version.LogicGraphSememeImpl;
//~--- classes ----------------------------------------------------------------
/**
* The Class ConceptChronologyImpl.
*
* @author kec
*/
public class ConceptChronologyImpl
extends ObjectChronologyImpl<ConceptVersionImpl>
implements ConceptChronology<ConceptVersionImpl>, OchreExternalizable {
/** The concept origin relationship list. */
List<RelationshipAdaptorChronologyImpl> conceptOriginRelationshipList;
/** The concept origin relationship list defalt coordinate. */
List<RelationshipAdaptorChronologyImpl> conceptOriginRelationshipListDefaltCoordinate;
/** The relationship list with concept as destination. */
List<RelationshipAdaptorChronologyImpl> relationshipListWithConceptAsDestination;
/** The relationship list with concept as destination list defalt coordinate. */
List<RelationshipAdaptorChronologyImpl> relationshipListWithConceptAsDestinationListDefaltCoordinate;
//~--- constructors --------------------------------------------------------
/**
* Instantiates a new concept chronology impl.
*/
private ConceptChronologyImpl() {}
/**
* Instantiates a new concept chronology impl.
*
* @param primordialUuid the primordial uuid
* @param nid the nid
* @param containerSequence the container sequence
*/
public ConceptChronologyImpl(UUID primordialUuid, int nid, int containerSequence) {
super(primordialUuid, nid, containerSequence);
}
//~--- methods -------------------------------------------------------------
/**
* Contains description.
*
* @param descriptionText the description text
* @return true, if successful
*/
@Override
public boolean containsDescription(String descriptionText) {
return Get.sememeService()
.getDescriptionsForComponent(getNid())
.anyMatch((desc) -> desc.getVersionList()
.stream()
.anyMatch((version) -> version.getText()
.equals(descriptionText)));
}
/**
* Contains description.
*
* @param descriptionText the description text
* @param stampCoordinate the stamp coordinate
* @return true, if successful
*/
@Override
public boolean containsDescription(String descriptionText, StampCoordinate stampCoordinate) {
return Get.sememeService()
.getSnapshot(DescriptionSememe.class, stampCoordinate)
.getLatestDescriptionVersionsForComponent(getNid())
.anyMatch((latestVersion) -> latestVersion.value()
.getText()
.equals(descriptionText));
}
/**
* Creates the mutable version.
*
* @param stampSequence the stamp sequence
* @return the concept version impl
*/
@Override
public ConceptVersionImpl createMutableVersion(int stampSequence) {
final ConceptVersionImpl newVersion = new ConceptVersionImpl(this, stampSequence, nextVersionSequence());
addVersion(newVersion);
return newVersion;
}
/**
* Creates the mutable version.
*
* @param state the state
* @param ec the ec
* @return the concept version impl
*/
@Override
public ConceptVersionImpl createMutableVersion(State state, EditCoordinate ec) {
final int stampSequence = Get.stampService()
.getStampSequence(state,
Long.MAX_VALUE,
ec.getAuthorSequence(),
ec.getModuleSequence(),
ec.getPathSequence());
final ConceptVersionImpl newVersion = new ConceptVersionImpl(this, stampSequence, nextVersionSequence());
addVersion(newVersion);
return newVersion;
}
/**
* Make.
*
* @param data the data
* @return the concept chronology impl
*/
public static ConceptChronologyImpl make(ByteArrayDataBuffer data) {
final ConceptChronologyImpl conceptChronology = new ConceptChronologyImpl();
conceptChronology.readData(data);
return conceptChronology;
}
/**
* To string.
*
* @return the string
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("ConceptChronologyImpl{");
builder.append(toUserString());
builder.append(" <");
builder.append(getConceptSequence());
builder.append("> ");
toString(builder);
return builder.toString();
}
/**
* To user string.
*
* @return the string
*/
@Override
public String toUserString() {
final List<SememeChronology<? extends DescriptionSememe<?>>> descList = getConceptDescriptionList();
if (descList.isEmpty()) {
return "no description for concept: " + getUuidList() + " " + getConceptSequence() + " " + getNid();
}
return getConceptDescriptionList().get(0)
.getVersionList()
.get(0)
.getText();
}
/**
* Write chronicle data.
*
* @param data the data
*/
@Override
public void writeChronicleData(ByteArrayDataBuffer data) {
super.writeChronicleData(data);
}
/**
* Make version.
*
* @param stampSequence the stamp sequence
* @param bb the bb
* @return the concept version impl
*/
@Override
protected ConceptVersionImpl makeVersion(int stampSequence, ByteArrayDataBuffer bb) {
return new ConceptVersionImpl(this, stampSequence, bb.getShort());
}
/**
* Put additional chronicle fields.
*
* @param out the out
*/
@Override
protected void putAdditionalChronicleFields(ByteArrayDataBuffer out) {
// nothing to put for ConceptChronology...
}
/**
* Skip additional chronicle fields.
*
* @param in the in
*/
@Override
protected void skipAdditionalChronicleFields(ByteArrayDataBuffer in) {
// nothing to read for ConceptChronology...
}
//~--- get methods ---------------------------------------------------------
/**
* Gets the additional chronicle fields.
*
* @param in the in
* @return the additional chronicle fields
*/
@Override
protected void getAdditionalChronicleFields(ByteArrayDataBuffer in) {
// nothing to read for ConceptChronology...
}
/**
* Gets the concept description list.
*
* @return the concept description list
*/
@Override
public List<SememeChronology<? extends DescriptionSememe<?>>> getConceptDescriptionList() {
if (Get.sememeServiceAvailable()) {
return Get.sememeService()
.getDescriptionsForComponent(getNid())
.collect(Collectors.toList());
} else {
return new ArrayList<>();
}
}
/**
* Gets the concept description text.
*
* @return the concept description text
*/
@Override
public String getConceptDescriptionText() {
return Get.conceptDescriptionText(getNid());
}
/**
* Gets the concept sequence.
*
* @return the concept sequence
*/
@Override
public int getConceptSequence() {
return getContainerSequence();
}
/**
* Gets the data format version.
*
* @return the data format version
*/
@Override
public byte getDataFormatVersion() {
return 0;
}
/**
* Gets the fully specified description.
*
* @param languageCoordinate the language coordinate
* @param stampCoordinate the stamp coordinate
* @return the fully specified description
*/
@Override
public Optional<LatestVersion<DescriptionSememe<?>>> getFullySpecifiedDescription(
LanguageCoordinate languageCoordinate,
StampCoordinate stampCoordinate) {
return languageCoordinate.getFullySpecifiedDescription(getConceptDescriptionList(), stampCoordinate);
}
/**
* Gets the logical definition.
*
* @param stampCoordinate the stamp coordinate
* @param premiseType the premise type
* @param logicCoordinate the logic coordinate
* @return the logical definition
*/
@Override
public Optional<LatestVersion<LogicGraphSememe<?>>> getLogicalDefinition(StampCoordinate stampCoordinate,
PremiseType premiseType,
LogicCoordinate logicCoordinate) {
int assemblageSequence;
if (premiseType == PremiseType.INFERRED) {
assemblageSequence = logicCoordinate.getInferredAssemblageSequence();
} else {
assemblageSequence = logicCoordinate.getStatedAssemblageSequence();
}
final Optional<?> optional = Get.sememeService()
.getSnapshot(LogicGraphSememe.class, stampCoordinate)
.getLatestSememeVersionsForComponentFromAssemblage(getNid(), assemblageSequence)
.findFirst();
return (Optional<LatestVersion<LogicGraphSememe<?>>>) optional;
}
/**
* Gets the logical definition chronology report.
*
* @param stampCoordinate the stamp coordinate
* @param premiseType the premise type
* @param logicCoordinate the logic coordinate
* @return the logical definition chronology report
*/
@Override
public String getLogicalDefinitionChronologyReport(StampCoordinate stampCoordinate,
PremiseType premiseType,
LogicCoordinate logicCoordinate) {
int assemblageSequence;
if (premiseType == PremiseType.INFERRED) {
assemblageSequence = logicCoordinate.getInferredAssemblageSequence();
} else {
assemblageSequence = logicCoordinate.getStatedAssemblageSequence();
}
final Optional<SememeChronology<? extends SememeVersion<?>>> definitionChronologyOptional = Get.sememeService()
.getSememesForComponentFromAssemblage(
getNid(),
assemblageSequence)
.findFirst();
if (definitionChronologyOptional.isPresent()) {
final Collection<LogicGraphSememeImpl> versions =
(Collection<LogicGraphSememeImpl>) definitionChronologyOptional.get()
.getVisibleOrderedVersionList(
stampCoordinate);
// Collection<LogicGraphSememeImpl> versionsList = new ArrayList<>();
// for (LogicGraphSememeImpl lgs : definitionChronologyOptional.get().getVisibleOrderedVersionList(stampCoordinate)) {
//
// }
final StringBuilder builder = new StringBuilder();
builder.append("_______________________________________________________________________\n");
builder.append(" Encountered concept '")
.append(Get.conceptDescriptionText(getNid()))
.append("' with ")
.append(versions.size())
.append(" definition versions:\n");
builder.append(" ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄\n");
int version = 0;
LogicalExpression previousVersion = null;
for (final LogicGraphSememeImpl lgmv: versions) {
final LogicalExpression lg = lgmv.getLogicalExpression();
builder.append(" Version ")
.append(version++)
.append("\n")
.append(Get.stampService()
.describeStampSequence(lgmv.getStampSequence()))
.append("\n");
if (previousVersion == null) {
builder.append(lg);
} else {
final IsomorphicResults solution = lg.findIsomorphisms(previousVersion);
builder.append(solution);
}
builder.append("_______________________________________________________________________\n");
previousVersion = lg;
}
builder.append(" ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄\n");
return builder.toString();
}
return "No definition found. ";
}
/**
* Gets the ochre object type.
*
* @return the ochre object type
*/
@Override
public OchreExternalizableObjectType getOchreObjectType() {
return OchreExternalizableObjectType.CONCEPT;
}
/**
* Gets the preferred description.
*
* @param languageCoordinate the language coordinate
* @param stampCoordinate the stamp coordinate
* @return the preferred description
*/
@Override
public Optional<LatestVersion<DescriptionSememe<?>>> getPreferredDescription(LanguageCoordinate languageCoordinate,
StampCoordinate stampCoordinate) {
return languageCoordinate.getPreferredDescription(getConceptDescriptionList(), stampCoordinate);
}
/**
* Gets the relationship list originating from concept.
*
* @return the relationship list originating from concept
*/
@Override
public List<? extends SememeChronology<? extends RelationshipVersionAdaptor<?>>> getRelationshipListOriginatingFromConcept() {
if (this.conceptOriginRelationshipList == null) {
this.conceptOriginRelationshipList = new ArrayList<>();
Get.logicService()
.getRelationshipAdaptorsOriginatingWithConcept(this)
.forEach((relAdaptor) -> {
this.conceptOriginRelationshipList.add((RelationshipAdaptorChronologyImpl) relAdaptor);
});
}
return this.conceptOriginRelationshipList;
}
/**
* Gets the relationship list originating from concept.
*
* @param logicCoordinate the logic coordinate
* @return the relationship list originating from concept
*/
@Override
public List<? extends SememeChronology<? extends RelationshipVersionAdaptor<?>>> getRelationshipListOriginatingFromConcept(
LogicCoordinate logicCoordinate) {
if (this.conceptOriginRelationshipList == null) {
this.conceptOriginRelationshipList = new ArrayList<>();
Get.logicService().getRelationshipAdaptorsOriginatingWithConcept(this, logicCoordinate).forEach((relAdaptor) -> {
this.conceptOriginRelationshipList.add((RelationshipAdaptorChronologyImpl) relAdaptor);
});
}
return this.conceptOriginRelationshipList;
}
/**
* Gets the relationship list with concept as destination.
*
* @return the relationship list with concept as destination
*/
@Override
public List<? extends SememeChronology<? extends RelationshipVersionAdaptor<?>>> getRelationshipListWithConceptAsDestination() {
if (this.relationshipListWithConceptAsDestinationListDefaltCoordinate == null) {
this.relationshipListWithConceptAsDestinationListDefaltCoordinate = new ArrayList<>();
Get.logicService()
.getRelationshipAdaptorsWithConceptAsDestination(this)
.forEach((relAdaptor) -> {
this.relationshipListWithConceptAsDestinationListDefaltCoordinate.add(
(RelationshipAdaptorChronologyImpl) relAdaptor);
});
}
return this.relationshipListWithConceptAsDestinationListDefaltCoordinate;
}
/**
* Gets the relationship list with concept as destination.
*
* @param logicCoordinate the logic coordinate
* @return the relationship list with concept as destination
*/
@Override
public List<? extends SememeChronology<? extends RelationshipVersionAdaptor<?>>> getRelationshipListWithConceptAsDestination(
LogicCoordinate logicCoordinate) {
if (this.relationshipListWithConceptAsDestination == null) {
this.relationshipListWithConceptAsDestination = new ArrayList<>();
Get.logicService().getRelationshipAdaptorsWithConceptAsDestination(this, logicCoordinate).forEach((relAdaptor) -> {
this.relationshipListWithConceptAsDestination.add(
(RelationshipAdaptorChronologyImpl) relAdaptor);
});
}
return this.relationshipListWithConceptAsDestination;
}
}