package graph;

import java.awt.Color;
import java.util.ArrayList;

import org.eclipse.elk.graph.ElkEdge;
import org.eclipse.elk.graph.ElkNode;

import bk.LayoutType;

/**
 * Ein Interface, welches die Methoden eines Knotens aus einem gelayerten
 * Graphen beschreibt (Ein Knoten kann dabei auch einen weiteren Graphen
 * beinhalten)
 * 
 * @author kolja
 *
 */
public interface LayeredGraphNode {
  /**
   * Gibt den originalen Elk Knoten zur�ck
   * 
   * @return
   */
  public ElkNode getOriginalNode();

  /**
   * set the shift of this node to the given value in the given layout
   * or in all layouts if the argument is null.
   * 
   * @param shift
   *          the value to set to
   * @param layout
   *          the layout
   */
  public void setShift(double shift, LayoutType layout);

  /**
   * get the shift of this node in the given layout
   * 
   * @param layout
   *          the layout
   * @return the shift
   */
  public double getShift(LayoutType layout);

  /**
   * set the sink of this node in the given layout
   * or in all layouts if the argument is null.
   * 
   * @param sink
   *          the sink
   * @param layout
   *          the layout
   */
  public void setSink(LayeredGraphNode sink, LayoutType layout);

  /**
   * get the sink of this node in the given layout
   * 
   * @param layout
   *          the layout
   * @return the sink
   */
  public LayeredGraphNode getSink(LayoutType layout);

  /**
   * checks if the x coordinate of the node is defined in the given layout
   * 
   * @param layout
   *          the layout
   * @return true iff the x coordinate is undefined
   */
  public boolean isXUndefined(LayoutType layout);

  /**
   * sets the align-attribute (the next node in the block) in the given layout
   * or in all layouts if the argument is null.
   * 
   * @param align
   *          the next node in the block
   * @param layout
   *          the layout
   */
  public void setAlign(LayeredGraphNode align, LayoutType layout);

  /**
   * get the next node in the block of this node (in the given layout)
   * 
   * @param layout
   *          the layout
   * @return the next node
   */
  public LayeredGraphNode getAlign(LayoutType layout);

  /**
   * sets the root node of this node in the given layout which identifies the
   * block that it belongs to 
   * or in all layouts if the argument is null.
   * 
   * @param root
   *          the new root node
   * @param layout
   *          the layout
   */
  public void setRoot(LayeredGraphNode root, LayoutType layout);

  /**
   * get the root node of this node in the given layout which identifies the
   * block that it belongs to
   * 
   * @param layout
   *          the layout
   * @return the root node
   */
  public LayeredGraphNode getRoot(LayoutType layout);

  /**
   * set the name of this node
   * 
   * @param name
   *          the name
   */
  public void setName(String name);

  /**
   * get the name of this node
   * 
   * @return the name
   */
  public String getName();

  /**
   * set the display color of this node in the given layout
   * or in all layouts if the argument is null.
   * 
   * @param c
   *          the color
   * @param layout
   *          the layout
   */
  public void setColor(Color c, LayoutType layout);

  /**
   * check the display color of this node in the given layout.
   * @param layout the layout
   * @return the color
   */
  public Color getColor(LayoutType layout);
  
  /**
   * check the color of this nodes class in the given layout
   * or in all layouts if the argument is null.
   * @param layout the layout
   * @return the color
   */
  public Color getClassColor( LayoutType layout );
  
  /**
   * mark the node as "selected" in the given layout
   * or in all layouts if the argument is null.
   * @param layout
   */
  public void setSelected(LayoutType layout);

  /**
   * checks if the node is selected in the given layout
   * @param layout
   * @return
   */
  public boolean isSelected(LayoutType layout);

  /**
   * sets whether this node is a dummy node
   * @param dummy is it?
   */
  public void setDummyNode(boolean dummy);


  /**
   * checks whether this node is a dummy node
   * @param dummy is it?
   */
  public boolean isDummyNode();

  /**
   * unselects the subgraph of this node
   */
  public void unselectGraph();

  /**
   * Setzt den Index des Layers, zu dem der Knoten geh�ren soll
   * 
   * @param index
   *          Der Index mit 0 beginnend
   */
  public void setLayer(int index);

  /**
   * Gibt den Index des Layers zur�ck, dem dieser Knoten angeh�rt
   * 
   * @return Der Index des Layers mit 0 beginnend
   */
  public int getLayer();

