package demo.view;

import java.awt.EventQueue;
import java.awt.geom.Line2D;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import y.base.Edge;
import y.base.Node;
import y.layout.circular.SingleCycleLayouter;
import y.view.ArcEdgeRealizer;
import y.view.Graph2D;

/**
 * Demonstrates how to layout a circular graph with
 * SingleCycleLayouter. The edges of the graph
 * will be represented as arcs.
 */
public class SingleCycleDemo extends ViewActionDemo {
  
  public SingleCycleDemo() {
    Graph2D graph = view.getGraph2D();
    
    //create circular graph
    Node first = graph.createNode();
    Node last = first;
    for(int i = 0; i < 5; i++) {
      Node v = graph.createNode();
      graph.createEdge(last,v);
      last = v;
    }
    graph.createEdge(last, first);
    
    //splitNode construction
    Map splitMap = new HashMap();
    Edge[] edges = graph.getEdgeArray();
    for(int i = 0; i < edges.length; i++) {
      Edge e = edges[i];
      Node splitNode = graph.createNode();
      graph.createEdge(e.source(), splitNode);
      graph.createEdge(splitNode, e.target());
      graph.setSize(splitNode, 1, 1);
      splitMap.put(splitNode, e);
    }
    
    //layout extended graph
    SingleCycleLayouter layouter = new SingleCycleLayouter();
    layouter.doLayout(graph);
    
    for(Iterator iter = splitMap.keySet().iterator(); iter.hasNext();) {
      Node splitNode = (Node)iter.next();
      Edge e = (Edge)splitMap.get(splitNode);
      
      //set up an arc edge realizer that uses the splitNode
      //coordinate as its reference point for height calculation
      ArcEdgeRealizer arc = new ArcEdgeRealizer();
      graph.setRealizer(e, arc);
      arc.setArcType(ArcEdgeRealizer.FIXED_HEIGHT);
      Line2D line = new Line2D.Double(
      graph.getCenterX(e.source()),
      graph.getCenterY(e.source()),
      graph.getCenterX(e.target()),
      graph.getCenterY(e.target()));
      float dist = (float)line.ptLineDist(
      graph.getCenterX(splitNode),
      graph.getCenterY(splitNode));
      
      arc.setHeight(-dist);
      //note: use "dist" if cycle orientation is the other way around
      
      //remove temporary splitNodes again
      graph.removeNode(splitNode);
    }
    
    view.fitContent();
    graph.updateViews();
  }
  
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        initLnF();
        new SingleCycleDemo().start("Single Cycle Demo");
      }
    });
  }
}
