Package org.neo4j.collections.list

Source Code of org.neo4j.collections.list.List

/**
* Copyright (c) 2002-2013 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.collections.list;

import java.util.Collection;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException;

import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;

class List implements java.util.List<Node> {

  class ElementIterator implements Iterator<Node> {

    protected Node currentElement = underlyingNode;
    protected int index = -1;

    ElementIterator(int index) {
      if (index > -1) {
        currentElement = outer.get(index);
        this.index = index;
      }
    }

    @Override
    public boolean hasNext() {
      if (currentElement.getId() == underlyingNode.getId()) {
        return currentElement.hasRelationship(RelTypes.FIRST_ELEMENT,
            Direction.OUTGOING);
      } else {
        return currentElement.hasRelationship(RelTypes.NEXT_ELEMENT,
            Direction.OUTGOING);
      }
    }

    @Override
    public Node next() {
      if (!hasNext())
        throw new NoSuchElementException();
      if (currentElement.getId() == underlyingNode.getId()) {
        currentElement = underlyingNode.getSingleRelationship(
            RelTypes.FIRST_ELEMENT, Direction.OUTGOING)
            .getEndNode();
      } else {
        currentElement = currentElement.getSingleRelationship(
            RelTypes.NEXT_ELEMENT, Direction.OUTGOING).getEndNode();
      }
      index++;
      return currentElement;
    }

    public boolean hasPrevious() {
      if (currentElement == underlyingNode) {
        return false;
      } else {
        return currentElement.hasRelationship(RelTypes.NEXT_ELEMENT,
            Direction.INCOMING);
      }
    }
   
    public Node previous() {
      if (!hasPrevious())
        throw new NoSuchElementException();
      currentElement = currentElement.getSingleRelationship(
          RelTypes.NEXT_ELEMENT, Direction.INCOMING).getStartNode();
      index--;
      return currentElement;
    }

    @Override
    public void remove() {
      if(hasPrevious()) {
        previous();
        outer.remove(index + 1);
       
      }else{
        outer.remove(index);
        currentElement = underlyingNode;
        index = -1;
      }
    }
  }
  class ElementListIterator extends ElementIterator implements
      ListIterator<Node> {

    ElementListIterator(int index) {
      super(index);
    }

    @Override
    public void add(Node e) {
      outer.add(index, e);
    }

    @Override
    public int nextIndex() {
      return index + 1;
    }


    @Override
    public int previousIndex() {
      return index - 1;
    }

    @Override
    public void set(Node e) {
      outer.set(index, e);

    }
  }

  class NodeIterator extends ElementIterator {

    NodeIterator(int index) {
      super(index);
    }

    @Override
    public Node next() {
      return super
          .next()
          .getSingleRelationship(RelTypes.LIST_ENTRY,
              Direction.OUTGOING).getEndNode();
    }
  }

  class NodeListIterator extends ElementListIterator {

    NodeListIterator(int index) {
      super(index);
    }

    @Override
    public Node next() {
      return super
          .next()
          .getSingleRelationship(RelTypes.LIST_ENTRY,
              Direction.OUTGOING).getEndNode();
    }

    @Override
    public Node previous() {
      return super
          .previous()
          .getSingleRelationship(RelTypes.LIST_ENTRY,
              Direction.OUTGOING).getEndNode();
    }
  }

  public static enum RelTypes implements RelationshipType {
    /**
     * A relationship which goes from the list node to the first element in
     * the list
     */
    FIRST_ELEMENT,

    /**
     * A relationship which goes from the list node to the last element in
     * the list
     */
    LAST_ELEMENT,

    /**
     * A relationship which points to the next entry in the list
     */
    NEXT_ELEMENT,

    /**
     * A relationship which points to the node added as entry in the list
     */
    LIST_ENTRY
  }

  class ReverseElementIterator implements Iterator<Node> {

    protected Node currentElement = underlyingNode;

    @Override
    public boolean hasNext() {
      if (currentElement.getId() == underlyingNode.getId()) {
        return currentElement.hasRelationship(RelTypes.LAST_ELEMENT,
            Direction.OUTGOING);
      } else {
        return currentElement.hasRelationship(RelTypes.NEXT_ELEMENT,
            Direction.INCOMING);
      }
    }

    @Override
    public Node next() {
      if (!hasNext())
        throw new NoSuchElementException();
      if (currentElement.getId() == underlyingNode.getId()) {
        currentElement = underlyingNode.getSingleRelationship(
            RelTypes.LAST_ELEMENT, Direction.OUTGOING)
            .getEndNode();
      } else {
        currentElement = currentElement.getSingleRelationship(
            RelTypes.NEXT_ELEMENT, Direction.INCOMING)
            .getStartNode();
      }
      return currentElement;
    }

    @Override
    public void remove() {
      throw new UnsupportedOperationException();
    }

  };

  class ReverseList implements Iterable<Node> {

    @Override
    public Iterator<Node> iterator() {
      return new ReverseNodeIterator();
    }

  }

  class ReverseNodeIterator extends ReverseElementIterator {

    @Override
    public Node next() {
      return super
          .next()
          .getSingleRelationship(RelTypes.LIST_ENTRY,
              Direction.OUTGOING).getEndNode();
    }
  }

  protected Node underlyingNode;

  protected GraphDatabaseService graphDb;

  private List outer = this;

  static final String INDEX_SIZE = "index_size";

  public List(Node listNode, GraphDatabaseService graphDb) {
    this.graphDb = graphDb;
    this.underlyingNode = listNode;
  }

  @Override
  public void add(int index, Node element) {
    if (index < 0 || index >= size())
      throw new IndexOutOfBoundsException();
    Relationship currentEntryRelation = underlyingNode
        .getSingleRelationship(RelTypes.FIRST_ELEMENT,
            Direction.OUTGOING);
    Node currentEntry = currentEntryRelation.getEndNode();
    if (index == 0) {
      currentEntryRelation.delete();
      Node newEntry = graphDb.createNode();
      underlyingNode.createRelationshipTo(newEntry,
          RelTypes.FIRST_ELEMENT);
      newEntry.createRelationshipTo(currentEntry, RelTypes.NEXT_ELEMENT);
      newEntry.createRelationshipTo(element, RelTypes.LIST_ENTRY);
      underlyingNode.setProperty(INDEX_SIZE, 1);
    } else {
      for (int i = 0; i < index; i++) {
        currentEntryRelation = currentEntry.getSingleRelationship(
            RelTypes.NEXT_ELEMENT, Direction.OUTGOING);
        currentEntry = currentEntryRelation.getEndNode();
      }
      Node prevEntry = currentEntryRelation.getStartNode();
      currentEntryRelation.delete();
      Node newEntry = graphDb.createNode();
      prevEntry.createRelationshipTo(newEntry, RelTypes.NEXT_ELEMENT);
      newEntry.createRelationshipTo(currentEntry, RelTypes.NEXT_ELEMENT);
      newEntry.createRelationshipTo(element, RelTypes.LIST_ENTRY);
      int i = (Integer) underlyingNode.getProperty(INDEX_SIZE);
      underlyingNode.setProperty(INDEX_SIZE, i+1);
    }
  }

  @Override
  public boolean add(Node e) {
    Node entry = graphDb.createNode();
    entry.createRelationshipTo(e, RelTypes.LIST_ENTRY);
    if (this.isEmpty()) {
      underlyingNode.createRelationshipTo(entry, RelTypes.FIRST_ELEMENT);
      underlyingNode.createRelationshipTo(entry, RelTypes.LAST_ELEMENT);
      underlyingNode.setProperty(INDEX_SIZE, 1);
    } else {
      Relationship lastElementRelation = underlyingNode
          .getSingleRelationship(RelTypes.LAST_ELEMENT,
              Direction.OUTGOING);
      Node lastElement = lastElementRelation.getEndNode();
      lastElementRelation.delete();
      lastElement.createRelationshipTo(entry, RelTypes.NEXT_ELEMENT);
      underlyingNode.createRelationshipTo(entry, RelTypes.LAST_ELEMENT);
      int i = (Integer) underlyingNode.getProperty(INDEX_SIZE);
      underlyingNode.setProperty(INDEX_SIZE, i+1);
    }
    return true;
  }

  @Override
  public boolean addAll(Collection<? extends Node> c) {
    for (Node n : c) {
      add(n);
    }
    return true;
  }

  @Override
  public boolean addAll(int index, Collection<? extends Node> c) {
    if (index < 0 || index >= size())
      throw new IndexOutOfBoundsException();
    Node firstElement = null;
    Node lastElement = null;

    for (Node n : c) {
      Node element = graphDb.createNode();
      if (firstElement == null) {
        firstElement = element;
        lastElement = element;
      } else {
        lastElement
            .createRelationshipTo(element, RelTypes.NEXT_ELEMENT);
        lastElement = element;
      }
      element.createRelationshipTo(n, RelTypes.LIST_ENTRY);
    }

    if (firstElement != null) {
      Relationship currentEntryRelation = underlyingNode
          .getSingleRelationship(RelTypes.FIRST_ELEMENT,
              Direction.OUTGOING);
      Node currentEntry = currentEntryRelation.getEndNode();
      if (index == 0) {
        currentEntryRelation.delete();
        underlyingNode.createRelationshipTo(firstElement,
            RelTypes.FIRST_ELEMENT);
        lastElement.createRelationshipTo(currentEntry,
            RelTypes.NEXT_ELEMENT);
        underlyingNode.setProperty(INDEX_SIZE, size()+c.size());
      } else {
        for (int i = 0; i < index; i++) {
          currentEntryRelation = currentEntry.getSingleRelationship(
              RelTypes.NEXT_ELEMENT, Direction.OUTGOING);
          currentEntry = currentEntryRelation.getEndNode();
        }
        Node prevEntry = currentEntryRelation.getStartNode();
        currentEntryRelation.delete();
        prevEntry.createRelationshipTo(firstElement,
            RelTypes.NEXT_ELEMENT);
        lastElement.createRelationshipTo(currentEntry,
            RelTypes.NEXT_ELEMENT);
        underlyingNode.setProperty(INDEX_SIZE, size()+c.size());
      }
    }
    return true;
  }

  @Override
  public void clear() {
    for (Iterator<Node> i = this.iterator(); i.hasNext();) {
      i.next();
      i.remove();
    }
  }

  @Override
  public boolean contains(Object o) {
    if (o instanceof Node) {
      for (Node node : this) {
        if (((Node)o).getId() == node.getId()) {
          return true;
        }
      }
      return false;
    } else
      throw new ClassCastException("Supplied object is not a Node");
  }

  @Override
  public boolean containsAll(Collection<?> c) {
    for (Object o : c) {
      if (!this.contains(o))
        return false;
    }
    return true;
  }

  public void delete() {
    clear();
    underlyingNode.removeProperty(INDEX_SIZE);
    underlyingNode.delete();
  }

  @Override
  public Node get(int index) {
    if (index < 0 || index >= size())
      throw new IndexOutOfBoundsException();
    Iterator<Node> it = iterator();
    for (int i = 0; i < this.size(); i++) {
      Node n = it.next();
      if (i == index)
        return n;
    }
    throw new IndexOutOfBoundsException();
  }

  /**
   * Returns the underlying node representing this timeline.
   *
   * @return The underlying node representing this timeline
   */
  public Node getUnderlyingNode() {
    return underlyingNode;
  }

  @Override
  public int indexOf(Object o) {
    if (o instanceof Node) {
      int i = 0;
      for (Node node : this) {
        if (((Node)o).getId() == node.getId()) {
          return i;
        }
        i++;
      }
      return -1;
    } else
      throw new ClassCastException("Supplied object is not a Node");
  }

  @Override
  public boolean isEmpty() {
    return !underlyingNode.hasRelationship(RelTypes.FIRST_ELEMENT,
        Direction.OUTGOING);
  }

  @Override
  public Iterator<Node> iterator() {
    return new NodeIterator(-1);
  }

  @Override
  public int lastIndexOf(Object o) {
    if (o instanceof Node) {
      int i = size() - 1 ;
      for (Node node : new ReverseList()) {
        if (((Node)o).getId() == node.getId()) {
          return i;
        }
        i--;
      }
      return -1;
    } else
      throw new ClassCastException("Supplied object is not a Node");
  }

  @Override
  public ListIterator<Node> listIterator() {
    return new NodeListIterator(-1);
  }

  @Override
  public ListIterator<Node> listIterator(int index) {
    if (index < 0 || index >= size())
      throw new IndexOutOfBoundsException();
    return new NodeListIterator(index);
  }

  @Override
  public Node remove(int index) {
    if (index < 0 || index >= size())
      throw new IndexOutOfBoundsException();
    Relationship currentEntryRelation = underlyingNode
        .getSingleRelationship(RelTypes.FIRST_ELEMENT,
            Direction.OUTGOING);
    Node currentEntry = currentEntryRelation.getEndNode();
    Node currentNode = currentEntry.getSingleRelationship(
        RelTypes.LIST_ENTRY, Direction.OUTGOING).getEndNode();
    Relationship lastEntryRelation = underlyingNode.getSingleRelationship(
        RelTypes.LAST_ELEMENT, Direction.OUTGOING);
    Node lastEntry = lastEntryRelation.getEndNode();
    if (index == 0) {
      currentEntryRelation.delete();
      if (currentEntry.getId() == lastEntry.getId()) {
        lastEntryRelation.delete();
        Relationship entryRelation = currentEntry
            .getSingleRelationship(RelTypes.LIST_ENTRY,
                Direction.OUTGOING);
        entryRelation.delete();
        currentEntry.delete();
        underlyingNode.setProperty(INDEX_SIZE, 0);

      } else {
        Relationship nextEntryRelation = currentEntry
            .getSingleRelationship(RelTypes.NEXT_ELEMENT,
                Direction.OUTGOING);
        Node nextEntry = nextEntryRelation.getEndNode();
        nextEntryRelation.delete();
        Relationship entryRelation = currentEntry
            .getSingleRelationship(RelTypes.LIST_ENTRY,
                Direction.OUTGOING);
        entryRelation.delete();
        currentEntry.delete();
        underlyingNode.createRelationshipTo(nextEntry,
            RelTypes.FIRST_ELEMENT);
        int i = (Integer) underlyingNode.getProperty(INDEX_SIZE);
        underlyingNode.setProperty(INDEX_SIZE, i-1);
      }
    } else {
      for (int i = 0; i < index; i++) {
        currentEntryRelation = currentEntry.getSingleRelationship(
            RelTypes.NEXT_ELEMENT, Direction.OUTGOING);
        currentEntry = currentEntryRelation.getEndNode();
      }
      currentNode = currentEntry.getSingleRelationship(
          RelTypes.LIST_ENTRY, Direction.OUTGOING).getEndNode();
      Node prevEntry = currentEntryRelation.getStartNode();
      currentEntryRelation.delete();
      if (currentEntry.getId() == lastEntry.getId()) {
        lastEntryRelation.delete();
        underlyingNode.createRelationshipTo(prevEntry,
            RelTypes.LAST_ELEMENT);
        Relationship entryRelation = currentEntry
            .getSingleRelationship(RelTypes.LIST_ENTRY,
                Direction.OUTGOING);
        entryRelation.delete();
        currentEntry.delete();
        int i = (Integer) underlyingNode.getProperty(INDEX_SIZE);
        underlyingNode.setProperty(INDEX_SIZE, i-1);
      } else {
        Relationship nextEntryRelation = currentEntry
            .getSingleRelationship(RelTypes.NEXT_ELEMENT,
                Direction.OUTGOING);
        Node nextEntry = nextEntryRelation.getEndNode();
        nextEntryRelation.delete();
        Relationship entryRelation = currentEntry
            .getSingleRelationship(RelTypes.LIST_ENTRY,
                Direction.OUTGOING);
        entryRelation.delete();
        currentEntry.delete();
        prevEntry
            .createRelationshipTo(nextEntry, RelTypes.NEXT_ELEMENT);
        int i = (Integer) underlyingNode.getProperty(INDEX_SIZE);
        underlyingNode.setProperty(INDEX_SIZE, i-1);
      }
    }
    return currentNode;
  }

  @Override
  public boolean remove(Object o) {
    int idx = indexOf(o);
    if (idx >= 0) {
      remove(idx);
      return true;
    } else
      return false;
  }

  @Override
  public boolean removeAll(Collection<?> c) {
    boolean changed = false;
    for (Object o : c) {
      if (o instanceof Node) {
        changed = true;
        remove(o);
      }
    }
    return changed;
  }

  @Override
  public boolean retainAll(Collection<?> c) {
    boolean changed = false;
    for (Iterator<Node> i = this.iterator(); i.hasNext();) {
      if (!c.contains(i.next())) {
        changed = true;
        i.remove();
      }
    }
    return changed;
  }

  @Override
  public Node set(int index, Node element) {
    if (index < 0 || index >= size())
      throw new IndexOutOfBoundsException();
    Node currentEntry = underlyingNode.getSingleRelationship(
        RelTypes.FIRST_ELEMENT, Direction.OUTGOING).getEndNode();
    for (int i = 0; i < index; i++) {
      currentEntry = currentEntry.getSingleRelationship(
          RelTypes.NEXT_ELEMENT, Direction.OUTGOING).getEndNode();
    }
    currentEntry.getSingleRelationship(RelTypes.LIST_ENTRY,
        Direction.OUTGOING).delete();
    currentEntry.createRelationshipTo(element, RelTypes.LIST_ENTRY);
    return element;
  }

  @Override
  public int size() {
    if (underlyingNode.hasProperty(INDEX_SIZE)) {
      return (Integer) underlyingNode.getProperty(INDEX_SIZE);
    } else {
      underlyingNode.setProperty(INDEX_SIZE, 0);
      return 0;
    }
  }

  @Override
  public java.util.List<Node> subList(int fromIndex, int toIndex) {
    throw new UnsupportedOperationException();
  }

  @Override
  public Object[] toArray() {
    Node[] nodeArray = new Node[this.size()];
    for (int i = 0; i < size(); i++) {
      nodeArray[i] = this.get(i);
    }
    return nodeArray;
  }

  @SuppressWarnings("unchecked")
  @Override
  public <T> T[] toArray(T[] a) {
    if (a instanceof Node[]) {
      if (a.length < this.size()) {
        return (T[]) toArray();
      } else {
        for (int i = 0; i < a.length; i++) {
          if (i <= this.size()) {
            a[i] = (T) this.get(i);
          } else {
            a[i] = null;
          }
        }
        return a;
      }
    } else
      throw new ArrayStoreException();
  }

}
TOP

Related Classes of org.neo4j.collections.list.List

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.