package com.ohnosequences.typedGraphs.titan;

import com.ohnosequences.typedGraphs.Node;
import com.ohnosequences.typedGraphs.NodeType;
import com.ohnosequences.typedGraphs.Property;
import com.ohnosequences.typedGraphs.PropertyType;
import com.ohnosequences.typedGraphs.RelTypes;

import com.thinkaurelius.titan.core.TitanVertex;
import com.thinkaurelius.titan.core.TitanEdge;
import com.thinkaurelius.titan.core.TitanKey;
import com.thinkaurelius.titan.core.TitanElement;

public abstract class TitanNode<
  N extends TitanNode<N,NT>, 
  NT extends  Enum<NT> & TitanNodeType<N,NT>
> implements Node<N,NT>, TitanVertex {

  protected TitanNode(TitanVertex raw) { this.raw = raw; }
  protected TitanVertex raw;

  // TODO delegate all TitanVertex methods to raw

  // TODO move to TitanElement
  @Override
  public <P extends Property<N,NT>, PT extends PropertyType<N,NT, P,PT, V>, V> V get(PT pt) {

    return raw.<V>getProperty(pt.fullName());
  }

  // use get for implementing all the property-name() methods

  public <P extends Property<N,NT>, PT extends PropertyType<N,NT, P,PT, V>, V> void set(PT pt, V value) {

    raw.setProperty(pt.fullName(), value);
  }

  /*
    adds a rel with source this node; note that this method does not set any properties.
  */
  public <
    R extends TitanRelationship<N,NT,R,RT,T,TT>, 
    RT extends Enum<RT> & TitanRelationshipType<N,NT,R,RT,T,TT>,
    T extends TitanNode<T,TT>,
    TT extends Enum<TT> & TitanNodeType<T,TT>
  > R addOut(RT relType, T to) {

    TitanEdge rawEdge = to.addEdge(relType.value().toString(), this);

    return relType.from(rawEdge);
  }

  /*
    adds a rel with target this node; note that this method does not set any properties
  */
  public <
    S extends TitanNode<S,ST>,
    ST extends Enum<ST> & TitanNodeType<S,ST>,
    R extends TitanRelationship<S,ST,R,RT,N,NT>, 
    RT extends Enum<RT> & TitanRelationshipType<S,ST,R,RT,N,NT>
  > R addIn(RT relType, S from) {

    TitanEdge rawEdge = this.addEdge(relType.value().toString(), from);

    return relType.from(rawEdge);
  }

  // TODO maybe is not even needed
  // what we need is something similar depending on arity
  public abstract <
    R extends TitanRelationship<N,NT,R,RT,T,TT>, 
    RT extends Enum<RT> & TitanRelationshipType<N,NT,R,RT,T,TT>,
    T extends TitanNode<T,TT>,
    TT extends Enum<TT> & TitanNodeType<T,TT>
  > Iterable<R> out(RT relType);
  // {

    // TODO map relType.from
    // return relType.from(
    //   this.getEdges(com.tinkerpop.blueprints.Direction.OUT, relType.value().toString())
    // );
  // }

  // TODO equivalent methods for oneToMany in, out etc
  protected <
    R extends TitanRelationship<N,NT,R,RT,T,TT>, 
    RT extends Enum<RT> & RelTypes.ToOne<N,NT,R,RT,T,TT> & TitanRelationshipType<N,NT,R,RT,T,TT>,
    T extends TitanNode<T,TT>,
    TT extends Enum<TT> & TitanNodeType<T,TT>
  > R outToOne(RT relType) {

    // TODO check the arity here, throw expection otherwise
    Iterable<TitanEdge> tEdges = this.getTitanEdges(com.tinkerpop.blueprints.Direction.OUT, relType.label());

    return relType.from(
      tEdges.iterator().next()
    );
  }


  // protected <
  //   R extends TitanRelationship<N,NT,R,RT,T,TT>, 
  //   RT extends Enum<RT> & RelTypes.ToMany<N,NT,R,RT,T,TT> & TitanRelationshipType<N,NT,R,RT,T,TT>,
  //   T extends TitanNode<T,TT>,
  //   TT extends Enum<TT> & TitanNodeType<T,TT>
  // > List<R> outToMany(RT relType) {

  //   Iterable<TitanEdge> tEdges = this.getTitanEdges(com.tinkerpop.blueprints.Direction.OUT, relType.label());

  //   // TODO map relType.from over tEdges
  // }





  protected <
    S extends TitanNode<S,ST>,
    ST extends Enum<ST> & TitanNodeType<S,ST>,
    R extends TitanRelationship<S,ST,R,RT,N,NT>, 
    RT extends Enum<RT> & TitanRelationshipType<S,ST,R,RT,N,NT> & RelTypes.FromOne<S,ST,R,RT,N,NT>
  > R inFromOne(RT relType) {

    // TODO check the arity here, throw expection otherwise
    Iterable<TitanEdge> tEdges = this.getTitanEdges(com.tinkerpop.blueprints.Direction.IN, relType.label());

    return relType.from(
      tEdges.iterator().next()
    );
  }
}
@@ -39,16 +39,96 @@
 titan;%0A%0A
+import java.util.Iterator;%0Aimport java.util.LinkedList;%0Aimport java.util.List;%0A%0A
 import c
@@ -354,17 +354,16 @@
 lTypes;%0A
-%0A
 import c
@@ -3211,21 +3211,17 @@
 );%0A  %7D%0A%0A
-%0A  //
+ 
  protect
@@ -3226,19 +3226,16 @@
 cted %3C%0A 
- //
    R ext
@@ -3276,19 +3276,16 @@
 ,TT%3E, %0A 
- //
    RT ex
@@ -3371,27 +3371,24 @@
 ,RT,T,TT%3E,%0A 
- //
    T extends
@@ -3406,19 +3406,16 @@
 T,TT%3E,%0A 
- //
    TT ex
@@ -3452,19 +3452,16 @@
 %3CT,TT%3E%0A 
- //
  %3E List%3C
@@ -3489,19 +3489,16 @@
 pe) %7B%0A%0A 
- //
    Itera
@@ -3602,63 +3602,209 @@
 ));%0A
-%0A  //   // TODO map relType.from over tEdges%0A  // %7D%0A%0A%0A%0A
+    List%3CR%3E list = new LinkedList%3C%3E();   %0A    Iterator%3CTitanEdge%3E iterator = tEdges.iterator();%0A    while(iterator.hasNext())%7B%0A    %09list.add(relType.from(iterator.next())); %0A    %7D%0A%0A    return list;%0A  %7D
 %0A%0A  
@@ -4310,9 +4310,10 @@
  );%0A  %7D%0A
+%0A
 %7D

fix conflicts, add conversion, compiles