/*  
 *  src/org/metaqtl/CMarkerSequence.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;
/**
 * A Common marker sequence between two ordered set of markers
 * is a sub-set of at least two markers which order is the same between
 * the two sets (may be reverse).
 * For example :
 * 
 * Set 1 : {a,b,c,d,e}
 * Set 2 : {a,b,e,d,c}
 * 
 * Then this two sets have two common sequences {a,b} and {d,e}.
 * 
 * Hereafter the term 'Common Marker Sequence' is used as well as for
 * a single commom sequence than for the set of common sequences for 
 * a same comparison between two ordered sets.
 */
public class CMarkerSequence {
	/**
	 * The number of common marker between chromosomes
	 */
	public int nmc;
	/**
	 * The common marker indices on the chromosomes. 
	 */
	public int[][] mcidx;
	/**
	 * 
	 */
	public boolean[] incms;
	/**
	 * The number of common sequences.
	 */
	public int ncs;
	/**
	 * The sizes of the common sequences
	 */
	public int[] css;
	/**
	 * The frame of the common marker sequences
	 */
	public boolean[] frames;
	/**
	 * The indices of the markers on the first
	 * chromosome for the common sequences.
	 */
	public int[][] idx1;
	/**
	 * The indices of the marker on the second
	 * chromosome for the common sequences.
	 */
	public int[][] idx2;
	/**
	 * Initiates a new Common marker sequence from the
	 * tow arrays of common marker indices
	 * <code>mcidx[0..1][0..nmc-1]</code>. This assumes
	 * that <code>mcidx</code> has been obtained by using
	 * one of the two orderd set as the reference.
	 * 
	 * @param mcidx the two arrays of common marker indices. 
	 * @param nmc the number of common markers.
	 */
	public CMarkerSequence(int mcidx[][], int nmc) {
		this.ncs    = 0;
		this.nmc    = nmc;
		this.mcidx  = mcidx;
		this.css    = new int[nmc/2];
		this.frames = new boolean[nmc/2];
		this.idx1   = new int[nmc/2][nmc];
		this.idx2   = new int[nmc/2][nmc];
		this.incms  = new boolean[nmc];
	}
	/**
	 * 
	 * @param m1 the indice of the marker.
	 * @return the indices of both the common sequence which contains the marker
	 * and the indice of the marker inside the sequence.
	 */
	public int[] getCSIdx(int i, int m1) {
		if (i==0 || i==1) {
			int[] idx = new int[2];
			for(int j=0;j<ncs;j++) {
				for(int k=0;k<css[j];k++) {
					if (i==0 && idx1[j][k] == m1) {
						idx[0]=j;
						idx[1]=k;
						return idx;
					}
					if (i==1 && idx2[j][k] == m1) {
						idx[0]=j;
						idx[1]=k;
						return idx;
					}
				}
			}
		}
		return null;
	}
	/**
	 * Returns the indices of the marker at the left of the 
	 * given one.
	 * @param cs1
	 * @param m1x
	 * @return
	 */
	public int[] getLeftCSMarker(int cs1, int m1x) {
		int[] idx = new int[2];
		if (m1x >  0) {
			idx[0]=cs1;
			idx[1]=m1x-1;
		} else if (cs1 > 0) {
			idx[0]=cs1-1;
			idx[1]=css[idx[0]]-1;
		} else {
			idx[0]=cs1;
			idx[0]=m1x;
		}
		return idx;
	}
	/**
	 * @param cs2
	 * @param m2x
	 * @return
	 */
	public int[] getRightCSMarker(int cs2, int m2x) {
		int[] idx = new int[2];
		if (m2x <  css[cs2]-1) {
			idx[0]=cs2;
			idx[1]=m2x+1;
		} else if (cs2 < ncs-1) {
			idx[0]=cs2+1;
			idx[1]=0;
		} else {
			idx[0]=cs2;
			idx[1]=m2x;
		} 
		return idx;
	}
	/**
	 * @param i
	 * @param cs1
	 * @param m1x
	 * @return
	 */
	public int getMarkerIdx(int i, int cidx, int midx) {
		if (i==0 || i==1) {
			if (i==0)
				return idx1[cidx][midx];
			else
				return idx2[cidx][midx];
		}
		return -1;
	}
	/**
	 * @param cs1
	 * @param cs2
	 */
	public boolean haveSameFrame(int cs1, int cs2) {
		return ((frames[cs1] && frames[cs2]) || (!frames[cs1] && !frames[cs2]));
	}

}
