/*******************************************************************************
 * 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.share.protein.tools;

import java.util.Iterator;

import edu.duke.donaldLab.share.geom.Sphere;
import edu.duke.donaldLab.share.geom.Vector3;
import edu.duke.donaldLab.share.math.Matrix3;
import edu.duke.donaldLab.share.math.Quaternion;
import edu.duke.donaldLab.share.protein.AtomAddressInternal;
import edu.duke.donaldLab.share.protein.Protein;
import edu.duke.donaldLab.share.protein.Subunit;

public class ProteinGeometry
{
	public static Vector3 center( Subunit subunit )
	{
		return center( subunit, subunit.getAtomIndex().iterator() );
	}
	
	public static Vector3 center( Subunit subunit, Iterator<AtomAddressInternal> iterAddress )
	{
		Vector3 c = getCentroid( subunit, iterAddress );
		c.negate();
		translate( subunit, c );
		return c;
	}
	
	public static Vector3 center( Protein protein )
	{
		return center( protein, protein.getAtomIndex() );
	}
	
	public static Vector3 center( Protein protein, Iterator<AtomAddressInternal> iterAddress )
	{
		Vector3 c = getCentroid( protein, iterAddress );
		c.negate();
		translate( protein, c );
		return c;
	}
	
	public static Vector3 getCentroid( Protein protein )
	{
		return getCentroid( protein, protein.getAtomIndex() );
	}
	
	public static Vector3 getCentroid( Protein protein, Iterator<AtomAddressInternal> iterAddress )
	{
		Vector3 centroid = new Vector3();
		
		// for each atom...
		int numAtoms = 0;
		while( iterAddress.hasNext() )
		{
			AtomAddressInternal address = iterAddress.next();
			centroid.add( protein.getAtom( address ).getPosition() );
			numAtoms++;
		}
		
		centroid.scale( 1.0 / numAtoms );
		
		return centroid;
	}
	
	public static Vector3 getCentroid( Subunit subunit )
	{
		return getCentroid( subunit, subunit.getAtomIndex().iterator() );
	}
	
	public static Vector3 getCentroid( Subunit subunit, Iterator<AtomAddressInternal> iterAddress )
	{
		Vector3 centroid = new Vector3();
		
		// for each atom...
		int numAtoms = 0;
		while( iterAddress.hasNext() )
		{
			AtomAddressInternal address = iterAddress.next();
			centroid.add( subunit.getAtom( address ).getPosition() );
			numAtoms++;
		}
		
		centroid.scale( 1.0 / numAtoms );
		
		return centroid;
	}
	
	public static void translate( Subunit subunit, Vector3 t )
	{
		// for each atom...
		for( AtomAddressInternal address : subunit.getAtomIndex() )
		{
			// translate it
			subunit.getAtom( address ).getPosition().add( t );
		}
	}
	
	public static void rotate( Subunit subunit, Quaternion q )
	{
		// for each atom...
		for( AtomAddressInternal address : subunit.getAtomIndex() )
		{
			// rotate it
			subunit.getAtom( address ).getPosition().rotate( q );
		}
	}
	
	public static void transform( Subunit subunit, Matrix3 m )
	{
		// for each atom...
		for( AtomAddressInternal address : subunit.getAtomIndex() )
		{
			// translate it
			subunit.getAtom( address ).getPosition().transform( m );
		}
	}
	
	public static void transform( Subunit subunit, Matrix3 m, Vector3 translation )
	{
		// for each atom...
		for( AtomAddressInternal address : subunit.getAtomIndex() )
		{
			// transform it
			Vector3 pos = subunit.getAtom( address ).getPosition();
			pos.subtract( translation );
			pos.transform( m );
			pos.add( translation );
		}
	}
	
	public static void translate( Protein protein, Vector3 t )
	{
		// for each subunit...
		for( Subunit subunit : protein.getSubunits() )
		{
			translate( subunit, t );
		}
	}
	
	public static void rotate( Protein protein, Quaternion q )
	{
		// for each subunit...
		for( Subunit subunit : protein.getSubunits() )
		{
			rotate( subunit, q );
		}
	}
	
	public static void transform( Protein protein, Matrix3 m )
	{
		// for each subunit...
		for( Subunit subunit : protein.getSubunits() )
		{
			transform( subunit, m );
		}
	}
	
	public static void transform( Protein protein, Matrix3 m, Vector3 translation )
	{
		// for each subunit...
		for( Subunit subunit : protein.getSubunits() )
		{
			transform( subunit, m, translation );
		}
	}
	
	public static Sphere getBoundingSphere( Subunit subunit )
	{
		// grab the positions vectors from the atoms
		Vector3[] points = new Vector3[subunit.getAtomIndex().size()];
		int atomIndex = 0;
		for( AtomAddressInternal address : subunit.getAtomIndex() )
		{
			points[atomIndex++] = subunit.getAtom( address ).getPosition();
		}
		
		// construct the minimum bounding sphere
		return new Sphere( points );
	}
}
