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

import java.util.List;

import edu.duke.donaldLab.share.geom.Vector3;
import edu.duke.donaldLab.share.mapping.NameMapper;
import edu.duke.donaldLab.share.mapping.NameScheme;
import edu.duke.donaldLab.share.nmr.ChemicalShift;
import edu.duke.donaldLab.share.nmr.ChemicalShiftReader;
import edu.duke.donaldLab.share.pdb.ProteinReader;
import edu.duke.donaldLab.share.protein.AminoAcid;
import edu.duke.donaldLab.share.protein.Element;
import edu.duke.donaldLab.share.protein.Protein;
import edu.duke.donaldLab.share.protein.AtomAddressReadable;
import edu.duke.donaldLab.share.protein.Residue;
import edu.duke.donaldLab.share.protein.Subunit;
import edu.duke.donaldLab.share.pseudoatoms.PseudoatomBuilder;
import edu.duke.donaldLab.share.test.ExtendedTestCase;

public class TestPseudoatomBuilder extends ExtendedTestCase
{
	private static final String ProteinPath = "src/resources/test/largeProtein.pdb";
	
	public void testProtein( )
	throws Exception
	{
		// get a protein
		Protein protein = new ProteinReader().read( ProteinPath );
		
		PseudoatomBuilder builder = PseudoatomBuilder.getInstance();
		builder.build( protein );
		
		// make sure a few of the pseudoatoms were added
		for( Subunit subunit : protein.getSubunits() )
		{
			for( Residue residue : subunit.getResidues() )
			{
				switch( residue.getAminoAcid() )
				{
					case Phenylalanine:
						assertNotNull( residue.getAtomByName( "qb" ) );
						assertNotNull( residue.getAtomByName( "qd" ) );
						assertNotNull( residue.getAtomByName( "qe" ) );
						assertNotNull( residue.getAtomByName( "qr" ) );
					break;
					
					case Lysine:
						assertNotNull( residue.getAtomByName( "qb" ) );
						assertNotNull( residue.getAtomByName( "qg" ) );
						assertNotNull( residue.getAtomByName( "qd" ) );
						assertNotNull( residue.getAtomByName( "qe" ) );
					break;
				}
			}
		}
		
		// check a few of the atom positions
		Residue residue = null;
		
		// get a Phe residue in the first subunit
		residue = protein.getResidue( 0, 9 );
		assertEquals( AminoAcid.Phenylalanine, residue.getAminoAcid() );
		assertEquals( new Vector3( 15.38250, 0.63550, 6.19000 ), residue.getAtomByName( "qb" ).getPosition() );
		assertEquals( new Vector3( 15.72000, 1.33700, 8.13050 ), residue.getAtomByName( "qd" ).getPosition() );
		assertEquals( new Vector3( 15.69400, 1.75900, 10.57550 ), residue.getAtomByName( "qe" ).getPosition() );
		assertEquals( new Vector3( 15.70733, 1.54833, 9.35350 ), residue.getAtomByName( "qr" ).getPosition() );
		
		// Lysine
		residue = protein.getResidue( 0, 0 );
		assertEquals( AminoAcid.Lysine, residue.getAminoAcid() );
		assertEquals( new Vector3( 15.34050, 24.45850, 5.86300 ), residue.getAtomByName( "qb" ).getPosition() );
		assertEquals( new Vector3( 14.50100, 26.68850, 6.18800 ), residue.getAtomByName( "qg" ).getPosition() );
		assertEquals( new Vector3( 13.40150, 26.22700, 4.15100 ), residue.getAtomByName( "qd" ).getPosition() );
		assertEquals( new Vector3( 15.54850, 26.14650, 3.16350 ), residue.getAtomByName( "qe" ).getPosition() );
	}
	
