// Copyright 2017 JanusGraph Authors
//
// 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.
package org.janusgraph.graphdb.relations;
import org.janusgraph.core.*;
import org.janusgraph.graphdb.internal.AbstractElement;
import org.janusgraph.graphdb.internal.InternalRelation;
import org.janusgraph.graphdb.internal.InternalRelationType;
import org.janusgraph.graphdb.internal.InternalVertex;
import org.janusgraph.graphdb.transaction.StandardJanusGraphTx;
import org.janusgraph.graphdb.types.system.ImplicitKey;
import org.apache.tinkerpop.gremlin.structure.*;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
import java.util.Iterator;
import java.util.stream.Stream;
public abstract class AbstractTypedRelation extends AbstractElement implements InternalRelation {
protected final InternalRelationType type;
public AbstractTypedRelation(final long id, final RelationType type) {
super(id);
assert type != null && type instanceof InternalRelationType;
this.type = (InternalRelationType) type;
}
@Override
public InternalRelation it() {
InternalVertex v = getVertex(0);
if (v == v.it())
return this;
InternalRelation next = (InternalRelation) RelationIdentifier.get(this).findRelation(tx());
if (next == null)
throw InvalidElementException.removedException(this);
return next;
}
@Override
public final StandardJanusGraphTx tx() {
return getVertex(0).tx();
}
/**
* Cannot currently throw exception when removed since internal logic relies on access to the edge
* beyond its removal. TODO: re-concile with access validation logic
*/
protected final void verifyAccess() {
return;
// if (isRemoved()) {
// throw InvalidElementException.removedException(this);
// }
}
/* ---------------------------------------------------------------
* Immutable Aspects of Relation
* ---------------------------------------------------------------
*/
@Override
public Direction direction(Vertex vertex) {
for (int i=0;i<getArity();i++) {
if (it().getVertex(i).equals(vertex)) return EdgeDirection.fromPosition(i);
}
throw new IllegalArgumentException("Relation is not incident on vertex");
}
@Override
public boolean isIncidentOn(Vertex vertex) {
for (int i=0;i<getArity();i++) {
if (it().getVertex(i).equals(vertex)) return true;
}
return false;
}
@Override
public boolean isInvisible() {
return type.isInvisibleType();
}
@Override
public boolean isLoop() {
return getArity()==2 && getVertex(0).equals(getVertex(1));
}
@Override
public RelationType getType() {
return type;
}
@Override
public RelationIdentifier id() {
return RelationIdentifier.get(this);
}
/* ---------------------------------------------------------------
* Mutable Aspects of Relation
* ---------------------------------------------------------------
*/
@Override
public <V> Property<V> property(final String key, final V value) {
verifyAccess();
PropertyKey pkey = tx().getOrCreatePropertyKey(key);
Object normalizedValue = tx().verifyAttribute(pkey,value);
it().setPropertyDirect(pkey,normalizedValue);
return new SimpleJanusGraphProperty<V>(this,pkey,value);
}
@Override
public <O> O valueOrNull(PropertyKey key) {
verifyAccess();
if (key instanceof ImplicitKey) return ((ImplicitKey)key).computeProperty(this);
return it().getValueDirect(key);
}
@Override
public <O> O value(String key) {
verifyAccess();
O val = valueInternal(tx().getPropertyKey(key));
if (val==null) throw Property.Exceptions.propertyDoesNotExist(this,key);
return val;
}
private <O> O valueInternal(PropertyKey type) {
if (type==null) {
return null;
}
return valueOrNull(type);
}
@Override
public <V> Iterator<Property<V>> properties(final String... keyNames) {
verifyAccess();
Stream<PropertyKey> keys;
if (keyNames==null || keyNames.length==0) {
keys = IteratorUtils.stream(it().getPropertyKeysDirect().iterator());
} else {
keys = Stream.of(keyNames)
.map(s -> tx().getPropertyKey(s)).filter(rt -> rt != null && getValueDirect(rt)!=null);
}
return keys.map( rt -> (Property<V>)new SimpleJanusGraphProperty<V>(this,rt,valueInternal(rt))).iterator();
}
/* ---------------------------------------------------------------
* Blueprints Iterators
* ---------------------------------------------------------------
*/
// @Override
// public Iterator<Vertex> vertexIterator(Direction direction) {
// verifyAccess();
//
// List<Vertex> vertices;
// if (direction==Direction.BOTH) {
// vertices = ImmutableList.of((Vertex)getVertex(0),getVertex(1));
// } else {
// vertices = ImmutableList.of((Vertex)getVertex(EdgeDirection.position(direction)));
// }
// return vertices.iterator();
// }
//
// @Override
// public <V> Iterator<Property<V>> propertyIterator(String... keyNames) {
// verifyAccess();
//
// Stream<RelationType> keys;
//
// if (keyNames==null || keyNames.length==0) {
// keys = IteratorUtils.stream(it().getPropertyKeysDirect());
// } else {
// keys = Stream.of(keyNames)
// .map(s -> tx().getRelationType(s)).filter(rt -> rt != null && getValueDirect(rt)!=null);
// }
// return keys.map( rt -> (Property<V>)new SimpleJanusGraphProperty<V>(this,rt,valueInternal(rt))).iterator();
// }
}