/* BEGIN_HEADER                                              Java TreeView
 *
 * $Author: rqluk $
 * $RCSfile: Chromosome.java,v $
 * $Revision: 1.1 $
 * $Date: 2006-08-16 19:13:49 $
 * $Name:  $
 *
 * This file is part of Java TreeView
 * Copyright (C) 2001-2014 Alok Saldanha, All Rights Reserved. Modifications Copyright (C) Lawrence Berkeley Lab.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * END_HEADER 
 */
package edu.stanford.genetics.treeview.plugin.karyoview;

import edu.stanford.genetics.treeview.LogBuffer;

/**
* represents the loci in just one chromosome...
*/
abstract class Chromosome {
	final public static int LINEAR = 1;
	final public static int CIRCULAR = 1;
	
	abstract public ChromosomeLocus getLeftEnd();
	abstract public ChromosomeLocus getRightEnd();

	public boolean isEmpty() {
		if (getLeftEnd() == getRightEnd() && getRightEnd() == null) {
			return true;
		} else {
			return false;
		}
	}
	abstract public int getType();
	
	abstract public double getMaxPosition();
	abstract public double getMaxPosition(int arm);
	abstract public ChromosomeLocus getClosestLocus(int arm, double position);
	abstract public ChromosomeLocus getLocus(int arm, int index);
	abstract public void insertLocus(ChromosomeLocus locus);
	/**
  * this internal routine is used to insert a locus into an array, maintaining the property that a
  * locus with minimal position is at index 0, and that there is a non-decreasing position as the
  * indexes increase. The array may include null values.
  *
  * @return the index inserted into or -1 on failure to insert.
  */
  protected int insertLocusIntoArray(ChromosomeLocus [] array, ChromosomeLocus locus) {
//	System.out.println("Inserting " + locus.toString());
	for (int point = 0; point < array.length; point++) {
//	  System.out.print("Checking " + point + "... ");
	  if (array[point] == null) {
		// easy case, insert and return.
//	  System.out.println("inserting");
		
		array[point] = locus;
 		return point;
	  }
//	  System.out.print("Found " + array[point].toString());
	  if (array[point].getPosition() > locus.getPosition()) {
//		System.out.println(", decided to backtrack ");
		// we need to push everyone up...
		for (int j = array.length-1; j > point; j--) {
///		  System.out.println("moving " + (j-1) + " to " + j);
		  array[j] = array[j-1];
		}
		array[point] = locus;
		return point;
	  }
//		System.out.println(", decided to continue ");
	}
	System.out.println(" array " + array  ); 
	LogBuffer.println("Error in Genome.insertLocusIntoArray(): we weren't about to fit locus " + locus + " into data structure on account of not allocating enough space");
	return -1;
  }

  /**
  * just bisect and recurse. Bottoms out when min == max....
  */
  
  protected ChromosomeLocus getLocusRecursive(double position, ChromosomeLocus [] array, int min, int max) {
//	System.out.println("Recursing " + min +" , " + max + " for " + position);
	if (min  == max) {
	//  System.out.println("bottomed out at "+min+"... ");
	  return array[min]; // bottom out
	}
	int midL = (max + min) /2; // rightmost member of left interval
	int midR = midL + 1;       // leftmost member of right interval.
	if (array[midL].getPosition() > position) { // we're on the left for sure...
	  return getLocusRecursive(position, array, min, midL);
	}
	if (array[midR].getPosition() < position) { // we're on the right for sure...
	  return getLocusRecursive(position, array, midR, max);
	}
//	  System.out.println("struck gold at "+midL+"... ");
	// we've struck gold! We're between the midL and midR!
	double distL = Math.abs(array[midL].getPosition() - position); 
	double distR = Math.abs(array[midR].getPosition() - position); 
	if (distL > distR) {
	  return array[midR];
	} else  {
	  return array[midL];
	}
  }
}