  /**
   * Entfernt den Knoten aus dem Graphen
   */
  public void remove();

  /**
   * Ermittelt eine Liste von Kanten, die an diesem Knoten beginnen
   * 
   * @return Liste mit Kanten
   */
  public ArrayList<LayeredGraphEdge> getOutgoingEdges();

  /**
   * Ermittelt eine Liste von Kanten, die an diesem Knoten enden
   * 
   * @return Liste mit Kanten
   */
  public ArrayList<LayeredGraphEdge> getIncomingEdges();

  /**
   * Ermittelt eine Liste von Kanten, die an diesem Knoten beginnen
   * 
   * @return Liste mit Kanten sortiert nach den positionen der Endknoten in
   *         ihrem layer
   */
  public ArrayList<LayeredGraphEdge> getSortedOutgoingEdges();

  /**
   * Ermittelt eine Liste von Kanten, die an diesem Knoten enden
   * 
   * @return Liste mit Kanten sortiert nach den positionen der Startknoten in
   *         ihrem layer
   */
  public ArrayList<LayeredGraphEdge> getSortedIncomingEdges();

  /**
   * Gibt den Knoten zur�ck, zu dessen Subgraph dieser Knoten geh�rt
   * 
   * @return Der Elternknoten
   */
  public LayeredGraphNode parent();

  /**
   * Legt den Knoten fest, zu dessen Subgraph dieser Knoten geh�rt
   * 
   * @param parent
   *          Der Elternknoten
   */
  public void setParent(LayeredGraphNode parent);

  /**
   * Legt die X Koordinate des Knotens fest
   * 
   * @param x
   *          die X Koordinate in Pixeln
   */
  public void setX(double x, boolean def, LayoutType layout);

  /**
   * Legt die Y Koordinate des Knotens Fest
   * 
   * @param y
   *          die Y Koordinate in Pixeln
   */
  public void setY(double y, LayoutType layout);

  /**
   * Gibt die X Koordinate zur�ck
   * 
   * @return die X Koordinate in Pixeln zur�ck
   */
  public double getX(LayoutType layout);

  /**
   * Gibt die Y Koordinate zur�ck
   * 
   * @return die Y Koordinate in Pixeln zur�ck
   */
  public double getY(LayoutType layout);

  /**
   * Gibt die Breite des Knotens zur�ck
   * 
   * @return die Breite in Pixeln
   */
  public double getWidth(LayoutType layout);

  /**
   * Gibt die H�he des Knotens zur�ck
   * 
   * @return die H�he in Pixeln
   */
  public double getHeight(LayoutType layout);

  public void setWidth(double w, LayoutType layout);

  public void setHeight(double h, LayoutType layout);

  // for subgraph

  /**
   * Ermittelt den Index des Layers, dem ein Knoten angeh�rt
   * 
   * @param n
   *          der Knoten, zu dem der Layerindex gesucht wird
   * @return der Index des Layers mit 0 beginnend
   */
  public int getNodeLayer(LayeredGraphNode n);

  /**
   * Sortiert einen Layer nach bestimmten Gewichten Die Knoten mit dem
   * geringsten Gewicht kommen vor den Knoten mit gr��erem Gewicht
   * 
   * @param indizes
   *          Eine Liste mit einem Gewicht f�r jeden Knoten
   * @param layerIndex
   *          Der Index des Layers, der sortiert werden soll
   */
  public void setOrderedLayer(ArrayList<Double> indizes, int layerIndex);

  /**
   * Legt fest zu welchem Layer ein bestimmter Knoten geh�rt
   * 
   * @param n
   *          Der Knoten
   * @param index
   *          Der Index des Layers
   */
  public void setNodeLayer(LayeredGraphNode n, int index);

  /**
   * @return Eine Liste mit allen Kanten des Subgraphen
   */
  public ArrayList<LayeredGraphEdge> getContainedEdges();

  /**
   * @return Eine Liste mit allen Knoten des Subgraphen
   */
  public ArrayList<LayeredGraphNode> getContainedNodes();

  /**
   * @return Eine Liste mit allen Knoten des Subgraphen sortiert nach Layern und
   *         Positionen
   */
  public ArrayList<LayeredGraphNode> getSortedContainedNodes();

