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

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;


public class QtlShape extends GraphShape {
	
	public double y_pos;
	
	public double y_from;
	
	public double ci_height;
	
	public double ci_width;	
	/**
	 * The x position of the CI
	 */
	private double x_ci;
	/**
	 * The y position of the text 
	 */
	private double y_label;
	/**
	 * The text layout which represent the Qtl name.
	 */
	private TextLayout label;
	/**
	 * The partitioned confidence interval.
	 */
	private Rectangle2D.Double[] rectangles;
	
	private int rectMaxIdx;
	/**
	 * The line at the Qtl most probale position.
	 */
	private GeneralPath position;
	
	public QtlShape() {
		super();
	}
	/**
	 * This methods create a new QtlShape from the given
	 * graphics context. 
	 * 
	 * @param graph
	 * @param font
	 * @param unit
	 * @return
	 */
	public void buildShape(Graphics2D graph, Object object) {
		int np=0;
		double x1,y1,x2,y2,h,yy,max;
		double[] partitions;
		
		QtlUnit unit = (QtlUnit) object; 
		
		this.y                = unit.from;
		this.y_pos			  = unit.pos;
		this.y_from  		  = unit.from;
		this.height           = this.ci_height = unit.to-unit.from;
		this.ci_width         = unit.width;
		
		if (MetaGraphPar.WITH_QTL_NAME) {
			FontRenderContext fr   = graph.getFontRenderContext();
			this.label             = new TextLayout(unit.name, MetaGraphPar.QTL_NAME_FONT, fr);
			h = this.label.getBounds().getHeight();
			this.x_ci += h;
			this.x_ci += h*MetaGraphPar.QTL_NAME_VSPACE_CEX;
			h 			= this.label.getBounds().getWidth();
			this.y_label= this.y_from + 0.5*(this.ci_height - h);
			if (h > this.ci_height) {
				// Then the shape ordinate y must be move down 
				this.y = this.y_label;
			}
			this.height = Math.max(this.height,this.label.getBounds().getWidth());			
		}
		
		if (unit.partition != null) {
			partitions = unit.partition;
		} else {
			partitions    = new double[1];
			partitions[0] = 1.0;
		}
		
		this.rectangles = new Rectangle2D.Double[partitions.length];
		
		yy = this.y_from;
		np=0;
		max=0;
		for(int i=0;i<partitions.length;i++) {
			if (partitions[i] > 1.e-2) {
				h=this.ci_height*partitions[i];
				this.rectangles[i]=new Rectangle2D.Double(this.x_ci, yy, this.ci_width, h);
				yy+=h;
				if (partitions[i] > max) {
					max=partitions[i];
					this.rectMaxIdx=i;
				}
			} else this.rectangles[i]=null;
		}
		
		x1 = this.x_ci;
		y1 = this.y_pos;
		x2 = this.x_ci + this.ci_width*(1.0+MetaGraphPar.QTL_TICK_WIDTH_CEX);
		y2 = this.y_pos;
		
		position = new GeneralPath(GeneralPath.WIND_EVEN_ODD,3);
		position.moveTo((float)(x_ci+ci_width), (float)(y_pos-ci_height*MetaGraphPar.QTL_POS_HEIGHT_CEX));
		position.lineTo((float)(x_ci+ci_width*(1+MetaGraphPar.QTL_POS_WIDTH_CEX)), (float)y_pos);
		position.lineTo((float)(x_ci+ci_width), (float)(y_pos+ci_height*MetaGraphPar.QTL_POS_HEIGHT_CEX));
		position.closePath();
		
		this.width = x_ci+ci_width*(1+MetaGraphPar.QTL_POS_WIDTH_CEX);
	}
	/**
	 * 
	 */
	public void draw(Graphics2D graph) {
		Color lcolor = Color.black;
		double xt,yt,h,w;
		int np;
		
		if (label != null) {
			AffineTransform t = graph.getTransform();
			AffineTransform rot   = new AffineTransform();
			h = label.getBounds().getHeight();
			w = label.getBounds().getWidth();
			rot.rotate(Math.PI/2, 0, y_label);
			graph.transform(rot);
			graph.setColor(MetaGraphPar.QTL_NAME_COLOR);
			label.draw(graph, 0, (float)y_label);
			// Restore the transformation context
			graph.setTransform(t);		
		}
		// Count the number of none zero partition
		np = rectangles.length;
		for(int i=0;i<np;i++) {
			if (rectangles[i]!=null) {
				if (MetaGraphPar.QTL_PALETTE!=null)
					graph.setPaint(MetaGraphPar.QTL_PALETTE[i]);
				else
					graph.setPaint(Color.darkGray);
				graph.fill(rectangles[i]);
			}			
		}
		if (MetaGraphPar.QTL_PALETTE!=null)
			graph.setPaint(MetaGraphPar.QTL_PALETTE[rectMaxIdx]);
		else
			graph.setPaint(Color.darkGray);
		graph.fill(position);		
	}
	
	
	public double getHeigth() {
		return this.height;
	}
	
	public double getWidth() {
		return this.width;
	}
	
	public double getYMin() {
		return y;
	}
	
	public double getYMax() {
		return y+height;
	}
	/**
	 * Computes the distance between two Qtl shapes assuming
	 * along the same axe Y (i.e the shapes have same X).
	 * 
	 * @param shape
	 * @param prev
	 * @return
	 */
	public static double getYDistance(QtlShape s1, QtlShape s2) {
		double d=0.0;
		
		if (s1.label != null && s2.label != null) {
			
			double yt1= s1.y_label; 
			double h1 = s1.label.getBounds().getWidth();
			double yt2= s2.y_label;
			double h2 = s2.label.getBounds().getWidth();
			if (yt1 > yt2)
				d = yt1-(yt2+h2);
			else
				d = yt2-(yt1+h1);
		}
		
		if (s1.y_from > s2.y_from)
			d = Math.min(d, s1.y_from-(s2.y_from+s2.ci_height));
		else
			d = Math.min(d, s2.y_from-(s1.y_from+s1.ci_height));
		
		return d;
	}
}