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

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

				  set_chi1.c

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

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

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

Notes:
	(1) This function ignores ALA, GLY and PRO.

========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		Chi1FromNCACBCG_ (AtomS *, size_t, size_t);
double		Chi1FromNCACBSG_ (AtomS *, size_t, size_t);
double		Chi1FromNCACBCG1_ (AtomS *, size_t, size_t);
double		Chi1FromNCACBOG_ (AtomS *, size_t, size_t);
double		Chi1FromNCACBOG1_ (AtomS *, size_t, size_t);
int		ExtractCACB_ (VectorS *, VectorS *, AtomS *, size_t, size_t);
int		RotateAtom_ (AtomS *, VectorS *, VectorS *, double);
int		DihedralAngles_ (MolComplexS *, ConfigS *);

/*======set chi1:============================================================*/

int SetChi1_ (MolComplexS *mol_complexSP, ConfigS *configSP, double chi1_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			chi1_old, delta_chi1;
int			n;
static VectorS		CA_vectorS, CB_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);

	/* Do nothing for ALA, GLY and PRO: */
	if ((residue_typeI ==  0) || (residue_typeI == 7) ||
	    (residue_typeI == 14)) continue;

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

	/* Initialize the old chi1: */
	chi1_old = BADDIHEDANGLE;

	/* Calculate the chi1_old: */
	switch (residue_typeI)
		{
		/* Use N, CA, CB and CG for ARG, ASN, ASP, GLN, */
		/* GLU, HIS, LEU, LYS, MET, PHE, TRP  and  TYR: */
		case  1:	/* ARG */ 
		case  2:	/* ASN */
		case  3:	/* ASP */
		case  5:	/* GLN */
		case  6:	/* GLU */
		case  8:	/* HIS */
		case 10:	/* LEU */
		case 11:	/* LYS */
		case 12:	/* MET */
		case 13:	/* PHE */
		case 17:	/* TRP */
		case 18:	/* TYR */
			chi1_old = Chi1FromNCACBCG_ (mol_complexSP->atomSP,
						     current_startI,
						     current_endI);
			break;

		/* Use N, CA, CB and SG for CYS: */
		case 4:		/* CYS */
			chi1_old = Chi1FromNCACBSG_ (mol_complexSP->atomSP,
						     current_startI,
						     current_endI);
			break;

		/* Use N, CA, CB and CG1 for ILE and VAL: */
		case  9:	/* ILE */
		case 19:	/* VAL */
			chi1_old = Chi1FromNCACBCG1_ (mol_complexSP->atomSP,
						      current_startI,
						      current_endI);
			break;

		/* Use N, CA, CB and OG for SER: */
		case 15:	/* SER */
			chi1_old = Chi1FromNCACBOG_ (mol_complexSP->atomSP,
						     current_startI,
						     current_endI);
			break;

		/* Use N, CA, CB and OG1 for THR: */
		case 16:	/* THR */
			chi1_old = Chi1FromNCACBOG1_ (mol_complexSP->atomSP,
						      current_startI,
						      current_endI);
			break;

		/* At present, exotic residues are ignored: */
		default:
			;
		}

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

	/* Calculate the difference: */
	delta_chi1 = chi1_new - chi1_old;

	/* Extract CA and CB coordinates: */
	n = ExtractCACB_ (&CA_vectorS, &CB_vectorS,
			  mol_complexSP->atomSP, current_startI, current_endI);
	if (n < 2) continue;

	/* Change the chi1 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 and CB: */
		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;

		/* Rotate the current atom about CA-CB bond: */
		RotateAtom_ (atomSP, &CA_vectorS, &CB_vectorS, delta_chi1);
                }
	}

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

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


