/**
 * Title:        ProAlign<p>
 * Description:  <p>
 * Copyright:    Copyright (c) Ari Loytynoja<p>
 * License:      GNU GENERAL PUBLIC LICENSE<p>
 * @see          http://www.gnu.org/copyleft/gpl.html
 * Company:      ULB<p>
 * @author Ari Loytynoja
 * @version 1.0
 */
package proalign;

class TreeNode {

    String tree;
    String[] subTrees;
    String[] revTrees;
    static String mpTree;

    TreeNode parent;
    TreeNode child0;
    TreeNode child1;

    static float halfLength;
    static float maxSpan;
    static float minDiff;
    float[] subDistances;
    float maxLength = 0f;
    float totalDist = 0f; // weight


    boolean isLast = true;

    TreeNode(String t) {

	mpTree = new String();
	minDiff = 100f;

	ProAlign.log("TreeNode");

	tree = t;
	TreeReader tr = new TreeReader();

	subTrees = tr.divideTree(tree);
	subDistances = tr.distance;
	subDistances[0] = Math.abs(subDistances[0]);
	subDistances[1] = Math.abs(subDistances[1]);

//	System.out.println(subTrees[0]+" "+subTrees[1]);

	float tot = subDistances[0]+subDistances[1];
	revTrees = new String[2];
	revTrees[0] = subTrees[1]+":"+tot;
	revTrees[1] = subTrees[0]+":"+tot;

	child0 = new TreeNode(tr,subTrees[0],TreeNode.this,0);
	child1 = new TreeNode(tr,subTrees[1],TreeNode.this,1);

	totalDist = subDistances[0]+subDistances[1]+
	    child0.totalDist+child1.totalDist;

	float currPair = subDistances[0]+child0.maxLength+
	    subDistances[1]+child1.maxLength;
	if(currPair > TreeNode.maxSpan) {
	    TreeNode.maxSpan = currPair;
//	    System.out.println("ms0 "+child0.tree+":"+subDistances[0]+" | "+
//			       child1.tree+":"+subDistances[1]+" "+currPair);
	}
    }

    TreeNode(TreeReader tr,String t,TreeNode p,int branch) {

	tree = t;
	parent = p;

	if(tree.indexOf(",")>0) {

	    isLast = false;
	    subTrees = tr.divideTree(tree);
	    subDistances = tr.distance;
	    subDistances[0] = Math.abs(subDistances[0]);
	    subDistances[1] = Math.abs(subDistances[1]);
	    
	    revTrees = new String[2];
	    revTrees[0] = "("+parent.revTrees[branch]+","+
		subTrees[1]+":"+subDistances[1]+"):"+subDistances[0];
	    revTrees[1] = "("+parent.revTrees[branch]+","+
		subTrees[0]+":"+subDistances[0]+"):"+subDistances[1];

	    child0 = new TreeNode(tr,subTrees[0],TreeNode.this,0);
	    child1 = new TreeNode(tr,subTrees[1],TreeNode.this,1);

	    totalDist = subDistances[0]+subDistances[1]+
		child0.totalDist+child1.totalDist;

	    float currPair = subDistances[0]+child0.maxLength+
		subDistances[1]+child1.maxLength;
	    if(currPair > TreeNode.maxSpan) {
		TreeNode.maxSpan = currPair;
//		System.out.println("ms1 "+child0.tree+":"+subDistances[0]+" | "+
//				   child1.tree+":"+subDistances[1]+" "+currPair);
	    }
	    if(subDistances[0]+child0.maxLength > subDistances[1]+child1.maxLength) {
		maxLength = subDistances[0]+child0.maxLength;
	    } else {
		maxLength = subDistances[1]+child1.maxLength;
	    }
//	    System.out.println("ml "+maxLength);
	}
    }

