/*  
 *  src/org/metaqtl/MapCluster.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.util.Enumeration;
import java.util.Hashtable;

import org.metaqtl.bio.IBioCross;
import org.metaqtl.bio.IBioGenome;
import org.metaqtl.bio.IBioLGroup;
import org.metaqtl.bio.IBioLocus;
import org.metaqtl.util.GeneticMapProperties;

/**
 * 
 */
public class MapCluster {
	/**
	 * The array of dubious markers.
	 */
	private IBioLocus[] dubious;
	/**
	 * The clusters of chromosomes.
	 */
	private Hashtable clusters;
	/**
	 * The chromosome name dictionnary - Not used and defined
	 * at this time.
	 */
	private MetaDico chrDico;
	
	private MetaDico mrkDico;
	/**
     * Creates a new instance of <code>MapCluster</code>.
     */
	public MapCluster() {
		clusters = new Hashtable();
	}
	/**
     * Add a map to the cluster. This automatically classifies
     * the chromosomes of the given map into clusters of chromosome
     * using their names.
     * 
     * @param map the map to add.
     * @param skeleton true if the chromosomes of this map must flagged as
     * the skeleton chromosomes. 
     * 
     * @see ChromCluster
     * @see ChromCluster#addChromosome(IBioLGroup, IBioCross, int, int, boolean, boolean)
     */
	public void addMap(IBioGenome map, boolean skeleton) {
		boolean rescale;
		int mappingFunct,mappingUnit;
		IBioCross crossDesign;
		IBioLGroup[] groups;
		
		/* Get the mapping function for the given map */
		mappingFunct = GeneticMapProperties.getMappingFunction(map);
		/* Get the mapping unit for the given map */
		mappingUnit = GeneticMapProperties.getMappingUnit(map);
		/* Get the scale status */
		rescale     = GeneticMapProperties.needToBeRescaled(map);
		/* Get the cross parameter for the given map */
		crossDesign = GeneticMapProperties.getCrossDesign(map);
		/* Get the linkage groups of the given map */
		groups = map.groups();
		for (int i=0;i<groups.length;i++) {
			addChromosome(groups[i], crossDesign, mappingFunct, mappingUnit, rescale, skeleton);
		}
	}
	/**
	 * Add a chromosome to the map cluster framework.
	 * @param group the chromosome.
	 * @param crossDesign the cross design
	 * @param mappingFunction the mapping function.
	 * @param mappingUnit the mapping unit.
	 * @param rescale true if the chromosome must be rescaled
	 * @param skeleton true if the chromosome is the skeleton chromosome.
	 */
	public void addChromosome(IBioLGroup group, IBioCross crossDesign, int mappingFunction, int mappingUnit, boolean rescale, boolean skeleton) {
		String groupName;
		ChromCluster cluster;
		
		groupName = getChromosomeName(group.getName());
		
		if (clusters.containsKey(groupName)) {
			cluster = (ChromCluster) (clusters.get(groupName));
			cluster.addChromosome(group, crossDesign, mappingFunction, mappingUnit, rescale, skeleton);
		} else { 
			cluster = new ChromCluster();
			cluster.setMarkerDico(this.mrkDico);
			cluster.setDubiousMarker(this.dubious);
			cluster.addChromosome(group, crossDesign, mappingFunction, mappingUnit, rescale, skeleton);
			clusters.put(groupName, cluster);
		}
	}
	/**
	 * This method returns the name of the chromosome
	 * from the given name. If no synonym dictionnary is defined
	 * then the method returns the same name.
	 * 
	 * @param name
	 * @return
	 */
	public String getChromosomeName(String name) {
		
		if (chrDico == null) {
			return name;
		}
		
		return null;
	}	
	/**
	 * Returns the chromosome clusters. This method
	 * must be invoked after that all the maps have been
	 * added using the method {@link #addMap(IBioGenome, boolean)}.
	 * Otherwise if any valid call has been done to this method
	 * then the returned array will be null.
	 * 
	 * <code>
	 * 	
	 *   IBioGenome[] mymaps = ...;	
	 *   MapCluster     mapCluster = new MapCluster();
	 *   
	 *   for(i=0;i<mymaps.length;i++) {
	 *      mapCluster.add(mymaps, false);
	 *   } 
	 * 	 
	 *   ChromCluster[] chrClusters = mapCluster.getClusters();
	 * 
	 *   if (chrClusters != null) {
	 *        // do something
	 *   } 
	 *   
	 * </code>
	 * 
	 * @return an array of <code>ChromCluster</code>.
	 * 
	 * @see ChromCluster
	 */
	public ChromCluster[] getClusters() {
		int i;
		Enumeration enu;
		String name;
		
		if (clusters == null) return null;
		if (clusters.size() == 0) return null;
		
		ChromCluster[] chrClusters = new ChromCluster[clusters.size()];
		
		i=0;
		enu = clusters.keys();
		while (enu.hasMoreElements()) {
			name = (String) enu.nextElement();
			chrClusters[i] = (ChromCluster) clusters.get(name); 
			chrClusters[i].name = name;
			i++;
		}
		
		return chrClusters;
	}
	/**
	 * This method sets the list of dubious marker. Any call
	 * to the method {@link #addMap(IBioGenome, boolean)} will
	 * then taken into account this list.
	 * 
	 * @param dubious the array of dubious loci.
	 * 
	 * @see ChromCluster#setDubiousMarker(IBioLocus[])
	 */
	public void setDubiousMarker(IBioLocus[] dubious) {
		this.dubious = dubious;
	}

	
	/**
	 * @return Returns the mrkDico.
	 */
	public MetaDico getMarkerDico() {
		return mrkDico;
	}
	/**
	 * @param mrkDico The mrkDico to set.
	 */
	public void setMarkerDico(MetaDico mrkDico) {
		this.mrkDico = mrkDico;
	}
	/**
	 * @param maps
	 */
	public void addAllMap(IBioGenome[] maps) {
		if (maps==null) return;
		for(int i=0;i<maps.length;i++)
			addMap(maps[i], false);
	}
}
