/*  
 *  src/org/metaqtl/graph/ChromLayer.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.awt.geom.GeneralPath;
import java.awt.geom.Point2D;

import org.metaqtl.CMarkerSequence;
import org.metaqtl.Chromosome;
import org.metaqtl.algo.CMSAlgorithm;

public class ChromLayer extends Layer {
	
    public static final int RIGHT_LABEL = ChromShape.RIGHT_LABEL;
	
	public static final int LEFT_LABEL  = ChromShape.LEFT_LABEL;
	
	public static final int ALIGN_FIRST_COMMON = 0;
	
	public static final int ALIGN_FIRST_MARKER = 1;
	
	public static final int SINGLE_COMMON = 2;
	
	public static final int POS_COMMON = 0;
	
	public static final int NEG_COMMON = 1;
	
	/**
	 * The chromosome shape.
	 */
	private ChromShape chromShape = null;
	/**
	 * The chromosome to draw.
	 */
	private Chromosome chromosome = null;
	
	/**
	 * 
	 * @param ref
	 * @param layer
	 * @param mode
	 */
	public static void alignChromLayers(ChromLayer ref, ChromLayer layer, int mode) {
		double y_ref=0.0,y_layer=0.0;
		switch(mode) {
			case ALIGN_FIRST_COMMON :
				int idx_ref=Chromosome.getFirstCommonMrkIdx(ref.chromosome, layer.chromosome);
				if (idx_ref >= 0) {
					int idx_layer=layer.chromosome.getMarkerIdxWithName(ref.chromosome.getMarkerName(idx_ref));
					y_ref   = ref.getChromAxe().transformY(ref.chromosome.getDistance(idx_ref));
					y_layer = layer.getChromAxe().transformY(layer.chromosome.getDistance(idx_layer));
				} else{
					y_ref = ref.getChromAxe().getYMin();
				    y_layer = layer.getChromAxe().getYMin();
				}
				break;
			case ALIGN_FIRST_MARKER :
				y_ref   = ref.getChromAxe().getYMin();
				y_layer = layer.getChromAxe().getYMin();
				break;
			default :
				y_ref   = ref.getChromAxe().getYMin();
				y_layer = layer.getChromAxe().getYMin();
				break;
		}
		layer.setY(layer.getY()+(y_ref-y_layer));
	}
	
	/**
	 * @param x
	 * @param y
	 */
	public ChromLayer(double x, double y) {
		super(x, y);
	}
	
	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 (chromShape != null) {
			chromShape.draw(graph);
		}		
		graph.setTransform(t);
		graph.setColor(c);
	}
	/* (non-Javadoc)
	 * @see org.thalia.metaqtl.graph.Layer#buildLayer()
	 */
	public void build(Graphics2D graph) {
		chromShape   = new ChromShape();
		chromShape.buildShape(graph, chromosome);
	}
	/**
	 * Return the axe of the chromosome.
	 * @return
	 */
	public ChromAxe getChromAxe() {
		return chromShape.getChromAxe();
	}
	/* (non-Javadoc)
	 * @see org.thalia.metaqtl.graph.Layer#attach(java.lang.Object)
	 */
	public void attach(Object object) {
		if (object instanceof Chromosome) {
			chromosome = (Chromosome) object;
		}
	}
	
	public void setLabelSide(int side) {
		chromShape.setLabelSide(side);
	}

	/* (non-Javadoc)
	 * @see org.thalia.metaqtl.graph.Layer#getHeight()
	 */
	public double getHeight() {
		return chromShape.getHeight();
	}

	/* (non-Javadoc)
	 * @see org.thalia.metaqtl.graph.Layer#getWidth()
	 */
	public double getWidth() {
		return chromShape.getWidth();
	}

	/* (non-Javadoc)
	 * @see org.thalia.metaqtl.graph.Layer#getYMin()
	 */
	public double getYMin() {
		return y;
	}

	/* (non-Javadoc)
	 * @see org.thalia.metaqtl.graph.Layer#getYMax()
	 */
	public double getYMax() {
		return chromShape.getYMax();
	}

	/**
	 * @param chromLayer
	 */
	public CMrkTickPoint[] getCommonMarkerPoints(ChromLayer chromLayer) {
		boolean reverse = (this.chromShape.getLabelSide() == chromLayer.chromShape.getLabelSide());
		CMarkerSequence cms = CMSAlgorithm.run(chromosome, chromLayer.chromosome);
		if  (cms != null) {
			CMrkTickPoint[] points = new CMrkTickPoint[cms.nmc];
			int i,j,k,mrk1,mrk2;
			k=0;
			for(i=0;i<cms.ncs;i++) { 
				for(j=0;j<cms.css[i];j++) {  
					mrk1 = cms.idx1[i][j];
					mrk2 = cms.idx2[i][j];
					points[k] = new CMrkTickPoint();
					points[k].p1 = getMrkTickPoint2D(mrk1, false);
					points[k].p2 = chromLayer.getMrkTickPoint2D(mrk2, reverse);
					if (cms.frames[i]) points[k].status=0;
					else points[k].status=1;
					k++;
				}
			}
			for(i=0;i<cms.nmc;i++) {
				if (!cms.incms[i]) {
					points[k] = new CMrkTickPoint();
					points[k].p1 = getMrkTickPoint2D(cms.mcidx[0][i], false);
					points[k].p2 = chromLayer.getMrkTickPoint2D(cms.mcidx[1][i], reverse);
					points[k].status=2;
					k++;
				}
			}
			return points;
		}
		return null;
	}
	
	public CMrkTickPath[] getCommonMarkerPaths(ChromLayer chromLayer) {
		
		CMrkTickPoint[] points = getCommonMarkerPoints(chromLayer);
		
		if (points == null) return null;
		
		double x1,y1,w;
		
		CMrkTickPath[] paths = new CMrkTickPath[points.length];
		
		for(int i=0;i<paths.length;i++) {

			paths[i]      = new CMrkTickPath();
			paths[i].path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 4);
			
			x1 = points[i].p1.getX();
			y1 = points[i].p1.getY();
			w  = Math.abs(points[i].p1.getX()-points[i].p2.getX()); 
			
			paths[i].path.moveTo((float)x1, (float)y1);
			x1 = points[i].p1.getX() + w*0.1;
			paths[i].path.lineTo((float)x1, (float)y1);
			x1 = points[i].p2.getX() - w*0.1;
			y1 = points[i].p2.getY();
			paths[i].path.lineTo((float)x1, (float)y1);
			x1 = points[i].p2.getX(); 
			paths[i].path.lineTo((float)x1, (float)y1);
			paths[i].status = points[i].status;
				
		}
		
		return paths;
	}
	
	public double getChromWidth() {
		if (chromShape!=null)
			return chromShape.getChromWidth();
		else return 0.0;
	}
	
	public Point2D getMrkTickPoint2D(int mrkIdx, boolean reverse) {
		if (chromShape != null) {
			Point2D p = chromShape.getMrkTickPoint2D(mrkIdx, reverse);
			p.setLocation(p.getX()+getX(), p.getY()+getY());
			return p;
		}
		else return null;
	}
	
	public class CMrkTickPoint {
		
		Point2D p1;
		
		Point2D p2;
		
		int status=0;
		
	}
	
	public class CMrkTickPath {
		
		GeneralPath path;
		
		int status;
	}

	/**
	 * @return
	 */
	public boolean hasProba() {
		return (chromosome.proba!=null);
	}
}