/******************************************************************************
*
* Copyright 2014 Paphus Solutions Inc.
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html
*
* 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.
*
******************************************************************************/
package org.botlibre.knowledge;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.Date;
import org.botlibre.api.knowledge.Relationship;
import org.botlibre.api.knowledge.Vertex;
import org.botlibre.util.Utils;
/**
* Meta reference.
* Basic implementation to allow subclasses to avoid defining some of the basic stuff.
*/
public class BasicRelationship implements Relationship, Comparable<Relationship>, Serializable {
private static final long serialVersionUID = 1L;
protected Long id;
protected Vertex type;
protected Vertex source;
protected Vertex target;
protected Vertex meta;
/** Index of the relationships in the source's relationships of that type. */
protected int index = -1;
/** Fuzzy value of the certainty of the relationship's correctness, between 0-1. */
protected float correctness = 0.5f;
protected Date creationDate;
protected Date accessDate;
protected int accessCount;
protected boolean pinned;
protected int consciousnessLevel;
protected int hashCode;
public BasicRelationship() {
super();
}
public BasicRelationship(Vertex source, Vertex type, Vertex target) {
super();
this.source = source;
this.target = target;
this.type = type;
}
public Long getId() {
return id;
}
/**
* Set the relationship id.
* The id can only be set when loading or creating a relationship.
*/
public void setId(Long id) {
this.id = id;
}
public boolean equals(Object another) {
if (this == another) {
return true;
}
if (hashCode() != another.hashCode()) {
return false;
}
if (!(another instanceof Relationship)) {
return false;
}
Relationship relationship = (Relationship) another;
if ((this.id != null) && this.id.equals(relationship.getId())) {
return true;
}
// Allow preset ordering, if both index and not the same, then not equal.
if (hasIndex() && relationship.hasIndex()) {
if (this.index != relationship.getIndex()) {
return false;
}
}
return this.source.equals(relationship.getSource())
&& this.target.equals(relationship.getTarget())
&& this.type.equals(relationship.getType());
}
/**
* Compare the relationships by index, to allow sorting.
*/
public int compareTo(Relationship another) {
if (this == another) {
return 0;
}
int index = ((Relationship)another).getIndex();
if (getIndex() > index ) {
return 1;
} else if (index == getIndex()) {
return 0;
} else {
return -1;
}
}
/**
* Return the fuzzy value of the certainty of the relationship's correctness.
* Values are between 0 and 1.
*/
public float getCorrectness() {
return correctness;
}
/**
* Set the fuzzy value of the certainty of the relationship's correctness.
* Values are between 0 and 1.
*/
public void setCorrectness(float correctness) {
this.correctness = correctness;
}
/**
* Return if the relationship is inverse, i.e. know to not exist.
*/
public boolean isInverse() {
return getCorrectness() < 0;
}
/**
* Return the index of the relationships in the source's relationships of that type.
*/
public int getIndex() {
return this.index;
}
/**
* Set the index of the relationships in the source's relationships of that type.
*/
public void setIndex(int index) {
this.index = index;
}
/**
* Return if the relationship has an index (preset order).
*/
public boolean hasIndex() {
return this.index != -1;
}
public Vertex getType() {
return type;
}
public Vertex getMeta() {
return meta;
}
public boolean hasMeta() {
return meta != null;
}
public Vertex getSource() {
return source;
}
public Vertex getTarget() {
return target;
}
public void resetHashCode() {
this.hashCode = 0;
}
public int hashCode() {
if (this.hashCode != 0) {
return this.hashCode;
}
if ((this.type == null) || (this.target == null)) {
return super.hashCode();
}
if ((this.type.getId() == null) || (this.target.getId() == null)) {
return super.hashCode();
}
this.hashCode = this.type.hashCode() + this.target.hashCode();
return this.hashCode;
}
public boolean checkHashCode() {
if (this.hashCode == 0) {
return false;
}
if ((this.type == null) || (this.target == null)) {
return false;
}
if ((this.type.getId() == null) || (this.target.getId() == null)) {
return false;
}
int hashCode = this.type.hashCode() + this.target.hashCode();
if (this.hashCode != hashCode) {
this.hashCode = hashCode;
return true;
}
return false;
}
public void setSource(Vertex source) {
this.source = source;
}
public void setTarget(Vertex target) {
this.target = target;
}
public void setType(Vertex type) {
this.type = type;
}
public void setMeta(Vertex meta) {
this.meta = meta;
}
/**
* Return if the vertex is pinned to memory, and will not be forgotten.
*/
public boolean isPinned() {
return pinned;
}
/**
* Set if the vertex should be pinned to memory.
* Pinned vertices will not be forgotten.
*/
public void setPinned(boolean pinned) {
this.pinned = pinned;
}
/**
* Return the date the vertex was created.
*/
public Date getCreationDate() {
return creationDate;
}
/**
* Set the date the vertex was created.
*/
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
/**
* Return the date the vertex was last accessed.
*/
public Date getAccessDate() {
return accessDate;
}
/**
* Set the date the vertex was last accessed.
* Access is considered moving from long term to short term memory.
*/
public void setAccessDate(Date accessDate) {
this.accessDate = accessDate;
}
/**
* Return the number of times the vertex has been accessed.
* Access is considered moving from long term to short term memory.
*/
public int getAccessCount() {
return accessCount;
}
/**
* Set the number of times the vertex has been accessed.
*/
public void setAccessCount(int accessCount) {
this.accessCount = accessCount;
}
/**
* Record that the vertex was accessed, update the access time and increment the access count.
*/
public void incrementAccessCount() {
if ((this.accessDate != null) && ((System.currentTimeMillis() - this.accessDate.getTime()) < (24 * Utils.HOUR))) {
// Avoid incrementing if already incremented this day.
return;
}
setAccessDate(new Date());
setAccessCount(this.accessCount + 1);
}
/**
* Increase the vertices's level of consciousness.
*/
public void incrementConsciousnessLevel() {
incrementConsciousnessLevel(1);
}
/**
* Decrease the vertices's level of consciousness.
*/
public void decrementConsciousnessLevel() {
decrementConsciousnessLevel(1);
}
/**
* Decrease the vertices's level of consciousness by the amount.
*/
public void decrementConsciousnessLevel(int amount) {
this.consciousnessLevel = this.consciousnessLevel - amount;
}
/**
* Increase the vertices's level of consciousness by the amount.
*/
public void incrementConsciousnessLevel(int amount) {
this.consciousnessLevel = this.consciousnessLevel + amount;
if (this.consciousnessLevel > 5) {
incrementAccessCount();
}
}
/**
* Return the vertices's level of consciousness.
*/
public int getConsciousnessLevel() {
return this.consciousnessLevel;
}
/**
* Set the vertices's level of consciousness.
*/
public void setConsciousnessLevel(int consciousnessLevel) {
this.consciousnessLevel = consciousnessLevel;
}
public String toString() {
StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(stringWriter);
BasicVertex.writeHeader(getType(), writer);
writer.print(" [");
writer.print(getIndex());
writer.print("] ");
writer.print(" (");
writer.print(((int)(getCorrectness() * 100)) / 100f);
writer.print(")-> ");
BasicVertex.writeHeader(getTarget(), writer);
writer.flush();
stringWriter.flush();
return stringWriter.toString();
}
}