/**
 * 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;

import java.io.File; 
import java.io.IOException;
import java.io.FileNotFoundException;
import java.util.ArrayList;

class TreeReader {

    float[] distance;
    boolean isUnRooted = false;

    TreeReader(){ 
	
    }

    // Read a tree from a file and remove branch lengths
    //
    String readFile(String filename) {

	String tree = new String();
	
	ProAlign.log("TreeReader: "+filename);

	try {
	    InFile in = new InFile(filename);

	    String row =  new String();
	    while((row = in.readLine()) != null) {
		tree += row;
	    }
	} catch (Exception e) {}

	return tree;
    }

    // Take a tree and divide it into two subtrees.
    // Notice that clustalw root is trifurcating
    //
    String[] divideTree(String tree) {

//	System.out.println("tree "+tree+"\n");

	String[] trees = new String[2];
	distance = new float[2];
	trees[0] = "";
	
	if(tree.endsWith(";")) {
	    tree = tree.substring(0,tree.length()-1); // remove last ';'
	}
	tree = tree.substring(1,tree.length()-1);     // remove first & last '('


	if(tree.charAt(0)!='(') { // only one taxon

	    String tmp = tree.substring(0,tree.indexOf(","));
	    trees[0] = tmp.substring(0,tmp.indexOf(":"));
	    distance[0] = new Float(tmp.substring(tmp.indexOf(":")+1)).floatValue();

	    boolean trifurc = false;
	    int open = 0;
	    for(int j = tree.indexOf(",")+1; j<tree.length(); j++) {
		if(tree.charAt(j)=='(') { open++; }
		else if(tree.charAt(j)==')') { open--; }
		if(open==0 && tree.substring(j).indexOf(",")>0) {
		    trifurc = true;
		}
	    }

	    // correction for trifurcating root
	    if(trifurc) {

		isUnRooted = true;
		trees[1] = "("+tree.substring(tree.indexOf(",")+1)+")";
		distance[0] = distance[0]/2f;
		distance[1] = distance[0];

	    } else {

		trees[1] = tree.substring(tree.indexOf(",")+1,tree.lastIndexOf(":"));
		tmp = tree.substring(tree.lastIndexOf(":")+1);
		distance[1] = new Float(tmp).floatValue();
	    }
			    
//	    System.out.println("1o:  "+trees[0]+" "+distance[0]+"\n");
//	    System.out.println("2o:  "+trees[1]+" "+distance[1]+"\n");

	} else {

	    int open = 0;

	    for(int i=0; i<tree.length(); i++) {

		// count parentheses that are "open"
		if(tree.charAt(i)=='(') { open++; }
		else if(tree.charAt(i)==')') { open--; }
		trees[0] += ""+tree.charAt(i);

		if(open<=0) {
		    String tmp = tree.substring(i+2,tree.indexOf(",",i+2));
		    distance[0] = new Float(tmp).floatValue();

		    boolean trifurc = false;
		    open = 0;
		    for(int j = tree.indexOf(",",i+2)+1; j<tree.length(); j++) {
			if(tree.charAt(j)=='(') { open++; }
			else if(tree.charAt(j)==')') { open--; }
			if(open==0 && tree.substring(j).indexOf(",")>0) {
			    trifurc = true;
			}
		    }

		    // correction for trifurcating root
		    if(trifurc) {

			isUnRooted = true;
			trees[1] = "("+tree.substring(tree.indexOf(",",i+2)+1)+")";
			distance[0] = distance[0]/2f;
			distance[1] = distance[0];
			
//			System.out.println("1:  "+trees[0]+" "+distance[0]+"\n");
//			System.out.println("2a: "+trees[1]+" "+distance[1]+"\n");
			
		    } else {

			tmp = tree.substring(tree.indexOf(",",i+2)+1);
			trees[1] = tmp.substring(0,tmp.lastIndexOf(":"));

			tmp = tmp.substring(tmp.lastIndexOf(":")+1);
			distance[1] = new Float(tmp).floatValue();

//			System.out.println("1:  "+trees[0]+" "+distance[0]+"\n");
//			System.out.println("2b: "+trees[1]+" "+distance[1]+"\n");

		    }

		    break; 
		}
	    }
	    
	}
           
	//System.out.println("0: "+trees[0]+" ["+distance[0]+"]");
	//System.out.println("1: "+trees[1]+" ["+distance[1]+"]");

	return trees;
    }

    String[] getAllNodes(String filepath) {
	ArrayList nl = new ArrayList();
	TreeReader tr = this;
	String tree = this.readFile(filepath);
//	if(ProAlign.DEBUG) {
//	    ProAlign.log.println(" reading a list of all the nodes.");
//	}

	//System.out.println(clustalw);
	String[] trees = tr.divideTree(tree);

	tr.loopThroughNodes(trees[0],tr,nl);
	tr.loopThroughNodes(trees[1],tr,nl);

	String[] nodes = new String[nl.size()];
	for(int i=0; i<nl.size(); i++) {
	    nodes[i] = (String) nl.get(i); 
	}

	return nodes;
    }

    void loopThroughNodes(String tree, TreeReader tr, ArrayList nl) {
	if(tree.indexOf(",")>0) {
	    String[] trees = tr.divideTree(tree);
	    tr.loopThroughNodes(trees[0],tr,nl);
	    tr.loopThroughNodes(trees[1],tr,nl);
	} else {
	    nl.add(tree);
	    //System.out.println(nl.size()+" "+tree);
	}
    }


    // ---DEBUGGING ONLY -->
    void loopTreeTest(String tree, TreeReader tr) {
	if(tree.indexOf(",")>0) {
	    String[] trees = tr.divideTree(tree);
	    tr.loopTreeTest(trees[0],tr);
	    tr.loopTreeTest(trees[1],tr);
	} else {
	    //System.out.println("l "+tree);
	}
    }

    public static void main(String[] args) {

	TreeReader tr = new TreeReader();
	String tree = tr.readFile(args[0]);
	String[] trees = tr.divideTree(tree);
	tr.loopTreeTest(trees[0],tr);
	tr.loopTreeTest(trees[1],tr);
	System.out.println("OK");
	String[] nodes = tr.getAllNodes(args[0]);
	for(int i=0; i<nodes.length; i++) {
	    System.out.println(nodes[i]); 
	}
    }
    // <--DEBUGGING ONLY ---

}