	public void testChemicalShift( )
	throws Exception
	{
		// read the protein
		Protein protein = new ProteinReader().read( "src/resources/test/1Q10.monomer.protein" );
		NameMapper.ensureProtein( protein, NameScheme.New );
		
		// read the shifts
		List<ChemicalShift> shifts = new ChemicalShiftReader().read( "src/resources/test/chemical.shifts" );
		NameMapper.ensureShifts( protein, shifts, NameScheme.New );
		assertEquals( 4, shifts.size() );
		
		// build the pseudoatoms - it shouldn't change anything
		PseudoatomBuilder.getInstance().buildShifts( protein, shifts );
		
		assertEquals( 4, shifts.size() );
		ChemicalShift shift = null;
		
		// 43  4 LYS CE   C  41.8662 0.2  1 
		shift = shifts.get( 0 );
		assertEquals( 43, shift.getNumber() );
		assertEquals( 1, shift.getAddresses().size() );
		assertEquals( new AtomAddressReadable( 'A', 4, "CE" ), shift.getAddresses().iterator().next() );
		assertEquals( AminoAcid.Lysine, shift.getAminoAcid() );
		assertEquals( Element.Carbon, shift.getElement() );
		assertEquals( 41.8662, shift.getValue() );
		assertEquals( 0.2, shift.getError() );
		assertEquals( 1, shift.getAmbiguityCode() );
		
		// 124 12 LEU HA   H   5.0068 0.02 1 
		shift = shifts.get( 1 );
		assertEquals( 124, shift.getNumber() );
		assertEquals( 1, shift.getAddresses().size() );
		assertEquals( new AtomAddressReadable( 'A', 12, "HA" ), shift.getAddresses().iterator().next() );
		assertEquals( AminoAcid.Leucine, shift.getAminoAcid() );
		assertEquals( Element.Hydrogen, shift.getElement() );
		assertEquals( 5.0068, shift.getValue() );
		assertEquals( 0.02, shift.getError() );
		assertEquals( 1, shift.getAmbiguityCode() );
		
		// 422 45 TYR H    H   8.8528 0.02 1
		shift = shifts.get( 2 );
		assertEquals( 422, shift.getNumber() );
		assertEquals( 1, shift.getAddresses().size() );
		assertEquals( new AtomAddressReadable( 'A', 45, "H" ), shift.getAddresses().iterator().next() );
		assertEquals( AminoAcid.Tyrosine, shift.getAminoAcid() );
		assertEquals( Element.Hydrogen, shift.getElement() );
		assertEquals( 8.8528, shift.getValue() );
		assertEquals( 0.02, shift.getError() );
		assertEquals( 1, shift.getAmbiguityCode() );
		
		// 466 50 LYS CG   C  24.5176 0.2  1 
		shift = shifts.get( 3 );
		assertEquals( 466, shift.getNumber() );
		assertEquals( 1, shift.getAddresses().size() );
		assertEquals( new AtomAddressReadable( 'A', 50, "CG" ), shift.getAddresses().iterator().next() );
		assertEquals( AminoAcid.Lysine, shift.getAminoAcid() );
		assertEquals( Element.Carbon, shift.getElement() );
		assertEquals( 24.5176, shift.getValue() );
		assertEquals( 0.2, shift.getError() );
		assertEquals( 1, shift.getAmbiguityCode() );
	}
	
	public void testChemicalShiftPseudo( )
	throws Exception
	{
		// read the protein
		Protein protein = new ProteinReader().read( "src/resources/test/1Q10.monomer.protein" );
		NameMapper.ensureProtein( protein, NameScheme.New );
		
		// read the shifts
		List<ChemicalShift> shifts = new ChemicalShiftReader().read( "src/resources/test/chemical.pseudo.shifts" );
		NameMapper.ensureShifts( protein, shifts, NameScheme.New );
		assertEquals( 2, shifts.size() );
		
		// build the pseudoatoms
		PseudoatomBuilder.getInstance().buildShifts( protein, shifts );
		
		assertEquals( 2, shifts.size() );
		ChemicalShift shift = null;

		// 8  1 MET HE   H   2.1100 0.02 1
		shift = shifts.get( 0 );
		assertEquals( 8, shift.getNumber() );
		assertEquals( 1, shift.getAddresses().size() );
		assertEquals( new AtomAddressReadable( 'A', 1, "ME" ), shift.getAddresses().iterator().next() );
		assertEquals( AminoAcid.Methionine, shift.getAminoAcid() );
		assertEquals( Element.Hydrogen, shift.getElement() );
		assertEquals( 2.1100, shift.getValue() );
		assertEquals( 0.02, shift.getError() );
		assertEquals( 1, shift.getAmbiguityCode() );
		
		// 130 12 LEU HD2  H   0.1190 0.02 2 
		shift = shifts.get( 1 );
		assertEquals( 130, shift.getNumber() );
		assertEquals( 1, shift.getAddresses().size() );
		assertEquals( new AtomAddressReadable( 'A', 12, "MD2" ), shift.getAddresses().iterator().next() );
		assertEquals( AminoAcid.Leucine, shift.getAminoAcid() );
		assertEquals( Element.Hydrogen, shift.getElement() );
		assertEquals( 0.1190, shift.getValue() );
		assertEquals( 0.02, shift.getError() );
		assertEquals( 2, shift.getAmbiguityCode() );
	}
}
