/*******************************************************************************
 * 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.test.analyze;

import java.util.Iterator;

import edu.duke.donaldLab.jdshot.TestMain;
import edu.duke.donaldLab.jdshot.grid.GridPoint;
import edu.duke.donaldLab.jdshot.grid.StructureGenerator;
import edu.duke.donaldLab.jdshot.test.ExtendedTestCase;
import edu.duke.donaldLab.share.geom.Vector3;
import edu.duke.donaldLab.share.protein.AtomAddressInternal;
import edu.duke.donaldLab.share.protein.Protein;
import edu.duke.donaldLab.share.protein.Subunit;

public class TestStructureGenerator extends ExtendedTestCase
{
	// UNDONE: find a way to check that the right transformations were applied
	
	public void testIdsAndCounts( )
	{
		// transformation settings
		int numSubunits = 4;
		GridPoint point = getRandomGridPoint();
		
		// generate a structure
		Protein oligomer = getOligomer( numSubunits, point );
		
		// check for the right number of subunits
		assertEquals( numSubunits, oligomer.getSubunits().size() );
		for( int i=0; i<numSubunits; i++ )
		{
			Subunit subunit = oligomer.getSubunits().get( i );
			assertEquals( i, subunit.getId() );
		}
		
		// check for the right number of atoms
		Subunit monomer = TestMain.getSearchContext().getMonomer();
		assertEquals( numSubunits * monomer.getAtomIndex().size(), oligomer.getNumAtoms() );
		for( Subunit subunit : oligomer.getSubunits() )
		{
			assertEquals( monomer.getAtomIndex().size(), subunit.getAtomIndex().size() );
		}
	}
	
	public void testIndices( )
	{
		// transformation settings
		int numSubunits = 4;
		GridPoint point = getRandomGridPoint();
		
		// generate a structure
		Protein oligomer = getOligomer( numSubunits, point );
		
		assertProteinIndicesCorrect( oligomer );
	}
	
	public void testCentroid( )
	{
		// the centroid of the oligomer should be the centroid of the centroids of the subunits
		// that is, if the symmetry is correct
		
		// transformation settings
		int numSubunits = 4;
		GridPoint point = TestMain.getSearchContext().getSymmetry().newGridPoint();
		
		// generate a structure
		Protein oligomer = getOligomer( numSubunits, point );
		
		// calculate the centroid of the oligomer
		Vector3 oligomerCentroid = new Vector3();
		Iterator<AtomAddressInternal> iterAtom = oligomer.getAtomIndex();
		while( iterAtom.hasNext() )
		{
			Vector3 pos = oligomer.getAtom( iterAtom.next() ).getPosition();
			oligomerCentroid.add( pos );
		}
		oligomerCentroid.scale( 1.0 / (double)oligomer.getNumAtoms() );
		
		// compute the centroid of the subunits' centroids
		Vector3 compoundCentroid = new Vector3();
		for( Subunit subunit : oligomer.getSubunits() )
		{
			// compute the subunit centroid
			Vector3 subunitCentroid = new Vector3();
			iterAtom = subunit.getAtomIndex().iterator();
			while( iterAtom.hasNext() )
			{
				Vector3 pos = subunit.getAtom( iterAtom.next() ).getPosition();
				subunitCentroid.add( pos );
			}
			subunitCentroid.scale( 1.0 / (double)subunit.getAtomIndex().size() );
			
			// update the compound centroid
			compoundCentroid.add( subunitCentroid );
		}
		compoundCentroid.scale( 1.0 / (double)numSubunits );
		
		assertEquals( oligomerCentroid, compoundCentroid );
	}
	
	private Protein getOligomer( int numSubunits, GridPoint point )
	{
		Subunit monomer = TestMain.getSearchContext().getMonomer();
		StructureGenerator generator = TestMain.getSearchContext().getSymmetry().newStructureGenerator( monomer );
		return generator.getStructure( point, numSubunits );
	}
}
