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

import java.util.ArrayList;
import java.util.Iterator;

import edu.duke.donaldLab.share.io.Transformer;
import edu.duke.donaldLab.share.mapping.NameMapper;
import edu.duke.donaldLab.share.mapping.NameScheme;
import edu.duke.donaldLab.share.nmr.DistanceRestraint;
import edu.duke.donaldLab.share.nmr.Assignment;
import edu.duke.donaldLab.share.nmr.AssignmentIterator;
import edu.duke.donaldLab.share.nmr.DistanceRestraintMapper;
import edu.duke.donaldLab.share.nmr.DistanceRestraintReader;
import edu.duke.donaldLab.share.pdb.ProteinReader;
import edu.duke.donaldLab.share.protein.AtomAddressInternal;
import edu.duke.donaldLab.share.protein.AtomAddressReadable;
import edu.duke.donaldLab.share.protein.Protein;
import edu.duke.donaldLab.share.test.ExtendedTestCase;

public class TestAssignmentIterator extends ExtendedTestCase
{
	private static final String ProteinPath = "src/resources/test/largeProtein.pdb";
	private static final String NoesPath = "src/resources/test/large.noe";
	
	public void testOneAssignment( )
	{
		// build endpoints
		AtomAddressInternal l1 = new AtomAddressInternal( 1, 2, 3 );
		AtomAddressInternal r1 = new AtomAddressInternal( 7, 6, 5 );
		
		// build the restraint
		DistanceRestraint<AtomAddressInternal> restraint = new DistanceRestraint<AtomAddressInternal>();
		restraint.setLefts( Transformer.toTreeSet( l1 ) );
		restraint.setRights( Transformer.toTreeSet( r1 ) );
		
		// get the iterator
		AssignmentIterator<AtomAddressInternal> iter = new AssignmentIterator<AtomAddressInternal>( restraint );
		
		// check it, yo
		assertNextRestraint( iter, l1, r1 );
		assertFalse( iter.hasNext() );
	}
	
	public void testTwoLeftAssignments( )
	{
		// build endpoints
		AtomAddressInternal l1 = new AtomAddressInternal( 1, 2, 3 );
		AtomAddressInternal l2 = new AtomAddressInternal( 7, 6, 5 );
		AtomAddressInternal r1 = new AtomAddressInternal( 10, 11, 12 );
		
		// build the restraint
		DistanceRestraint<AtomAddressInternal> restraint = new DistanceRestraint<AtomAddressInternal>();
		restraint.setLefts( Transformer.toTreeSet( l1, l2 ) );
		restraint.setRights( Transformer.toTreeSet( r1 ) );
		
		// get the iterator
		AssignmentIterator<AtomAddressInternal> iter = new AssignmentIterator<AtomAddressInternal>( restraint );
		
		// check it, yo
		assertNextRestraint( iter, l1, r1 );
		assertNextRestraint( iter, l2, r1 );
		assertFalse( iter.hasNext() );
	}
	
	public void testTwoRightAssignments( )
	{
		// build endpoints
		AtomAddressInternal l1 = new AtomAddressInternal( 1, 2, 3 );
		AtomAddressInternal r1 = new AtomAddressInternal( 7, 6, 5 );
		AtomAddressInternal r2 = new AtomAddressInternal( 10, 11, 12 );
		
		// build the restraint
		DistanceRestraint<AtomAddressInternal> restraint = new DistanceRestraint<AtomAddressInternal>();
		restraint.setLefts( Transformer.toTreeSet( l1 ) );
		restraint.setRights( Transformer.toTreeSet( r1, r2 ) );
		
		// get the iterator
		AssignmentIterator<AtomAddressInternal> iter = new AssignmentIterator<AtomAddressInternal>( restraint );
		
		// check it, yo
		assertNextRestraint( iter, l1, r1 );
		assertNextRestraint( iter, l1, r2 );
		assertFalse( iter.hasNext() );
	}
	
	public void testTwoRightTwoLeftAssignments( )
	{
		// build endpoints
		AtomAddressInternal l1 = new AtomAddressInternal( 1, 2, 3 );
		AtomAddressInternal l2 = new AtomAddressInternal( 22,21, 20 );
		AtomAddressInternal r1 = new AtomAddressInternal( 7, 6, 5 );
		AtomAddressInternal r2 = new AtomAddressInternal( 10, 11, 12 );
		
		// build the restraint
		DistanceRestraint<AtomAddressInternal> restraint = new DistanceRestraint<AtomAddressInternal>();
		restraint.setLefts( Transformer.toTreeSet( l1, l2 ) );
		restraint.setRights( Transformer.toTreeSet( r1, r2 ) );
		
		// get the iterator
		AssignmentIterator<AtomAddressInternal> iter = new AssignmentIterator<AtomAddressInternal>( restraint );
		
		// check it, yo
		assertNextRestraint( iter, l1, r1 );
		assertNextRestraint( iter, l1, r2 );
		assertNextRestraint( iter, l2, r1 );
		assertNextRestraint( iter, l2, r2 );
		assertFalse( iter.hasNext() );
	}
	
	public void testAllAssignments( )
	throws Exception
	{
		// load some distance restraints and a protein
		Protein protein = new ProteinReader().read( ProteinPath );
		ArrayList<DistanceRestraint<AtomAddressReadable>> readableRestraints = new DistanceRestraintReader().read( NoesPath );
		NameMapper.ensureProtein( protein, NameScheme.New );
		NameMapper.ensureDistanceRestraints( protein, readableRestraints, NameScheme.New );
		ArrayList<DistanceRestraint<AtomAddressInternal>> restraints = DistanceRestraintMapper.mapReadableToInternal( readableRestraints, protein );
		
		// for each restraint
		for( DistanceRestraint<AtomAddressInternal> restraint : restraints )
		{
			// for each assignment
			for( @SuppressWarnings( "unused" ) Assignment<AtomAddressInternal> assignment : restraint )
			{
				// don't do anything (including crashing)
			}
		}
	}
	
	private void assertNextRestraint( Iterator<Assignment<AtomAddressInternal>> iter, AtomAddressInternal left, AtomAddressInternal right )
	{
		assertTrue( iter.hasNext() );
		Assignment<AtomAddressInternal> assignment = iter.next();
		assertEquals( left, assignment.getLeft() );
		assertEquals( right, assignment.getRight() );
	}
}
