/*  
 *  src/org/metaqtl/graph/QtlPartitionLayer.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.graph;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;

import org.metaqtl.QtlPartition;
import org.metaqtl.numrec.NumericalUtilities;


public class QtlPartitionLayer extends Layer {
	/**
	 * The Qtl layers
	 */
	private QtlLayer[] qtlLayers;
	/**
	 * The Qtl tree
	 */
	private QtlTreeLayer qtlTreeLayer;
	/**
	 * The chromosome axe coordinates.
	 */
	private ChromAxe chromAxe;
	/**
	 * The Qtl partition attached to this layer.
	 */
	private QtlPartition qtlPartition;
	
	/**
	 * @param x
	 * @param y
	 * @param size
	 * @param type
	 */
	public QtlPartitionLayer(double x, double y) {
		super(x, y);
	}
	/**
	 * @param height
	 * @return
	 */
	public void build(Graphics2D graph) {
		// Build the Qtl layers.
		if (qtlPartition != null) {
			switch(qtlPartition.mode) {
				case QtlPartition.HORIZONTAL_MODE:
					buildQtlTreeLayer(graph);
					break;
				case QtlPartition.VERTICAL_MODE:
					buildQtlLayers(graph);
					break;
				default :
					buildQtlLayers(graph);
					break;
			}
		}
		
	}
	
	private void buildQtlTreeLayer(Graphics2D graph) {
		qtlTreeLayer = new QtlTreeLayer(x,y);
		qtlTreeLayer.attach(qtlPartition);
		qtlTreeLayer.setChromAxe(this.chromAxe);
		qtlTreeLayer.build(graph);
		width=qtlTreeLayer.getWidth();
	}
	
	private void buildQtlLayers(Graphics2D graph) {
		int i,nqtl;
		boolean[] see;
		double    x_layer;
		double[]  qpos,ci;
		int[]     idx;
		ArrayList layerList = new ArrayList();
		
		nqtl = qtlPartition.nqtl;
		
		if (nqtl==0) return;
		
		see  = new boolean[nqtl+1];
		qpos    = new double[nqtl+1];
		ci   = new double[nqtl+1];
		idx  = new int[nqtl+1];
		
		for(i=0;i<nqtl;i++) {
			if (chromAxe != null) {
				qpos[i+1]   = chromAxe.transformY(qtlPartition.qtlPos[i]);
				ci[i+1]     = chromAxe.scaleHeight(qtlPartition.qtlCI[i]);
			} else {
				qpos[i+1]   = qtlPartition.qtlPos[i];
				ci[i+1]     = qtlPartition.qtlCI[i];
			}
			see[i+1]    = false;			
		}
		
		if (nqtl > 1) // Heap sort of the positions
			 NumericalUtilities.indexx(nqtl,qpos,idx);
		else if (nqtl==1) idx[1]=1;
		
		// Init the x_layer
		x_layer = x;
		
		do {
			
			QtlLayerBuffer qtlBuffer = new QtlLayerBuffer();
			
			for(i=1;i<=nqtl;i++) {
				
				if (!see[idx[i]]) {
					
					QtlUnit unit    = new QtlUnit();
					unit.name    	= qtlPartition.qtlNames[idx[i]-1];
					unit.partition  = qtlPartition.proba[idx[i]-1];
					unit.from       = Math.max(qpos[idx[i]]-ci[idx[i]]/2.0, chromAxe.getYMin());
					unit.to         = Math.min(qpos[idx[i]]+ci[idx[i]]/2.0, chromAxe.getYMax());
					unit.pos        = qpos[idx[i]];
					//unit.x          = x_layer;
					unit.width      = MetaGraphPar.QTL_CI_WIDTH;
					
					see[idx[i]]     = qtlBuffer.addQtl(graph,unit);
					
					/*if (see[idx[i]]) {
						System.out.println("ADD " + unit.pos);
						System.out.println(">> " +  unit.from + " " + unit.to);
					}*/
						
					if (!qtlBuffer.canAddMoreQtl(chromAxe.getYMax())) break;
					
				}
				
			}
			
			QtlLayer layer = qtlBuffer.getLayer(x_layer, y);
			// Build the layer
			layer.build(graph);
			if (layer.getHeight() > height) height = layer.getHeight();
			layerList.add(layer);
			x_layer += MetaGraphPar.QTL_HSPACE;
			x_layer += layer.getWidth();
			// Check if finish 
			for(i=1;i<=nqtl;i++)
				if (!see[i]) break;
			if (i>nqtl)	break;			
		} while(0==0); // End building Qtl layers 
		
		if (layerList != null) {
			qtlLayers = new QtlLayer[layerList.size()];
			layerList.toArray(this.qtlLayers);
		}
		
		
		width    = x_layer - x; // the width
	}

	/* (non-Javadoc)
	 * @see org.thalia.metaqtl.graph.Layer#draw(java.awt.Graphics2D)
	 */
	public void draw(Graphics2D graph) {
		Color           c     = graph.getColor();
		AffineTransform t     = graph.getTransform();
		AffineTransform trans = new AffineTransform();
		trans.translate(x,y);
		graph.transform(trans);
		if (qtlLayers != null) {
			for(int i=0;i<qtlLayers.length;i++)
				if (qtlLayers[i] != null) 
					qtlLayers[i].draw(graph);
		}
		if (qtlTreeLayer != null) {
			qtlTreeLayer.draw(graph);
		}
		graph.setTransform(t);
		graph.setColor(c);
	}
	/**
	 * @param chromAxe
	 */
	public void setChromAxe(ChromAxe chromAxe) {
		this.chromAxe = chromAxe;
	}
	
	/**
	 * @return Returns the chromAxe.
	 */
	public ChromAxe getChromAxe() {
		return chromAxe;
	}

	/* (non-Javadoc)
	 * @see org.thalia.metaqtl.graph.Layer#attach(java.lang.Object)
	 */
	public void attach(Object object) {
		if (object instanceof QtlPartition) {
			qtlPartition = (QtlPartition) object;
		}
	}
	/* (non-Javadoc)
	 * @see org.thalia.metaqtl.graph.Layer#getYMin()
	 */
	public double getYMin() {
		double min = Double.POSITIVE_INFINITY;
		if (qtlLayers != null) {
			for(int i=0;i<qtlLayers.length;i++) {
				if (qtlLayers[i].getYMin() < min)
					min =(y+qtlLayers[i].getYMin());
			}
		}
		if (qtlTreeLayer != null) {
			min = Math.min(min, qtlTreeLayer.getYMin());
		}
		return min;
	}
	/* (non-Javadoc)
	 * @see org.thalia.metaqtl.graph.Layer#getYMax()
	 */
	public double getYMax() {
		double max = Double.NEGATIVE_INFINITY;
		if (qtlLayers!=null) {
			for(int i=0;i<qtlLayers.length;i++) {
				if (qtlLayers[i].getYMax() < max)
					max = (y+qtlLayers[i].getYMax());
			}
		}
		if (qtlTreeLayer != null) {
			max = Math.max(max, qtlTreeLayer.getYMax());
		}
		return max;
	}
	/**
	 * @return
	 */
	public ArrayList getQtlPartNames() {
		if (this.qtlPartition!=null)
			return qtlPartition.getPartNames();
		else return new ArrayList();
	}
}