package org.openntf.domino.graph2.annotations;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.openntf.domino.graph2.DGraphUtils;
import org.openntf.domino.graph2.impl.DEdge;
import org.openntf.domino.graph2.impl.DEdgeList;
import org.openntf.domino.graph2.impl.DFramedTransactionalGraph;
import org.openntf.domino.graph2.impl.DVertex;
import org.openntf.domino.types.CaseInsensitiveString;
import org.openntf.domino.utils.TypeUtils;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.frames.EdgeFrame;
import com.tinkerpop.frames.FramedGraph;
import com.tinkerpop.frames.VertexFrame;
import com.tinkerpop.frames.structures.FramedEdgeIterable;
public class FramedEdgeList<T extends EdgeFrame> extends FramedEdgeIterable<T> implements List<T> {
public static class FramedListIterator<T> implements ListIterator<T> {
protected final Class<T> kind_;
// protected final Direction direction_;
protected final ListIterator<Edge> iterator_;
protected final FramedGraph<? extends Graph> framedGraph_;
public FramedListIterator(final FramedGraph<? extends Graph> graph, final ListIterator<Edge> iterator, final Class<T> kind/*, Direction direction*/) {
// System.out.println("TEMP DEBUG Created new FramedListIterator with a " + iterator.getClass().getName() + " kind: "
// + kind.getName());
kind_ = kind;
// direction_ = direction;
iterator_ = iterator;
framedGraph_ = graph;
}
@Override
public void add(final Object arg0) {
if (arg0 == null)
return;
if (kind_.isAssignableFrom(arg0.getClass())) {
iterator_.add(((EdgeFrame) kind_.cast(arg0)).asEdge());
} else if (arg0 instanceof Edge) {
iterator_.add((Edge) arg0);
} else {
throw new IllegalArgumentException("Cannot add an object of type " + arg0.getClass().getName() + " to an iterator of "
+ kind_.getName());
}
}
@Override
public boolean hasNext() {
return iterator_.hasNext();
}
@Override
public boolean hasPrevious() {
return iterator_.hasPrevious();
}
@Override
public T next() {
T result = framedGraph_.frame(iterator_.next(), kind_);
// System.out.println("next() resulted in a " + result.getClass().getName());
return result;
}
@Override
public int nextIndex() {
return iterator_.nextIndex();
}
@Override
public T previous() {
return framedGraph_.frame(iterator_.previous(), kind_);
}
@Override
public int previousIndex() {
return iterator_.previousIndex();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void set(final Object arg0) {
if (arg0 instanceof Edge) {
iterator_.set((Edge) arg0);
} else if (kind_.isAssignableFrom(arg0.getClass())) {
iterator_.set(((EdgeFrame) kind_.cast(arg0)).asEdge());
} else {
throw new IllegalArgumentException("Cannot set an object of type " + arg0.getClass().getName() + " to an iterator of "
+ kind_.getName());
}
}
}
protected List<Edge> list_;
protected Vertex sourceVertex_;
public FramedEdgeList(final FramedGraph<? extends Graph> framedGraph, final Vertex sourceVertex, final Iterable<Edge> list,
final Class<T> kind) {
super(framedGraph, list, kind);
// System.out.println("TEMP DEBUG new FramedEdgeList created from a " + list.getClass().getName());
sourceVertex_ = sourceVertex;
if (list instanceof List) {
list_ = (List<Edge>) list;
} else {
list_ = new ArrayList<Edge>();
for (Edge e : list) {
list_.add(e);
}
}
}
//TODO optimize by building a NoteCoordinateList of the target vertices
public FramedVertexList<?> toVertexList() {
// System.out.println("TEMP DEBUG converting a FramedEdgeList to a FramedVertexList");
List<Vertex> vertList = new ArrayList<Vertex>();
for (Edge edge : list_) {
if (edge instanceof DEdge) {
try {
Vertex other = ((DEdge) edge).getOtherVertex(sourceVertex_);
vertList.add(other);
} catch (Throwable t) {
t.printStackTrace();
}
} else {
// System.out.println("TEMP DEBUG edge is actually a " + edge.getClass().getName());
}
}
FramedVertexList<?> result = new FramedVertexList<VertexFrame>(this.framedGraph, sourceVertex_, vertList, null);
return result;
}
public FramedEdgeList<T> applyFilter(final String key, final Object value) {
DEdgeList edgeList = new DEdgeList((DVertex) sourceVertex_);
if (this.size() > 0) {
for (EdgeFrame edge : this) {
try {
if ("@type".equals(key)) {
if (isType(edge, TypeUtils.toString(value))) {
edgeList.add(edge.asEdge());
}
} else {
Object edgeVal = null;
Method crystal = getGetters(edge).get(new CaseInsensitiveString(key));
if (crystal != null) {
try {
edgeVal = crystal.invoke(edge, (Object[]) null);
} catch (Exception e) {
edgeVal = edge.asEdge().getProperty(key);
}
} else {
System.err.println("No method found for key " + key);
}
if (value.equals(TypeUtils.toString(edgeVal))) {
edgeList.add(edge.asEdge());
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
FramedEdgeList<T> result = new FramedEdgeList<T>(framedGraph, sourceVertex_, edgeList, this.kind);
return result;
}
public boolean isType(final EdgeFrame frame, final String typename) {
Class<?>[] interfaces = frame.getClass().getInterfaces();
for (Class<?> inter : interfaces) {
if (inter.getName().equals(typename))
return true;
}
return false;
}
public Class<?> findInterface(final EdgeFrame frame) {
Class<?>[] interfaces = frame.getClass().getInterfaces();
return interfaces[interfaces.length - 1];
}
public Map<CaseInsensitiveString, Method> getGetters(final EdgeFrame frame) {
Class<?> type = getGraph().getTypeManager().resolve(frame.asEdge(), findInterface(frame));
return getGraph().getTypeRegistry().getPropertiesGetters(type);
}
public DFramedTransactionalGraph<?> getGraph() {
return (DFramedTransactionalGraph<?>) framedGraph;
}
@Override
public boolean add(final T arg0) {
return list_.add(arg0.asEdge());
}
@Override
public void add(final int arg0, final T arg1) {
list_.add(arg0, arg1.asEdge());
}
protected static Collection<Edge> convertToEdges(final Collection<?> arg0) {
List<Edge> result = new ArrayList<Edge>(arg0.size());
for (Object raw : arg0) {
if (raw instanceof Edge) {
result.add((Edge) raw);
} else if (raw instanceof EdgeFrame) {
result.add(((EdgeFrame) raw).asEdge());
} else {
throw new IllegalArgumentException("Cannot set an object of type " + arg0.getClass().getName()
+ " to an EdgeFrame iterator");
}
}
return result;
}
protected static Collection<Edge> convertToEdges(final Object[] arg0) {
List<Edge> result = new ArrayList<Edge>(arg0.length);
for (Object raw : arg0) {
if (raw instanceof Edge) {
result.add((Edge) raw);
} else if (raw instanceof EdgeFrame) {
result.add(((EdgeFrame) raw).asEdge());
} else {
throw new IllegalArgumentException("Cannot set an object of type " + arg0.getClass().getName()
+ " to an EdgeFrame iterator");
}
}
return result;
}
@Override
public boolean addAll(final Collection<? extends T> arg0) {
return list_.addAll(convertToEdges(arg0));
}
@Override
public boolean addAll(final int arg0, final Collection<? extends T> arg1) {
return list_.addAll(arg0, convertToEdges(arg1));
}
@Override
public void clear() {
list_.clear();
}
@Override
public boolean contains(final Object arg0) {
if (arg0 instanceof Edge) {
return list_.contains(arg0);
} else if (kind.isAssignableFrom(arg0.getClass())) {
return list_.contains(((EdgeFrame) kind.cast(arg0)).asEdge());
} else {
throw new IllegalArgumentException("Cannot set an object of type " + arg0.getClass().getName() + " to an iterator of "
+ kind.getName());
}
}
@Override
public boolean containsAll(final Collection<?> arg0) {
return list_.containsAll(convertToEdges(arg0));
}
@Override
public T get(final int arg0) {
return framedGraph.frame(list_.get(arg0), kind);
}
@Override
public int indexOf(final Object arg0) {
if (arg0 instanceof Edge) {
return list_.indexOf(arg0);
} else if (kind.isAssignableFrom(arg0.getClass())) {
return list_.indexOf(((EdgeFrame) kind.cast(arg0)).asEdge());
} else {
throw new IllegalArgumentException("Cannot set an object of type " + arg0.getClass().getName() + " to an iterator of "
+ kind.getName());
}
}
@Override
public boolean isEmpty() {
return list_.isEmpty();
}
@Override
public int lastIndexOf(final Object arg0) {
if (arg0 instanceof Edge) {
return list_.lastIndexOf(arg0);
} else if (kind.isAssignableFrom(arg0.getClass())) {
return list_.lastIndexOf(((EdgeFrame) kind.cast(arg0)).asEdge());
} else {
throw new IllegalArgumentException("Cannot set an object of type " + arg0.getClass().getName() + " to an iterator of "
+ kind.getName());
}
}
@Override
public ListIterator<T> listIterator() {
return new FramedListIterator<T>(framedGraph, list_.listIterator(), kind);
}
@Override
public ListIterator<T> listIterator(final int arg0) {
return new FramedListIterator<T>(framedGraph, list_.listIterator(arg0), kind);
}
@Override
public Iterator<T> iterator() {
return new FramedListIterator<T>(framedGraph, list_.listIterator(), kind);
}
@Override
public T remove(final int arg0) {
Edge e = list_.remove(arg0);
return framedGraph.frame(e, kind);
}
@Override
public boolean remove(final Object arg0) {
if (arg0 instanceof Edge) {
return list_.remove(arg0);
} else if (kind.isAssignableFrom(arg0.getClass())) {
return list_.remove(((EdgeFrame) kind.cast(arg0)).asEdge());
} else {
throw new IllegalArgumentException("Cannot set an object of type " + arg0.getClass().getName() + " to an iterator of "
+ kind.getName());
}
}
@Override
public boolean removeAll(final Collection<?> arg0) {
return list_.removeAll(convertToEdges(arg0));
}
@Override
public boolean retainAll(final Collection<?> arg0) {
return list_.retainAll(convertToEdges(arg0));
}
@Override
public T set(final int arg0, final T arg1) {
Edge edge = arg1.asEdge();
list_.set(arg0, edge);
return arg1;
}
@Override
public int size() {
return list_.size();
}
@Override
public List<T> subList(final int arg0, int arg1) {
if (arg1 > list_.size()) {
arg1 = list_.size();
}
List<Edge> sublist = list_.subList(arg0, arg1);
return new FramedEdgeList<T>(framedGraph, sourceVertex_, sublist, kind);
}
@Override
public Object[] toArray() {
int size = list_.size();
Object[] result = new Object[size];
for (int i = 0; i < size; i++) {
Edge e = list_.get(i);
result[i] = framedGraph.frame(e, kind);
}
return result;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public <U> U[] toArray(final U[] arg0) {
int size = list_.size();
Class c = arg0.getClass().getComponentType();
U[] result = (U[]) Array.newInstance(c, size);
for (int i = 0; i < size; i++) {
Edge e = list_.get(i);
result[i] = (U) framedGraph.frame(e, kind);
}
return result;
}
private static final EdgeFrame[] EF = new EdgeFrame[1];
public FramedEdgeList<T> sortBy(final List<? extends CharSequence> list, final boolean desc) {
EdgeFrame[] array = toArray(EF);
Arrays.sort(array, new DGraphUtils.EdgeFrameComparator(getGraph(), list, desc));
return new FramedEdgeList<T>(framedGraph, sourceVertex_, convertToEdges(array), kind);
}
}