/*******************************************************************************
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 * 
 * Contact Info:
 * 	Bruce Donald
 * 	Duke University
 * 	Department of Computer Science
 * 	Levine Science Research Center (LSRC)
 * 	Durham
 * 	NC 27708-0129 
 * 	USA
 * 	brd@cs.duke.edu
 * 
 * Copyright (C) 2011 Jeffrey W. Martin and Bruce R. Donald
 * 
 * <signature of Bruce Donald>, April 2011
 * Bruce Donald, Professor of Computer Science
 ******************************************************************************/


package edu.duke.donaldLab.jdshot.grid.cn;

import edu.duke.donaldLab.jdshot.grid.GridCell;
import edu.duke.donaldLab.jdshot.grid.SearchSpace;
import edu.duke.donaldLab.jdshot.grid.cn.CnGridCell;
import edu.duke.donaldLab.jdshot.search.CellSplitter;

public class CnCellSplitter implements CellSplitter
{
	/**************************
	 *   Data Members
	 **************************/
	
	private CnGridPoint m_primalDeltas;
	
	
	/**************************
	 *   Constructors
	 **************************/
	
	public CnCellSplitter( SearchSpace searchSpace )
	{
		m_primalDeltas = (CnGridPoint)searchSpace.getInitialCells().get( 0 ).getDeltas();
	}
	
	
	/**************************
	 *   Methods
	 **************************/
	
	@Override
	public void split( GridCell left, GridCell right, GridCell source )
	{
		// make sure the casts we're about to make are safe
		assert( left instanceof CnGridCell );
		assert( right instanceof CnGridCell );
		assert( source instanceof CnGridCell );
		
		split( (CnGridCell)left, (CnGridCell)right, (CnGridCell)source );
	}
	
	public void split( CnGridCell left, CnGridCell right, CnGridCell source )
	{
		/* Jeff: /6/18/2009
			I can't seem to get the ratio heuristic working. It looks like it
			depends on a ratio member of the CnGridCell class, but it is never
			set to a mraningful value. I'll just default to the primal deltas
			heuristic.
		*/
		/*Himanshu:07/16/2009
		 * 	Would use ratio if we are using convex hulls.
		 */
		//splitRatio( left, right, source );
		splitDeltas( left, right, source );
	}
	
	public void splitRatio( CnGridCell leftCell, CnGridCell rightCell, CnGridCell source )
	{
		// just in case...
		assert( source.ratio != -1 ) : "Ratio should never be negative.";
		
		CnGridPoint Deltas = source.getDeltas();
		
		if(source.ratio >1) //Box volume more than hull volume, choose orientations
		{
			if(Deltas.phi > Deltas.theta)
				source.split(leftCell,rightCell,3);
			else
				source.split(leftCell,rightCell,4);
		}
		else
		{
			if(Deltas.x > Deltas.y)
				source.split(leftCell,rightCell,0);
			else
				source.split(leftCell,rightCell,1);
		}
	}
	
	public void splitDeltas( CnGridCell leftCell, CnGridCell rightCell, CnGridCell source ) 
	{
		// just in case...
		assert( leftCell != null );
		assert( rightCell != null );
		assert( source != null );
		
		// copy source to children
		leftCell.set( source );
		rightCell.set( source );
		
		// scale the lengths by the primal deltas to unbias searching certain dimensions first
		CnGridPoint scaled = source.getDeltas();
		scaled.x /= m_primalDeltas.x;
		scaled.y /= m_primalDeltas.y;
		scaled.phi /= m_primalDeltas.phi;
		scaled.theta /= m_primalDeltas.theta;
		
		// decide which dimension to split
		int dimension = -1;
		if( scaled.x>=scaled.y && scaled.x >=scaled.phi && scaled.x>=scaled.theta)
		{
			dimension = 0;
		}
		else if( scaled.y>=scaled.x && scaled.y >=scaled.phi && scaled.y>=scaled.theta )
		{
			dimension = 1;
		}
		else if( scaled.phi>=scaled.x && scaled.phi >=scaled.y && scaled.phi>=scaled.theta )
		{
			dimension = 2;
		}
		else if( scaled.theta>=scaled.x && scaled.theta >=scaled.y && scaled.theta>=scaled.phi )
		{
			dimension = 3;
		}
			
		assert( dimension != -1 ) : "Didn't choose a valid dimension to split!";
		
		// split along the selected dimension
		source.split( leftCell, rightCell, dimension );
	}
}
