/* Copyright (C) 2001 Damir Zucic */

/*=============================================================================

				  set_phi.c

Purpose:
	Set the phi angle for each selected residue in the specified complex.
	A residue is treated  as selected  if the first atom  of this residue
	is selected.  For proteins,  this is typically the N atom (nitrogen).

Input:
	(1) Pointer to MolComplexS structure.
	(2) Pointer to ConfigS structure.
	(3) The phi angle in degrees.

Output:
	(1) Phi angle set  for each selected residue  in each caught complex.
	(2) Return value.

Return value:
	(1) Positive always (trivial).

Notes:
	(1) This function uses only the main chain atoms to calculate the phi
	    angle. The coordinates of H atoms are not used.

========includes:============================================================*/

#include <stdio.h>

#include <string.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>

#include "defines.h"
#include "typedefs.h"

/*======function prototypes:=================================================*/

int		ExtractNCAC_ (VectorS *, VectorS *, VectorS *,
			      AtomS *, size_t, size_t);
int		ExtractC_ (VectorS *, AtomS *, size_t, size_t);
double		PhiFromCNCAC_ (VectorS *, VectorS *, VectorS *, VectorS *,
			       ConfigS *);
int		RotateAtom_ (AtomS *, VectorS *, VectorS *, double);
int		DihedralAngles_ (MolComplexS *, ConfigS *);

/*======set phi angle(s):====================================================*/

int SetPhi_ (MolComplexS *mol_complexSP, ConfigS *configSP, double phi_new)
{
int			residuesN, residueI;
size_t			atomsN, atomI;
ResidueS		*current_residueSP;
AtomS			*first_atomSP;
size_t			current_startI, current_endI;
int			n;
static VectorS		N_vectorS, CA_vectorS, C_vectorS;
ResidueS		*previous_residueSP;
size_t			previous_startI, previous_endI;
static VectorS		previousC_vectorS;
double			phi_old, delta_phi;
AtomS			*atomSP;

/* Copy the number of residues in the specified complex: */
residuesN = mol_complexSP->residuesN;

/* Copy the number of atoms in the specified complex: */
atomsN = mol_complexSP->atomsN;

/* Scan residues, but skip the first one: */
for (residueI = 1; residueI < residuesN; residueI++)
	{
	/* Pointer to the current residue: */
	current_residueSP = mol_complexSP->residueSP + residueI;

	/* Pointer to the first atom of this residue: */
	first_atomSP = mol_complexSP->atomSP +
		       current_residueSP->residue_startI;

	/* If the first atom of this residue is not */
	/* selected,  the residue  is not selected: */
	if (first_atomSP->selectedF == 0) continue;

	/* The range of atomic indices for the current residue: */
	current_startI = current_residueSP->residue_startI;
	current_endI   = current_residueSP->residue_endI;

	/* Try to extract N, CA and C coordinates for the current residue: */
	n = ExtractNCAC_ (&N_vectorS, &CA_vectorS, &C_vectorS,
			  mol_complexSP->atomSP, current_startI, current_endI);
	if (n < 3) continue;

	/* The C atom of the previous residue is required. */

	/* Pointer to the previous residue: */
	previous_residueSP = mol_complexSP->residueSP + residueI - 1;

	/* The atomic index range for the previous residue: */
	previous_startI = previous_residueSP->residue_startI;
	previous_endI   = previous_residueSP->residue_endI;

	/* Try to extract the C atom from the previous residue: */
	n = ExtractC_ (&previousC_vectorS,
		       mol_complexSP->atomSP, previous_startI, previous_endI);
	if (n < 1) break;

	/* Calculate and check the old phi: */
	phi_old = PhiFromCNCAC_ (&previousC_vectorS,
				 &N_vectorS, &CA_vectorS, &C_vectorS,
				 configSP);
	if (phi_old == BADDIHEDANGLE) continue;

	/* Calculate the difference: */
	delta_phi = phi_new - phi_old;

	/* Rotate all atoms of the current residue */
	/* (except H, N and CA)  about  N-CA bond: */
	for (atomI = current_startI; atomI <= current_endI; atomI++)
		{
		/* Pointer to the current atom: */
		atomSP = mol_complexSP->atomSP + atomI;

		/* Do not rotate H, N and CA: */
		if ((strcmp (atomSP->raw_atomS.pure_atom_nameA, "H")  == 0) ||
		    (strcmp (atomSP->raw_atomS.pure_atom_nameA, "N")  == 0) ||
		    (strcmp (atomSP->raw_atomS.pure_atom_nameA, "CA") == 0))
			{
			continue;
			}

		/* Rotate the current atom about N-CA bond: */
		RotateAtom_ (atomSP, &N_vectorS, &CA_vectorS, delta_phi);
                }

	/* Rotate all atoms after the current residue about N-CA bond: */
	for (atomI = current_endI + 1; atomI < atomsN; atomI++)
		{
		/* Pointer to the current atom: */
		atomSP = mol_complexSP->atomSP + atomI;

		/* Rotate atom: */
		RotateAtom_ (atomSP, &N_vectorS, &CA_vectorS, delta_phi);
		}
	}

/* Update dihedral angles and cis-trans flags: */
DihedralAngles_ (mol_complexSP, configSP);

/* Set the position_changedF: */
mol_complexSP->position_changedF = 1;

/* Return positive value (trivial): */
return 1;
}

/*===========================================================================*/


