/* Copyright (C) 2001, 2002 Damir Zucic */

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

				  set_chi5.c

Purpose:
	Set the chi5 angle for each selected residue in  the given 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 chi5 angle in degrees.

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

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

Notes:
	(1) This function sets the  chi5 angle for ARG.  All other residues
	    are ignored.

========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		IsStandard_ (char *);
double		Chi5FromCDNECZNH1_ (AtomS *, size_t, size_t);
int		ExtractNECZ_ (VectorS *, VectorS *, AtomS *, size_t, size_t);
int		RotateAtom_ (AtomS *, VectorS *, VectorS *, double);
int		DihedralAngles_ (MolComplexS *, ConfigS *);

/*======set chi5:============================================================*/

int SetChi5_ (MolComplexS *mol_complexSP, ConfigS *configSP, double chi5_new)
{
int			residuesN, residueI;
size_t			atomsN, atomI;
ResidueS		*current_residueSP;
AtomS			*first_atomSP;
char			*residue_nameP;
size_t			current_startI, current_endI;
int			residue_typeI;
double			chi5_old, delta_chi5;
int			n;
static VectorS		NE_vectorS, CZ_vectorS;
AtomS			*atomSP;
char			*atom_nameP;

/* 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 the residues: */
for (residueI = 0; 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 name of the current residue: */
	residue_nameP = first_atomSP->raw_atomS.pure_residue_nameA;

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

	/* Check is the current residue from */
	/* the set of  20 standard residues: */
	residue_typeI = IsStandard_ (residue_nameP);

	/* This function works for ARG only: */
	if (residue_typeI != 1) continue;

	/* Now calculate and check the old chi5 value. */

	/* Initialize the old chi5: */
	chi5_old = BADDIHEDANGLE;

	/* Calculate the chi5_old (the residue */
	/* is  ARG  if this point is reached): */
	/* Use CD, NE, CZ and NH1 for ARG: */
	chi5_old = Chi5FromCDNECZNH1_ (mol_complexSP->atomSP,
				       current_startI, current_endI);

	/* Check the value: */
	if (chi5_old == BADDIHEDANGLE) continue;

	/* Calculate the difference: */
	delta_chi5 = chi5_new - chi5_old;

	/* Extract NE and CZ coordinates: */
	n = ExtractNECZ_ (&NE_vectorS, &CZ_vectorS,
			  mol_complexSP->atomSP, current_startI, current_endI);
	if (n < 2) continue;

	/* Change the chi5 angle: */
	for (atomI = current_startI; atomI <= current_endI; atomI++)
		{
		/* Pointer to the current atom: */
		atomSP = mol_complexSP->atomSP + atomI;

		/* Pointer to the purified atom name: */
		atom_nameP = atomSP->raw_atomS.pure_atom_nameA;

		/* Do not rotate  H, N, CA, HA, C, O, */
		/* CB, HB, CG, HG, CD, HD, NE and HE: */
		if (strcmp (atom_nameP, "H" ) == 0) continue;
		if (strcmp (atom_nameP, "N" ) == 0) continue;
		if (strcmp (atom_nameP, "CA") == 0) continue;
		if (strcmp (atom_nameP, "HA") == 0) continue;
		if (strcmp (atom_nameP, "C" ) == 0) continue;
		if (strcmp (atom_nameP, "O" ) == 0) continue;
		if (strcmp (atom_nameP, "CB") == 0) continue;
		if (strcmp (atom_nameP, "HB") == 0) continue;
		if (strcmp (atom_nameP, "CG") == 0) continue;
		if (strcmp (atom_nameP, "HG") == 0) continue;
		if (strcmp (atom_nameP, "CD") == 0) continue;
		if (strcmp (atom_nameP, "HD") == 0) continue;
		if (strcmp (atom_nameP, "NE") == 0) continue;
		if (strcmp (atom_nameP, "HE") == 0) continue;

		/* Rotate the current atom about NE-CZ bond: */
		RotateAtom_ (atomSP, &NE_vectorS, &CZ_vectorS, delta_chi5);
                }
	}

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

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


