/*  
 *  src/org/metaqtl/algo/QtlTreeAlgorithm.java
 * 
 *  $Author: veyrieras $, $Date: 2006-10-17 15:41:55 $, $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.algo;

import org.metaqtl.MetaQtlAnalysis;
import org.metaqtl.MetaQtlData;
import org.metaqtl.MetaQtlResult;
import org.metaqtl.adapter.MetaQtlAnalysisAdapter;
import org.metaqtl.bio.IBioGenome;
import org.metaqtl.bio.IBioOntology;
/**
 * This class defines methods to perform agglomerative
 * hierarchical QTL clustering.  
 */
public class QtlTreeAlgorithm extends ClustAlgorithm {
	/**
	 * This global variable defines the method used by the aglomerative
	 * hierarchical clustering.
	 */
	public int tree_method = HClustAlgorithm.WARD_METHOD;
	
	
	public QtlTreeAlgorithm(IBioGenome map, IBioOntology ontology) {
		super(map,ontology);
	}
	/**
	 * This method performs an agglomerative hierarchical QTL clustering 
	 * on each chromosome and returns the result as a {@link MetaQtlAnalysis}
	 * object. 
	 * 
	 * To control the behaviour of the algorithm use the global variables
	 * of the class. 
	 * 
	 * @param map
	 * @return the chromosomes of 
	 */
	public void run() {
		int i;
		MetaQtlData data;
		
		/* Loop on linkage groups */
		for(i=0;i<chromosomes.length;i++) {
			
			if (chromosomes[i].hasQTL()) {
			
				workProgress++;
				/* First compute the standard deviation of the 
				 * QTL positions */  
				chromosomes[i].computeQtlSD(sd_mode);
				/* Then adapt the QTL in the chromosome into a metaQTLData object */
				data      = new MetaQtlData(chromosomes[i].getQtls());
				
				if (ontology == null)
					data.doTraitGroupClustering();
				else
					data.doTraitOntologyClustering(ontology);
				
				/* Do imputation for qtl with missing CI */
				data.manageMissingData(missing_sd_mode);
				/* Do the clustering */
				if (isLoggerEnable()) {
					getLogger().println("Start Clustering on chromosome " + chromosomes[i].getName());
					getLogger().flush();
				}
				
				chromosomes[i].metaQtlAnalysis = buildQtlTree(data);
				
			}
		}
		
		result = MetaQtlAnalysisAdapter.adapt(chromosomes);
		
	}
	/**
	 * For the given data points this method build the tree which 
	 * represents the hierarchical clustering.
	 * 
	 * @param data the QTK data points.
	 * @return the results of the hierarchical clustering.
	 * 
	 * @see HClustAlgorithm
	 */
	public MetaQtlResult[] buildQtlTree(MetaQtlData data) {
		int i,ntg;
		Double[][] X;
		MetaQtlResult[] results = null;
		
		if (data==null) return null;
		
		ntg = data.getTraitClusterNumber();
		
		results = new MetaQtlResult[ntg];
		
		for(i=0;i<ntg;i++) {
			
			String trait = data.getTraitClusterName(i);
			
			if (isLoggerEnable()) {
				getLogger().println("Clustering for trait " + trait);
				getLogger().flush();
			}

			X                  = data.getDataPoints(i, true);
			
			if (X != null) {
				
				HClustAlgorithm.METHOD = tree_method;
				
				results[i] = new MetaQtlResult(trait,X[0].length);
				results[i].setX(X[0]);
				results[i].setSD(X[1]);
				results[i].setTree(HClustAlgorithm.run(results[i].x, results[i].sd));
				results[i].setQtlIdx(data.getQtlIdx(i));
				
			} else {
				
				if (isLoggerEnable()) {
					getLogger().print("[ WARNING ] : ");
					getLogger().println("No data points for trait cluster " + trait);
					getLogger().flush();
				}
				
			}
			
		}
		
		return results;
	}
	/**
	 * @param centroid_method
	 */
	public void setTreeMethod(int tree_method) {
		this.tree_method = tree_method;
	}
}