  /**
   * @return Eine Liste mit allen Layern des Subgraphen
   */
  public ArrayList<ArrayList<LayeredGraphNode>> getContainedLayers();

  /**
   * Entfernt eine Kante aus dem Subgraph
   * 
   * @param e
   *          die Kante, die entfernt werden soll
   */
  public void removeEdge(LayeredGraphEdge e);

  /**
   * Entfernt einen Knoten aus dem Subgraph
   * 
   * @param n
   *          der Knoten, die entfernt werden soll
   */
  public void removeNode(LayeredGraphNode n);

  /**
   * Ermittelt eine Liste von ausgehenden Kanten eines Knotens
   * 
   * @param n
   *          Der Knoten
   * @return Die Liste mit Kanten
   */
  public ArrayList<LayeredGraphEdge> getOutgoingEdges(LayeredGraphNode n);

  /**
   * Ermittelt eine Liste von ausgehenden Kanten eines Knotens
   * 
   * @param n
   *          Der Knoten
   * @return Die Liste mit Kanten sortiert nach den positionen der Endknoten in
   *         ihren Layern
   */
  public ArrayList<LayeredGraphEdge> getSortedOutgoingEdges(LayeredGraphNode n);

  /**
   * Ermittelt eine Liste von eingehenden Kanten eines Knotens
   * 
   * @param n
   *          Der Knoten
   * @return Die Liste mit Kanten
   */
  public ArrayList<LayeredGraphEdge> getIncomingEdges(LayeredGraphNode n);

  /**
   * Ermittelt eine Liste von eingehenden Kanten eines Knotens
   * 
   * @param n
   *          Der Knoten
   * @return Die Liste mit Kanten sortiert nach den positionen der Startknoten
   *         in ihren Layern
   */
  public ArrayList<LayeredGraphEdge> getSortedIncomingEdges(LayeredGraphNode n);

  /**
   * Ermittelt die Kante zwischen zwei Knoten
   * @param source Der Source Knoten der Kante
   * @param target Der Target Knoten der Kante
   * @return noll, falls die Kante nicht existiert. Sonst die Kante von source nach target
   */
  public LayeredGraphEdge findEdgeBetween( LayeredGraphNode source, LayeredGraphNode target );
  
  /**
   * F�gt einen neuen Knoten zum Subgraph hinzu
   * 
   * @param original
   *          Der originale Elk Knoten
   * @return Der neu erzeugte Knoten
   */
  public LayeredGraphNode createNode(ElkNode original);

  /**
   * F�gt eine neue Kante zum Subgraph hinzu
   * 
   * @param original
   *          Die Originale Elk Kante
   * @param sources
   *          Eine Liste mit Startknoten
   * @param targets
   *          Eine Liste mit Endknoten
   * @return Die neue Kante
   */
  public LayeredGraphEdge createEdge(ElkEdge original, ArrayList<LayeredGraphNode> sources,
      ArrayList<LayeredGraphNode> targets);

  /**
   * F�gt eine neue Kante zum Subgraph hinzu
   * 
   * @param original
   *          Die Originale Elk Kante
   * @param source
   *          Der Startknoten
   * @param target
   *          Der Endknoten
   * @return Die neue Kante
   */
  public LayeredGraphEdge createSimpleEdge(ElkEdge original, LayeredGraphNode source,
      LayeredGraphNode target);

  /**
   * Findet zu einer Originalen Kante eine Layered Kante
   * 
   * @param original
   *          die originale Kante
   * @return die layered Kante
   */
  public LayeredGraphEdge findEdgeFromOriginal(Object original);

  /**
   * Findet zu einem Originalen Knoten einen Layered Knoten
   * 
   * @param original
   *          der originale Knoten
   * @return der layered Knoten
   */
  public LayeredGraphNode findNodeFromOriginal(Object original);

  /**
   * Find a node with a given name whose parent node is this node.
   * @param name the name to search for
   * @return the node or {@code null} if no node was found.
   */
  public LayeredGraphNode findNodeByName(String name);

  /**
   * F�gt einen Knoten zum Subgraphen hinzu
   * 
   * @param n
   *          Der neue Knoten
   */
  public void addNode(LayeredGraphNode n);

  /**
   * F�gt eine Kante zum Subgraphen hinzu
   * 
   * @param e
   *          Die neue Kante
   */
  public void addEdge(LayeredGraphEdge e);
}
