package tree;

import java.util.List;
import java.util.LinkedList;
import java.util.Collections;
import java.util.Iterator;

public class TreeNode implements DrawableTreeNode {
  static final List<TreeNode> EMPTY_LIST = Collections.emptyList();
  private String label;
  private List<? extends TreeNode> children;
  private double x;
  private double maxX;
  private double minX;
  private int height;

  public TreeNode(String label) {
    this(label, EMPTY_LIST);
  }
  public TreeNode(String label, List<? extends TreeNode> children) {
    this.label = label;
    this.children = children;
    for (TreeNode child : children)
      if (height <= child.height)
        height = child.height + 1;
  }
  public String getLabel() {
    return label;
  }
  public List<? extends DrawableTreeNode> getChildren() {
    return children;
  }
  public double getX() {return x;}
  public void setX(double newx) {x=newx;}
  public double getMinX() {return minX;}
  public void setMinX(double newMinX) {minX=newMinX;}
  public double getMaxX() {return maxX;}
  public void setMaxX(double newMaxX) {maxX=newMaxX;}
  public int getHeight() {return height;}

    public String toString(){
	StringBuilder s = new StringBuilder();
	s.append("(");
	s.append(label);
	for (TreeNode child : children){
	    s.append(child.toString());
	}
	s.append(")");
	return s.toString();
    }

  public void position(double nextLeafX) {
    minX = nextLeafX;
    double firstson = nextLeafX;
    double lastson = nextLeafX;
    if (!children.isEmpty()) {
	boolean isfirstson=true;
	for (TreeNode pp : children) {
	    pp.position(nextLeafX);
	    nextLeafX = pp.getMaxX() + 1;
	    lastson = pp.getX();
	    if (isfirstson) {firstson = pp.getX();isfirstson=false;}
	}
	--nextLeafX;
    }
    maxX = nextLeafX;
    x = (firstson + lastson) / 2;
  }

    public void rel2abs(double lastX){
	x+=lastX;
	minX = x;
	maxX = x;
	double currentx = x;
	for (TreeNode child : children){
	    child.rel2abs(currentx);
	    if (child.getMinX()<minX) minX=child.getMinX();
	    if (child.getMaxX()>maxX) maxX=child.getMaxX();
	    currentx=child.getX();
	}
    }

    TreeNode mirrors(){
	LinkedList<TreeNode> mirrorChildren = new LinkedList<TreeNode>();
	for (TreeNode child : children)
	    mirrorChildren.addFirst(child.mirrors());
	TreeNode tree =  new TreeNode(label,mirrorChildren);
	tree.setX(-x);
	tree.setMinX(-maxX);
	tree.setMaxX(-minX);
	return tree;
    }

    void fusion(DrawableTreeNode tree){
	x=(x+tree.getX())/2;
	minX=(minX+tree.getMinX())/2;
	maxX=(maxX+tree.getMaxX())/2;
	Iterator<? extends TreeNode> myChildren = children.iterator();
	Iterator<? extends DrawableTreeNode> yourChildren = tree.getChildren().iterator();
 	while (myChildren.hasNext()&&yourChildren.hasNext()){
	    myChildren.next().fusion(yourChildren.next());
	}
    }

    public void symposition(){
	TreeNode tree = new TreeWithContours(mirrors());
	tree.rel2abs(0);
	fusion(tree.mirrors());
    }
}