    String findMiddlePoint() {

	TreeNode.halfLength = TreeNode.maxSpan/2f;	

	if(TreeNode.halfLength > child0.maxLength && 
	   TreeNode.halfLength < child0.maxLength+subDistances[0]+subDistances[1]) {

	    float b0 = TreeNode.halfLength-child0.maxLength;
	    float b1 = subDistances[0]+subDistances[1]-b0;

	    TreeNode.mpTree = "("+child0.tree+": "+b0+","+child1.tree+":"+b1+");";		    
	}

	child0.findMiddle(1);
	child1.findMiddle(0);
	ProAlign.log("mprooted: "+TreeNode.mpTree);
	return TreeNode.mpTree;
    }

    void findMiddle(int branch) {
	if(!isLast) {

	    if(branch==0) {

		if(TreeNode.halfLength > child0.maxLength && 
		   TreeNode.halfLength < child0.maxLength+subDistances[0]) {

		    float b0 = TreeNode.halfLength-child0.maxLength;
		    float b1 = subDistances[0]-b0;
			
		    TreeNode.mpTree = "("+child0.tree+": "+b0+",("+parent.revTrees[1]+","+
			subTrees[1]+":"+subDistances[1]+"):"+b1+");";		    
			
//		    System.out.println("nt "+branch+": "+child0.tree+" "+child0.maxLength+" "+
//		     child1.tree+" "+child1.maxLength+" "+TreeNode.halfLength+" "+TreeNode.minDiff);
		}

		if(TreeNode.halfLength > child1.maxLength && 
		   TreeNode.halfLength < child1.maxLength+subDistances[1]) {

		    float b0 = TreeNode.halfLength-child1.maxLength;
		    float b1 = subDistances[1]-b0;

		    TreeNode.mpTree = "("+child1.tree+": "+b0+",("+parent.revTrees[1]+","+
			subTrees[0]+":"+subDistances[0]+"):"+b1+");";

//		    System.out.println("nt "+branch+": "+child0.tree+" "+child0.maxLength+" "+
//		      child1.tree+" "+child1.maxLength+" "+TreeNode.halfLength+" "+TreeNode.minDiff);

		}
		child0.findMiddle(1);
		child1.findMiddle(0);

	    } else {

		if(TreeNode.halfLength > child0.maxLength && 
		   TreeNode.halfLength < child0.maxLength+subDistances[0]) {

		    float b0 = TreeNode.halfLength-child0.maxLength;
		    float b1 = subDistances[0]-b0;

		    TreeNode.mpTree = "("+child0.tree+": "+b0+",("+parent.revTrees[0]+
			","+subTrees[1]+":"+subDistances[1]+"):"+b1+");";

//		    System.out.println("nt "+branch+": "+child0.tree+" "+child0.maxLength+" "+
//		      child1.tree+" "+child1.maxLength+" "+TreeNode.halfLength+" "+TreeNode.minDiff);

		}


		if(TreeNode.halfLength > child1.maxLength && 
		   TreeNode.halfLength < child1.maxLength+subDistances[1]) {

		    float b0 = TreeNode.halfLength-child1.maxLength;
		    float b1 = subDistances[1]-b0;

		    TreeNode.mpTree = "("+child1.tree+": "+b0+",("+parent.revTrees[0]+
			","+subTrees[0]+":"+subDistances[0]+"):"+b1+");";

//		    System.out.println("nt "+branch+": "+child0.tree+" "+child0.maxLength+" "+
//		      child1.tree+" "+child1.maxLength+" "+TreeNode.halfLength+" "+TreeNode.minDiff);

		}
		child0.findMiddle(1);
		child1.findMiddle(0);
	    }
	}
    }


/*
This was the first attempt for the tree rooting. Not used anymore.
*/

    String findMiddleWeightPoint() {
	TreeNode.halfLength = totalDist/2f;
	child0.findMiddle(1);
	child1.findMiddle(0);
	ProAlign.log("mprooted: "+TreeNode.mpTree);
	return TreeNode.mpTree;
    }

