/* Copyright (C) 2001 Damir Zucic */

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

				edit_omega.c

Purpose:
        Edit omega angle.  If edit_single_bondF is zero,  edit omega for
	every selected residue in  the specified macromolecular complex.
	If the flag edit_single_bondF is different from zero,  edit only
	the omega angle for the bond specified by the given atomic array
	indices.  If the peptide bond is formed by residues I and I + 1,
	it is assigned to residue  I + 1.  The same is valid  for omega.
        A residue  is treated  as selected  if the  first  atom  of this
        residue is selected.  For protein residues,  this is typically N
        atom (nitrogen).

Input:
	(1) Pointer to MolComplexS structure.
	(2) Pointer to RuntimeS structure.
	(3) Pointer to ConfigS structure.
	(4) Rotation angle.

Output:
	(1) Omega angle changed for chosen residue(s).
	(2) Return value.

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

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

#include <stdio.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		ExtractC_ (VectorS *, AtomS *, size_t, size_t);
int		ExtractN_ (VectorS *, AtomS *, size_t, size_t);
int		RotateAtom_ (AtomS *, VectorS *, VectorS *, double);
int		DihedralAngles_ (MolComplexS *, ConfigS *);

/*======change omega angle for selected residues:============================*/

int EditOmega_ (MolComplexS *mol_complexSP,
		RuntimeS *runtimeSP, ConfigS *configSP,
		double delta_omega)
{
int			residuesN, residueI;
size_t			atomsN;
ResidueS		*residueSP;
size_t			startI, endI, atomI;
AtomS			*atomSP;
ResidueS		*previous_residueSP;
size_t			previous_startI, previous_endI;
int			atom1_foundF, atom2_foundF;
int			n;
VectorS			C_vectorS;
VectorS			N_vectorS;

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

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

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

	/* The atomic index range for the current residue: */
	startI = residueSP->residue_startI;
	endI   = residueSP->residue_endI;

	/* Pointer to the first atom of the current residue: */
	atomSP = mol_complexSP->atomSP + startI;

	/* Pointer to the previous residue (be sure */
	/* that residueI never starts  from zero!): */
	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;

	/* Editing of a single omega angle requested: */
	if (runtimeSP->edit_single_bondF)
		{
		/* Reset flags: */
		atom1_foundF = 0;
		atom2_foundF = 0;

		/* Check does the first atom belong to either the */
		/* current residue  or to  the  previous residue: */
		if ((runtimeSP->atom1_arrayI >= startI)  &&
		    (runtimeSP->atom1_arrayI <= endI  ))
			{
			atom1_foundF = 1;
			}
		else if ((runtimeSP->atom1_arrayI >= previous_startI)  &&
			 (runtimeSP->atom1_arrayI <= previous_endI  ))
			{
			atom1_foundF = 1;
			}

		/* Check does the second atom belong to either */
		/* the current residue or to the previous one: */
		if ((runtimeSP->atom2_arrayI >= startI)  &&
		    (runtimeSP->atom2_arrayI <= endI  ))
			{
			atom2_foundF = 1;
			}
		else if ((runtimeSP->atom2_arrayI >= previous_startI)  &&
			 (runtimeSP->atom2_arrayI <= previous_endI  ))
			{
			atom2_foundF = 1;
			}

		/* Both atoms are required to specify the C-N bond: */
		if ((atom1_foundF == 0) || (atom2_foundF == 0)) continue;
		}

	/* Editing of omega angles for all selected residues requested: */
	else
		{
		/* If the first atom of the current residue is */
		/* not selected,  the residue is not selected: */
		if (atomSP->selectedF == 0) continue;
		}

	/* The coordinates of the C atom of the previous residue: */
	n = ExtractC_ (&C_vectorS,
		       mol_complexSP->atomSP,
		       previous_startI, previous_endI);
	if (n != 1) continue;

	/* The coordinates of the N atom of the current residue: */
	n = ExtractN_ (&N_vectorS,
		       mol_complexSP->atomSP,
		       startI, endI);
	if (n != 1) continue;

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

		/* Rotate atom: */
		RotateAtom_ (atomSP, &C_vectorS, &N_vectorS, delta_omega);
		}
	}

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

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

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


