package l23_3;

public class BinaryTree {
	private TreeNode root;
	private static boolean trace;

	// Note... default constructor initializes root to null... good nuff

	public static void startTrace() { trace = true; }

	public static void stopTrace() { trace = false; }

	public void pushOrder(int payload) {
		if (root == null) root = new TreeNode(payload);
		else pushOrder(payload, root);
		if (trace) { 
			System.out.println("pushOrder(" + payload + ") : ");
			printGraph();
		}
	}

	private void pushOrder(int payload, TreeNode after) {
		if (payload < after.getPayload()) {
			if (after.getLeft() == null) after.setLeft(new TreeNode(payload));
			else pushOrder(payload, after.getLeft());
		} else {
			if (after.getRight() == null) after.setRight(new TreeNode(payload));
			else pushOrder(payload, after.getRight());
		}
	}
	
	public int size() {
		return size(root);
	}
	
	private int size(TreeNode from) {
		if (from==null) return 0;
		return 1+size(from.left) +size(from.right);
	}
	
	public int depth() {
		return depth(root);
	}
	
	private int depth(TreeNode from) {
		if (from==null) return 0;
		int dl=depth(from.left);
		int dr=depth(from.right);
		return 1+(dl>dr?dl:dr);
	}
	
	public int sum() { return sum(root); }
	
	private int sum(TreeNode from) {
		if (from==null) return 0;
		return from.payload + sum(from.left) + sum(from.right);
	}

	@Override
	public String toString() {
		if (root == null) return "empty";
		return toStringNLR(root);
	}

	private String toStringLNR(TreeNode from) {
		String result = "";
		if (from.getLeft() != null) result = toStringLNR(from.getLeft());
		result += from.toString();
		if (from.getRight() != null) result += toStringLNR(from.getRight());
		return result;
	}
	
	private String toStringNLR(TreeNode from) {
		String result = from.toString();
		if (from.getLeft() != null) result += toStringNLR(from.getLeft());
		if (from.getRight() != null) result += toStringNLR(from.getRight());
		return result;
	}
	
	private String toStringRNL(TreeNode from) {
		String result = "";
		if (from.getRight() != null) result = toStringRNL(from.getRight());
		result += from.toString();
		if (from.getLeft() != null) result += toStringRNL(from.getLeft());
		return result;
	}
	
	public void printGraph() {
		if (root==null) System.out.println("empty");
		else printGraph("","","",root);
	}
	
	private void printGraph(String b4root, String atRoot, String aftRoot,TreeNode from) {
		if (from.left!=null) {
			printGraph(b4root+"   ",b4root+"  -",b4root+"  |",from.left);
		}
		System.out.println(atRoot + String.format("%2d",from.payload) + ((from.left!=null || from.right!=null)? "+": ""));
		if (from.right!=null) {
			printGraph(aftRoot+"  |",aftRoot+"  -",aftRoot+"   ",from.right);
		}
	}

	private class TreeNode {
		private int payload;
		private TreeNode left;
		private TreeNode right;

		public TreeNode(int payload) {
			this.payload = payload;
			this.left = null;
			this.right = null;
		}

		public TreeNode getLeft() { return left; }

		public void setLeft(TreeNode left) { this.left = left; }

		public TreeNode getRight() { return right; }

		public void setRight(TreeNode right) { this.right = right; }

		public int getPayload() { return payload; }

		@Override
		public String toString() {
			return "[" + ((left == null) ? "null" : left.getPayload()) + "<-" + payload + "->"
					+ ((right == null) ? "null" : right.getPayload()) + "]";
		}

	}

}
