/*  
 *  src/org/metaqtl/TreeNode.java
 * 
 *  $Author: veyrieras $, $Date: 2006-10-17 15:41:54 $, $Version$
 *
 *  MetaQTL : a Java package for QTL Meta-Analysis
 * 
 *  Copyright (C) 2003-2006  Jean-Baptiste Veyrieras, INRA, France.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * 
 */
package org.metaqtl;

import java.io.Serializable;

/**
 * This class represents a node in a binary Tree obtained
 * when applying usual hirarchical clustering methods.
 * 
 * An array of <code>TreeNode</code> can then be viewed as
 * a tree.
 */
public class TreeNode  implements Serializable {
  /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
/**?
   * The identifiant of the cluster.
   */
  public int idx;
  /**
   * The label of the cluster
   */
  public String label;
  /**
   * The number of sequences in the cluster
   */
  public int card=0;
  /**
   * The indices of the sub-nodes
   */
  public int[] nidx=null;
  /**
   * The status of the node.
   */
  public boolean leaf=false;
  /**
   * The distance between the node and its parent. 
   */
  public double dist=0.0;
  /**
   * The distance between the node and the root of the tree (if defined).
   */
  public double height;
  /**
   * Left and right children, or null
   */
  public TreeNode[] children=null; 
  /**
   * The parent of the node
   */
  public TreeNode parent=null;
  
  public double x;
  
  public double y;
  
  public double xc;
  
 
 /**
  * Creates a new instance of <code>TreeNode</code>
  * with the given indice <code>idx</code>. Use it
  * to create the leaves of the tree. 
  * 
  * @param idx the indice of the node.
  */
  public TreeNode(int idx) {
  	this.idx=idx;
    leaf = true;
    card = 1;
    nidx = new int[1];
    nidx[0] = idx;
  }
  /**
   * Creates a new instance of  <code>TreeNode</code> with the
   * given indice <code>idx</code> and the children of the node.
   * Use this constructor to create the internal nodes of the tree. 
   */
  public TreeNode(int idx, TreeNode[] children) {
  	this.idx = idx;
  	if (children != null) {
  		card=0;
	  	for(int i=0;i<children.length;i++) {
	  		card += children[i].card;
	  	}
	    nidx = new int[card];
	    for(int i=0,k=0;i<children.length;i++) {
	  		for(int j=0;j<children[i].card;j++,k++) {
	  			nidx[k]=children[i].nidx[j];
	  		}
	  	}
	    this.children = children;
  	}
  }
  /**
   * Creates a new instance of <code>TreeNode</code> with
   * default attribute values.
   */
   public TreeNode() {}
   
	/**
	 * Add a child to the node.
	 * @param node
	 */
	public void addChild(TreeNode node) {
		
		if (node==null) return;
		
		int i;
		TreeNode[] tmp;
		
		if (children==null) {
			tmp = children = new TreeNode[1];
			i   = 0;
		}
		else {
			tmp = new TreeNode[children.length+1];
			for(i=0;i<children.length;i++)
				tmp[i]=children[i];
		}
		tmp[i]=node;
		children=tmp;
		if (node.card>0 && node.nidx != null) {
			// increment the cardinal and update the leaves index.
			int[] uidx = new int[card+node.card];
			i=0;
			if (card > 0) {
				for(;i<card;i++) {
		  			uidx[i]=nidx[i];
		  		}
			}
			for(i=0;i<node.card;i++)
				uidx[i+card]=node.nidx[i];
			card+=node.card;
			nidx=uidx;
		} 
	}
	/**
	 * @return
	 */
	public String getName() {
		return label;
	}
	/**
	 * @return
	 */
	public TreeNode[] getChildren() {
		return this.children;
	}
	/**
	 * @return
	 */
	public int getCard() {
		return card;
	}
	
	public double getHeight() {
		return height;
	}
	/**
	 * @param x
	 */
	public void setX(double x) {
		this.x = x;
	}
	/**
	 * @param x
	 */
	public void setY(double y) {
		this.y = y;
	}
	/**
	 * @return
	 */
	public double getY() {
		return y;
	}
	
	public double getX() {
		return x;
	}
	/**
	 * @return
	 */
	public double getDist() {
		return dist;
	}
	/**
	 * @return
	 */
	public TreeNode getParent() {
		return parent;
	}
	/**
	 * @param d
	 */
	public void setCentroid(double xc) {
		this.xc = xc;
	}
	/**
	 * @param y2
	 * @param sd
	 */
	public double getCentroid(double[] y2, double[] sd) {
		if (nidx==null) return 0.0;
		double t=0,s=0;
		for(int i=0;i<nidx.length;i++) {
			t+=y2[nidx[i]]/(sd[nidx[i]]*sd[nidx[i]]);
			s+=1.0/(sd[nidx[i]]*sd[nidx[i]]);
		}
		return t/s;
	}

}