    void findMiddleWeight(int branch) {
	if(!isLast) {

	    if(branch==0) {
		if(Math.abs(TreeNode.halfLength-child0.totalDist)<TreeNode.minDiff) {
		    
		    TreeNode.minDiff = Math.abs(TreeNode.halfLength-child0.totalDist);
		    float b0,b1;
		    if(TreeNode.halfLength>child0.totalDist) {
			b0 = TreeNode.halfLength-child0.totalDist;
			b1 = subDistances[0]-b0;
		    } else if(subDistances[0]>0.001f) {
			b0 = 0.001f;
			b1 = subDistances[0]-b0;
		    } else {
			b0 = 0f;
			b1 = subDistances[0];
		    }
		    TreeNode.mpTree = "("+child0.tree+": "+b0+",("+parent.revTrees[1]+","+
			subTrees[1]+":"+subDistances[1]+"):"+b1+");";		    
		}

		if(Math.abs(TreeNode.halfLength-child1.totalDist)<TreeNode.minDiff) {
		    
		    TreeNode.minDiff = Math.abs(TreeNode.halfLength-child1.totalDist);
		    float b0,b1;
		    if(TreeNode.halfLength>child1.totalDist) {
			b0 = TreeNode.halfLength-child1.totalDist;
			b1 = subDistances[1]-b0;
		    } else if(subDistances[1]>0.001f) {
			b0 = 0.001f;
			b1 = subDistances[1]-b0;
		    } else {
			b0 = 0f;
			b1 = subDistances[1];
		    }
		    TreeNode.mpTree = "("+child1.tree+": "+b0+",("+parent.revTrees[1]+","+
			subTrees[0]+":"+subDistances[0]+"):"+b1+");";
		}
		child0.findMiddle(1);
		child1.findMiddle(0);

	    } else {
		if(Math.abs(TreeNode.halfLength-child0.totalDist)<TreeNode.minDiff) {

		    TreeNode.minDiff = Math.abs(TreeNode.halfLength-child0.totalDist);
		    float b0,b1;
		    if(TreeNode.halfLength>child0.totalDist) {
			b0 = TreeNode.halfLength-child0.totalDist;
			b1 = subDistances[0]-b0;
		    } else if(subDistances[0]>0.001f) {
			b0 = 0.001f;
			b1 = subDistances[0]-b0;
		    } else {
			b0 = 0f;
			b1 = subDistances[0];	
		    }
		    TreeNode.mpTree = "("+child0.tree+": "+b0+",("+parent.revTrees[0]+
			","+subTrees[1]+":"+subDistances[1]+"):"+b1+");";
		}

		if(Math.abs(TreeNode.halfLength-child1.totalDist)<TreeNode.minDiff) {
		    
		    TreeNode.minDiff = Math.abs(TreeNode.halfLength-child1.totalDist);
		    float b0,b1;
		    if(TreeNode.halfLength>child1.totalDist) {
			b0 = TreeNode.halfLength-child1.totalDist;
			b1 = subDistances[1]-b0;
		    } else if(subDistances[1]>0.001f) {
			b0 = 0.001f;
			b1 = subDistances[1]-b0;
		    } else {
			b0 = 0f;
			b1 = subDistances[1];
		    }
		    TreeNode.mpTree = "("+child1.tree+": "+b0+",("+parent.revTrees[0]+
			","+subTrees[0]+":"+subDistances[0]+"):"+b1+")";
		}
		child0.findMiddle(1);
		child1.findMiddle(0);
	    }
	}
    }

    void printNames() {
	if(isLast) {
	    System.out.println(tree);
	} else {
	    child0.printNames();
	    child1.printNames();
	    System.out.println("node: "+totalDist);
	}
    }
    /*   
    public static void main(String[] args) {

	TreeReader2 tr = new TreeReader2();
	String tree = tr.readFile(args[0]);
	TreeNode root = new TreeNode(tree);
	TreeNode.halfLength = root.totalDist/2f;
	System.out.println(root.findMiddlePoint());
    }
    //*/
}
