package com.iambookmaster.client.editor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import com.iambookmaster.client.beans.Paragraph;
import com.iambookmaster.client.beans.ParagraphConnection;
import com.iambookmaster.client.model.Model;
public class ModelOptimizer {
public static void arrange(Model model) {
new ModelArrange(model);
}
public static class ModelArrange {
private Model model;
private HashMap<Paragraph, ArrayList<ParagraphConnection>> links;
private Paragraph[][] map;
private HashSet<Paragraph> unused;
private int widht;
private int height;
private boolean removed;
private int strategy;
public ModelArrange(Model mod) {
model = mod;
unused = new HashSet<Paragraph>();
unused.addAll(model.getParagraphs());
if (unused.size() < 21) {
//nothing to do
return;
}
for (Paragraph paragraph : unused) {
paragraph.setX(0);
paragraph.setY(0);
}
ArrayList<ParagraphConnection> connections = model.getParagraphConnections();
links = new HashMap<Paragraph, ArrayList<ParagraphConnection>>(unused.size());
for (ParagraphConnection connection : connections) {
ArrayList<ParagraphConnection> list = links.get(connection.getFrom());
if (list==null) {
list = new ArrayList<ParagraphConnection>();
links.put(connection.getFrom(), list);
}
list.add(connection);
}
height = unused.size() / 3;
widht = Math.max(height/ 2 ,1)+1;
height = height + 1;
connections = null;
map = new Paragraph[widht][height];
Paragraph start = model.getStartParagraph();
//put from Start
placeParagraph(0,0,start,true);
//put unused paragraphs
while (unused.size()>0) {
Iterator<Paragraph> iterator = unused.iterator();
removed = false;
while (iterator.hasNext()) {
Paragraph paragraph = iterator.next();
//max deep
findPlaceAndPlace(0, 0, paragraph,false);
if (removed) {
//children were removed, restart
break;
} else {
//just remove
iterator.remove();
}
}
}
//read data
int maxX = 0;
int maxY = 0;
for (int i = 0; i < widht; i++) {
for (int j = 0; j < height; j++) {
if (map[i][j] != null) {
Paragraph paragraph = map[i][j];
paragraph.setX(i*150+500);
paragraph.setY(j*60+300);
if (paragraph.getX()>maxX) {
maxX = paragraph.getX();
}
if (paragraph.getY()+100>maxY) {
maxX = paragraph.getY();
}
}
}
}
if (maxX + 200 > model.getSettings().getMaxDimensionX()) {
model.getSettings().setMaxDimensionX(maxX+200);
}
if (maxY + 100 > model.getSettings().getMaxDimensionY()) {
model.getSettings().setMaxDimensionY(maxY+100);
}
}
private void placeParagraph(int x, int y, Paragraph paragraph,boolean remove) {
strategy++;
if (strategy>3) {
strategy = 0;
}
if (remove) {
unused.remove(paragraph);
removed = true;
}
map[x][y]=paragraph;
paragraph.setX(x);
paragraph.setY(y);
ArrayList<ParagraphConnection> list = links.get(paragraph);
boolean child=false;
if (list !=null && list.size()>0) {
//can place more
Iterator<ParagraphConnection> iterator = list.iterator();
while (iterator.hasNext()) {
ParagraphConnection connection = iterator.next();
if (unused.contains(connection.getTo())) {
//not in map yet
findPlaceAndPlace(x,y,connection.getTo(),true);
}
}
}
}
private void findPlaceAndPlace(int x, int y, Paragraph paragraph,boolean remove) {
int step=1;
while (true) {
switch (strategy) {
case 0:
if (placeTop(x,y,step,paragraph,remove)) {
return;
}
if (placeBottom(x,y,step,paragraph,remove)) {
return;
}
if (placeLeft(x,y,step,paragraph,remove)) {
return;
}
if (placeRight(x,y,step,paragraph,remove)) {
return;
}
break;
case 1:
if (placeLeft(x,y,step,paragraph,remove)) {
return;
}
if (placeBottom(x,y,step,paragraph,remove)) {
return;
}
if (placeRight(x,y,step,paragraph,remove)) {
return;
}
if (placeTop(x,y,step,paragraph,remove)) {
return;
}
break;
case 2:
if (placeBottom(x,y,step,paragraph,remove)) {
return;
}
if (placeLeft(x,y,step,paragraph,remove)) {
return;
}
if (placeRight(x,y,step,paragraph,remove)) {
return;
}
if (placeTop(x,y,step,paragraph,remove)) {
return;
}
break;
default:
if (placeRight(x,y,step,paragraph,remove)) {
return;
}
if (placeTop(x,y,step,paragraph,remove)) {
return;
}
if (placeLeft(x,y,step,paragraph,remove)) {
return;
}
if (placeBottom(x,y,step,paragraph,remove)) {
return;
}
break;
}
//extend step
step++;
}
}
private boolean placeRight(int x, int y, int step, Paragraph paragraph, boolean remove) {
int y1 = x+step;
if (y1<widht) {
//rigth line
int from = Math.max(y-step,0);
int to = Math.min(y+step,height);
for (int i = from; i < to; i++) {
if (map[y1][i]==null) {
//found place
placeParagraph(y1, i, paragraph,remove);
return true;
}
}
}
return false;
}
private boolean placeLeft(int x, int y, int step, Paragraph paragraph,boolean remove) {
int y1 = x-step;
if (y1>=0) {
//left line
int from = Math.max(y-step,0);
int to = Math.min(y+step,height);
for (int i = from; i < to; i++) {
if (map[y1][i]==null) {
//found place
placeParagraph(y1, i, paragraph,remove);
return true;
}
}
}
return false;
}
private boolean placeBottom(int x, int y, int step, Paragraph paragraph, boolean remove) {
int y1 = y + step;
if (y1<height) {
//bottom line
int from = Math.max(x-step,0);
int to = Math.min(x+step,widht);
for (int i = from; i < to; i++) {
if (map[i][y1]==null) {
//found place
placeParagraph(i, y1, paragraph,remove);
return true;
}
}
}
return false;
}
private boolean placeTop(int x, int y, int step, Paragraph paragraph, boolean remove) {
int y1 = y-step;
if (y1>=0) {
//top line
int from = Math.max(x-step,0);
int to = Math.min(x+step,widht);
for (int i = from; i < to; i++) {
if (map[i][y1]==null) {
//found place
placeParagraph(i, y1, paragraph,remove);
return true;
}
}
}
return false;
}
}
}