/* Copyright (C) 2001 Damir Zucic */

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

				  set_psi.c

Purpose:
	Set the psi 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 psi angle in degrees.

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

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

Notes:
	(1) This function uses the atoms  N, CA, C of the current residue and
	    and the  N atom of  the next residue.  The O atom  of the current
	    residue is 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		ExtractN_ (VectorS *, AtomS *, size_t, size_t);
double		PsiFromNCACN_ (VectorS *, VectorS *, VectorS *, VectorS *,
			       ConfigS *);
int		RotateAtom_ (AtomS *, VectorS *, VectorS *, double);
int		DihedralAngles_ (MolComplexS *, ConfigS *);

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

int SetPsi_ (MolComplexS *mol_complexSP, ConfigS *configSP, double psi_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		*next_residueSP;
size_t			next_startI, next_endI;
static VectorS		nextN_vectorS;
double			psi_old, delta_psi;
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 omit the last one: */
for (residueI = 0; residueI < residuesN - 1; 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 N atom of the next residue is required. */

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

	/* The atomic index range for the next residue: */
	next_startI = next_residueSP->residue_startI;
	next_endI   = next_residueSP->residue_endI;

	/* Try to extract the N atom from the next residue: */
	n = ExtractN_ (&nextN_vectorS,
		       mol_complexSP->atomSP, next_startI, next_endI);
	if (n < 1) break;

	/* Calculate and check the old psi: */
	psi_old = PsiFromNCACN_ (&N_vectorS, &CA_vectorS, &C_vectorS,
				 &nextN_vectorS,
				 configSP);
	if (psi_old == BADDIHEDANGLE) continue;

	/* Calculate the difference: */
	delta_psi = psi_new - psi_old;

	/* Rotate the O atom of the current residue about CA-C bond: */
	for (atomI = current_startI; atomI <= current_endI; atomI++)
		{
		/* Pointer to the current atom: */
		atomSP = mol_complexSP->atomSP + atomI;

		/* The only atom which should be rotated is O: */
		if (strcmp (atomSP->raw_atomS.pure_atom_nameA, "O") != 0)
			{
			continue;
			}

		/* If this point is reached, rotate O about CA-C bond: */
		RotateAtom_ (atomSP, &CA_vectorS, &C_vectorS, delta_psi);
                }

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

		/* Rotate atom: */
		RotateAtom_ (atomSP, &CA_vectorS, &C_vectorS, delta_psi);
		}
	}

/* 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;
}

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


