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

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

				  set_chi2.c

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

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

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

Notes:
	(1) This function ignores ALA, CYS, GLY, PRO, SER, THR and VAL.

========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		Chi2FromCACBCGCD_ (AtomS *, size_t, size_t);
double		Chi2FromCACBCGOD1_ (AtomS *, size_t, size_t);
double		Chi2FromCACBCGND1_ (AtomS *, size_t, size_t);
double		Chi2FromCACBCG1CD_ (AtomS *, size_t, size_t);
double		Chi2FromCACBCGCD1_ (AtomS *, size_t, size_t);
double		Chi2FromCACBCGSD_ (AtomS *, size_t, size_t);
int		ExtractCBXG_ (VectorS *, VectorS *, AtomS *, size_t, size_t);
int		RotateAtom_ (AtomS *, VectorS *, VectorS *, double);
int		DihedralAngles_ (MolComplexS *, ConfigS *);

/*======set chi2:============================================================*/

int SetChi2_ (MolComplexS *mol_complexSP, ConfigS *configSP, double chi2_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			chi2_old, delta_chi2;
int			n;
static VectorS		CB_vectorS, XG_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, CYS, GLY, PRO, SER, THR and VAL: */
	if ((residue_typeI ==  0) || (residue_typeI ==  4) ||
	    (residue_typeI ==  7) || (residue_typeI == 14) ||
	    (residue_typeI == 15) || (residue_typeI == 16) ||
	    (residue_typeI == 19)) continue;

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

	/* Initialize the old chi2: */
	chi2_old = BADDIHEDANGLE;

	/* Calculate the chi2_old: */
	switch (residue_typeI)
		{
		/* Use CA, CB, CG and CD for ARG, GLN, GLU, LYS: */
		case  1:	/* ARG */
		case  5:	/* GLN */
		case  6:	/* GLU */
		case 11:	/* LYS */
			chi2_old =Chi2FromCACBCGCD_ (mol_complexSP->atomSP,
						     current_startI,
						     current_endI);
			break;

		/* Use CA, CB, CG and OD1 for ASN and ASP: */
		case  2:	/* ASN */
		case  3:	/* ASP */
			chi2_old =Chi2FromCACBCGOD1_ (mol_complexSP->atomSP,
						      current_startI,
						      current_endI);
			break;

		/* Use CA, CB, CG and ND1 for HIS: */
		case  8:	/* HIS */
			chi2_old =Chi2FromCACBCGND1_ (mol_complexSP->atomSP,
						      current_startI,
						      current_endI);
			break;

		/* Use CA, CB, CG1 and CD for ILE: */
		case  9:	/* ILE */
			chi2_old =Chi2FromCACBCG1CD_ (mol_complexSP->atomSP,
						      current_startI,
						      current_endI);
			break;

		/* Use CA, CB, CG and CD1 for LEU, PHE, TRP and TYR: */
		case 10:	/* LEU */
		case 13:	/* PHE */
		case 17:	/* TRP */
		case 18:	/* TYR */
			chi2_old =Chi2FromCACBCGCD1_ (mol_complexSP->atomSP,
						      current_startI,
						      current_endI);
			break;

		/* Use CA, CB, CG and SD for MET: */
		case 12:	/* MET */
			chi2_old =Chi2FromCACBCGSD_ (mol_complexSP->atomSP,
						     current_startI,
						     current_endI);
			break;

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

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

	/* Calculate the difference: */
	delta_chi2 = chi2_new - chi2_old;

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

	/* Change the chi2 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 and HB: */
		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;

		/* Rotate the current atom about CB-XG bond: */
		RotateAtom_ (atomSP, &CB_vectorS, &XG_vectorS, delta_chi2);
                }
	}

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

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


