/*******************************************************************************
* Copyright (c) 2009-2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* * Bert Lisser - Bert.Lisser@cwi.nl (CWI)
* * Paul Klint - Paul.Klint@cwi.nl - CWI
* * Arnold Lankamp - Arnold.Lankamp@cwi.nl
*******************************************************************************/
package org.rascalmpl.eclipse.library.vis.figure.graph.lattice;
/**
*
* Lattice layout.
*
* This layout is activated by by the property: hint("lattice").
*
*
* @author bertl used A Genetic Algorithm for drawing ordered sets, Brian Loft
* and John Snow
*/
//public class LatticeGraph extends Figure implements
// Comparator<LatticeGraph.Organism> {
// private final int E = 20;
// private final int G = 20;
// protected ArrayList<LatticeGraphNode> nodes;
// protected ArrayList<LatticeGraphEdge> edges;
// private HashMap<String, LatticeGraphNode> registered;
// private final boolean debug = false;
// private LinkedList<LatticeGraphNode> nextLayer = new LinkedList<LatticeGraphNode>();
// Layer[] layers;
// final int border = 20;
// final int lmargin = 0;
// final TypeStore ts = new TypeStore();
// final TypeFactory tf = TypeFactory.getInstance();
// final Type propt, shapeCurved;
//
// private final int E2 = E * E;
//
// final private Random rand = new Random();
//
// final LinSolve linSolve = new LinSolve();
//
// // private static boolean debug = false;
// private LatticeGraphNode topNode = null, bottomNode = null;
// private HashMap<LatticeGraphNode, LatticeGraphNode> visit = new HashMap<LatticeGraphNode, LatticeGraphNode>();
//
// class Organism {
// double[][] x = new double[layers.length][],
// aux = new double[layers.length][];
//
// final double fitness;
//
// final int cut;
//
// private double fitnessDefinition() {
// set();
// return -LatticeGraph.this.Z();
// }
//
// Organism() {
// int i = 0;
// for (Layer ns : layers) {
// x[i] = new double[ns.data.size()];
// aux[i] = new double[ns.data.size()];
// i++;
// }
// init();
// mutate(20);
// cut = -1;
// fitness = fitnessDefinition();
// }
//
// private void mutate(int p) {
// final int r = rand.nextInt(x.length);
// mutate(r, p);
// }
//
// private boolean isTriggered(double x, double step) {
// double d = Math.abs((x - lmargin) / step);
// if (d - Math.floor(d) < 0.001)
// return false;
// return true;
// }
//
// private void mutate(int cut, int p) {
// final int n = x[cut].length;
// // final double step = width / (n + 1);
// for (int i = 0; i < p; i++)
// if (n > 0) {
// int m = rand.nextInt(n * 4);
// int k = m / 4;
// double s = x[cut][k];
// final int l = rand.nextInt(n);
// x[cut][k] = x[cut][l];
// x[cut][l] = s;
// /*
// * if (m%4==1 || m%4==3) { if (isTriggered(x[cut][k], step))
// * x[cut][k]-=step/2; else x[cut][k]+=step/2; } if (m%4==2
// * || m%4==3) { if (isTriggered(x[cut][l], step))
// * x[cut][l]-=step/2; else x[cut][l]+=step/2; }
// */
// }
// }
//
// Organism(Organism o) {
// for (int i = 0; i < o.x.length; i++) {
// x[i] = new double[o.x[i].length];
// aux[i] = new double[x[i].length];
// }
// for (int i = 0; i < o.x.length; i++)
// for (int j = 0; j < o.x[i].length; j++) {
// x[i][j] = o.x[i][j];
// }
// this.cut = o.cut;
// mutate(cut, 2);
// // System.err.println("After mutate");
// fitness = fitnessDefinition();
// }
//
// Organism(Organism o1, Organism o2) {
// for (int i = 0; i < o1.x.length; i++) {
// x[i] = new double[o1.x[i].length];
// aux[i] = new double[x[i].length];
// }
// cut = o1.x.length > 3 ? 1 + rand.nextInt(o1.x.length - 2) : 0;
// for (int i = 0; i < cut; i++)
// for (int j = 0; j < o1.x[i].length; j++) {
// x[i][j] = o1.x[i][j];
// }
// for (int i = cut; i < o2.x.length; i++)
// for (int j = 0; j < o2.x[i].length; j++) {
// x[i][j] = o2.x[i][j];
// }
// fitness = fitnessDefinition();
// }
//
// private void init() {
// int i = 0;
// for (Layer ns : layers) {
// for (int j = 0; j < ns.data.size(); j++)
// x[i][j] = ns.data.get(j).x;
// i++;
// }
// }
//
// void set() {
// int i = 0;
// for (Layer ns : layers) {
// for (int j = 0; j < ns.data.size(); j++) {
// aux[i][j] = ns.data.get(j).x;
// ns.data.get(j).x = x[i][j];
// }
// i++;
// }
// }
//
// void reset() {
// int i = 0;
// for (Layer ns : layers) {
// for (int j = 0; j < ns.data.size(); j++)
// ns.data.get(j).x = aux[i][j];
// i++;
// }
// }
//
// }
//
// class Layer {
// final int rank;
// final ArrayList<LatticeGraphNode> data;
// final double step;
//
// Layer(ArrayList<LatticeGraphNode> data, int rank) {
// this.data = data;
// this.rank = rank;
// this.step = (minSize.getHeight() - 2 * border) / layers.length;
// }
// }
//
// Organism[] elitePopulation;
//
// // Organism[][] islands;
//
// public LatticeGraph(IFigureConstructionEnv fpa, PropertyManager properties,
// IList nodes, IList edges) {
// super( properties);
// this.nodes = new ArrayList<LatticeGraphNode>();
// propt = tf.abstractDataType(ts, "propt");
// shapeCurved = tf.constructor(ts, propt, "shapeCurved", tf.boolType());
// minSize.setWidth(getWidthProperty());
// minSize.setHeight(getHeightProperty());
// // if (debug)
// System.err.println("LatticeGraph:"+minSize.getWidth()+" "+minSize.getHeight());
// registered = new HashMap<String, LatticeGraphNode>();
// for (IValue v : nodes) {
// IConstructor c = (IConstructor) v;
// Figure ve = FigureFactory.make(fpa, c, properties, null);
// String name = ve.getIdProperty();
// if (name.length() == 0)
// throw RuntimeExceptionFactory.figureException(
// "Id property should be defined", v,
// fpa.getRascalContext().getCurrentAST(), fpa.getRascalContext().getStackTrace());
// LatticeGraphNode node = new LatticeGraphNode(name, ve);
// this.nodes.add(node);
// register(name, node);
// }
//
// this.edges = new ArrayList<LatticeGraphEdge>();
// for (IValue v : edges) {
// IConstructor c = (IConstructor) v;
// LatticeGraphEdge e = FigureFactory.makeLatticeGraphEdge(this, fpa,
// c, properties);
// this.edges.add(e);
// e.getFrom().addOut(e.getTo());
// e.getTo().addIn(e.getFrom());
// }
//
// if (!isLattice())
// throw RuntimeExceptionFactory.figureException("Not a lattice",
// null, fpa.getRascalContext().getCurrentAST(), fpa.getRascalContext().getStackTrace());
//
// assignRank();
// computeReached();
// initialPlacement();
// elitePopulation = computeFirstElitePopulation();
// evolution();
// IValueFactory vf = ValueFactoryFactory.getValueFactory();
// for (LatticeGraphNode n : this.nodes)
// for (LatticeGraphEdge e : this.edges)
// if (!e.getFrom().equals(n) && !e.getTo().equals(n))
// if (linSolve.isOnEdge(e, n)) {
// // System.err.println("BINGO");
// PropertyManager ep = new PropertyManager(fpa,
// properties, vf.list(vf.constructor(shapeCurved,
// vf.bool(true))));
// e.prop = ep;
// }
// }
//
// public void register(String name, LatticeGraphNode nd) {
// registered.put(name, nd);
// }
//
// public LatticeGraphNode getRegistered(String name) {
// return registered.get(name);
// }
//
// private void initialPlacement() {
// int i = 0;
// double y = border;
// for (Layer layer : layers) {
// int s = layer.data.size();
// // System.err.println("layer.size:"+s);
// if (s > 0) {
// double step = minSize.getWidth() / (s + 1);
// // System.err.println("width:"+width);
// // System.err.println("step:"+step);
// // double x = i % 2 == 0 ? step / 2 : (width - step / 2);
// double x = lmargin + step;
// for (LatticeGraphNode n : layer.data) {
// // n.x = (double) (n.x*Math.cos(phi)+n.y*Math.sin(phi));
// n.x = x;
// n.y = y;
// // x += (i % 2 == 0 ? step : -step);
// x += step;
// // System.err.println("y:"+n.y);
// }
// int z = 0;
// for (int k = 0; k < s; k++) {
// LatticeGraphNode q = layer.data.get(k);
// for (int j = k + 1; j < s; j++) {
// if (q.isConnected(layer.data.get(j))) {
// z++;
// layer.data.get(j).y += (z * layer.step / s);
//
// }
// }
// }
// // System.err.println("Problematic:" + i + " " + z);
// y += layer.step;
// i++;
// }
// }
// }
//
// @Override
// public void draw(GraphicsContext gc) {
// applyProperties(gc);
// for (LatticeGraphEdge e : edges)
// e.draw(gc);
// for (LatticeGraphNode n : nodes) {
// n.draw(gc);
// }
// }
//
// /**
// * Draw focus around this figure
// */
// public void drawFocus(GraphicsContext gc) {
// // System.err.println("drawFocus: " + this.left);
// gc.stroke(FigureColorUtils.colorNames.get("red").intValue());
// gc.strokeWeight(1);
// gc.noFill();
// gc.rect(getLeft(), getTop(), minSize.getWidth(), minSize.getHeight());
// }
//
// private void evolution() {
// for (int i = 0; i < G; i++) {
// Arrays.sort(elitePopulation, this);
// elitePopulation = nextPopulation(elitePopulation);
// }
// Arrays.sort(elitePopulation, this);
// System.err.println("After evolution Fitness:"
// + +elitePopulation[0].fitness);
// elitePopulation[0].set();
// }
//
// public boolean isLattice() {
// boolean r1 = false, r2 = false;
// topNode = bottomNode = null;
// for (LatticeGraphNode n : nodes) {
// if (n.out.isEmpty()) {
// if (!r1)
// bottomNode = n;
// else
// bottomNode = null;
// r1 = true;
// }
// if (n.in.isEmpty()) {
// if (!r2)
// topNode = n;
// else
// topNode = null;
// r2 = true;
// }
// }
// return topNode != null && bottomNode != null;
// }
//
// private int assignRank(final boolean top) {
// LatticeGraphNode first = top ? topNode : bottomNode;
// nextLayer.add(first);
// visit.put(first, first);
// do {
// LinkedList<LatticeGraphNode> newLayer = new LinkedList<LatticeGraphNode>();
// while (!nextLayer.isEmpty()) {
// LatticeGraphNode node = nextLayer.remove();
// for (LatticeGraphNode n : (top ? node.out : node.in)) {
// LatticeGraphNode oldNode = visit.put(n, n);
// if (oldNode == null) {
// newLayer.add(n);
// if (top)
// n.rankTop = node.rankTop + 1;
// else
// n.rankBottom = node.rankBottom + 1;
// } else {
// if (top)
// oldNode.rankTop = node.rankTop + 1;
// else
// oldNode.rankBottom = node.rankBottom + 1;
// }
// }
// }
// nextLayer = newLayer;
// } while (!nextLayer.isEmpty());
// return top ? bottomNode.rankTop : topNode.rankBottom;
// }
//
// @SuppressWarnings("unchecked")
// private void assignRank() {
// visit.clear();
// int maxTop = assignRank(true);
// // System.err.println("maxTop:"+maxTop);
// visit.clear();
// int maxBottom = assignRank(false);
// // System.err.println("maxBottom:"+maxBottom);
// int len = maxBottom + maxTop + 1;
// ArrayList<LatticeGraphNode>[] layer = new ArrayList[len];
// for (int i = 0; i < len; i++)
// layer[i] = new ArrayList<LatticeGraphNode>();
// for (LatticeGraphNode n : nodes) {
// // n.rank = n.rankTop - n.rankBottom + maxBottom;
// n.rank = (n.rankBottom - n.rankTop + maxTop);
// layer[n.rank].add(n);
// }
// int k = 0;
// for (int i = 0; i < layer.length; i++) {
// if (i == 0 || i == layer.length - 1 || layer[i].size() > 1)
// k++;
// }
// this.layers = new Layer[k];
// k = -1;
// for (int i = 0; i < layer.length; i++) {
// if (i == 0 || i == layer.length - 1 || layer[i].size() > 1) {
// k++;
// this.layers[k] = new Layer(layer[i], k);
// } else
// for (LatticeGraphNode n : layer[i]) {
// layers[k].data.add(n);
// }
// }
// }
//
// private void computeReached(LatticeGraphNode node) {
// for (LatticeGraphNode n : node.in) {
// LatticeGraphNode oldNode = visit.put(n, n);
// if (oldNode == null)
// computeReached(n);
// node.reached.add(n);
// }
// for (LatticeGraphNode n : node.in)
// for (LatticeGraphNode m : n.reached)
// node.reached.add(m);
// }
//
// private void computeReached() {
// visit.clear();
// computeReached(bottomNode);
// }
//
// private boolean isLessThen(LatticeGraphNode a, LatticeGraphNode b) {
// return b.reached.contains(a);
// }
//
// private double C() {
// double r = 0;
// int i = 0;
// for (LatticeGraphNode n : nodes)
// for (LatticeGraphNode m : n.reached) {
// double t = (n.x - m.x) * (n.x - m.x) + (n.y - m.y) * (n.y - m.y);
// r += t;
// i++;
// }
// return r / i;
// }
//
// private double Y() {
// double r = 0;
// // int i = 0;
// for (Layer ns : layers) {
// for (LatticeGraphNode n : ns.data)
// for (LatticeGraphNode m : ns.data)
// if (!m.equals(n)) {
// final double k = (n.x - m.x) * (n.x - m.x);
// r += k;
// }
// }
// return r;
// }
//
// /* Number Of Crossings */
// private double Z() {
// int r = 0, s = 0;
// for (LatticeGraphEdge e1 : edges)
// for (LatticeGraphEdge e2 : edges)
// if (!e1.equals(e2)) {
// boolean b = linSolve.isCuttingPointInside(e1, e2);
// if (b)
// r++;
// else
// s++;
// }
// // System.err.println("r="+r+" s="+s+" t="+(r+s));
// return r;
// }
//
// private Organism[] computeFirstElitePopulation() {
// Organism[] result = new Organism[E2];
// for (int i = 0; i < E; i++) {
// Organism[] organism = new Organism[E2];
// for (int k = 0; k < E2; k++) {
// final Organism o = new Organism();
// organism[k] = o;
// }
// Arrays.sort(organism, this);
// for (int j = 0; j < E; j++) {
// result[i * E + j] = organism[j];
// }
// // System.err.println("Start Fitness:" + organism[0].fitness + " i="
// // + i);
// }
// Arrays.sort(result, this);
// result[0].set();
// System.err.println("Initial Fitness:" + result[0].fitness);
// return result;
// }
//
// private Organism[] nextPopulation(Organism[] p) {
// Organism[] result = new Organism[E2];
// for (int i = 0; i < E; i++)
// for (int j = 0; j < E; j++) {
// // System.err.println("i=" + i + " j=" + j);
// Organism o1 = new Organism(p[i], p[j]);
// Organism o2 = new Organism(o1);
// result[E * i + j] = (o1.fitness < o2.fitness) ? o2 : o1;
// }
// return result;
// }
//
// public int compare(Organism o1, Organism o2) {
// // The biggest first
// return FigureMath.round(o2.fitness - o1.fitness);
// }
//
// @Override
// public void bbox() {
// for(LatticeGraphNode g : nodes){
// g.bbox();
// }
// setNonResizable();
// super.bbox();
// }
//
//
// public boolean getFiguresUnderMouse(Coordinate c,Vector<Figure> result){
// if(!mouseInside(c.getX(), c.getY())) return false;
// boolean found = false;
// for(int i = nodes.size()-1 ; i >= 0 ; i--){
// if(nodes.get(i).figure != null && nodes.get(i).figure.getFiguresUnderMouse(c, result)){
// found=true;
// break;
// }
// }
// if(!found){
// for(int i = nodes.size()-1 ; i >= 0 ; i--){
// if(edges.get(i).getFiguresUnderMouse(c, result)){
// break;
// }
// }
// }
// addMeAsFigureUnderMouse(result);
// return true;
// }
//
// public void computeFiguresAndProperties(ICallbackEnv env){
// super.computeFiguresAndProperties(env);
// for(LatticeGraphNode node : nodes){
// node.figure.computeFiguresAndProperties(env);
// }
// }
//
//
// public void registerNames(NameResolver resolver){
// super.registerNames(resolver);
// for(LatticeGraphNode node : nodes){
// node.figure.registerNames(resolver);
// }
// }
//
// @Override
// public void layout() {
// size.set(minSize);
// for(LatticeGraphNode node : nodes){
// node.layout();
// }
// for(LatticeGraphEdge edge : edges){
// edge.layout();
// }
// }
//
//}