/* Copyright (C) 2000-2003 Damir Zucic */

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

				strong_bonds.c

Purpose:
	Prepare strong bonds.  In proteins,  the waste majority of strong
	bonds (or all of them) are covalent bonds. Inter-atomic distances
	are used to recognize valid bonds.  This function does  not check
	the bond angles. For each atom, assume that bonds are established
	with neighboring atoms, as arranged in the input file.  The width
	of a window  to be scanned should be  defined through .garlicrc .
	In garlic,  there are two pseudoelements,  jellium and quarkonium
        (J and Q).  These  imaginary elements  are used to draw polygonal
	lines  and inert atoms.  Such  elements  were  invented  to adapt
	garlic for medical imaging.  The idea was  to represent the blood
	vessels in  human brain  as lines and  axon  retraction  balls as
	points (inert atoms).  J atoms  do not  form any bonds,  while  Q
	atoms bind to two neighboring Q atoms or, more precisely, only to
	the atoms which are listed as  the nearest neighbors in PDB file.
	The actual distance between neighboring Q atoms is not important.
	Q atoms  do not form  bonds  with atoms  from another chain.  For
	example, the i-th Q atom will form bonds with Q atoms with serial
	numbers  i - 1  and  i + 1  if all three atoms belong to the same
	chain.  This function  will not  generate  any pseudo-bonds  (see
	pseudo_bonds.c).

Input:
	(1) Pointer to MolComplexS structure, with macromolecular data.
	(2) The array index of a given macromolecular complex.
	(3) Pointer to ConfigS structure, with configuration data.

Output:
	(1) Information about bonds added to each element of  MolComplexS
	    array of structures.
	(2) Return value.

Return value:
	(1) The total number of bonds on success.
	(2) Zero if there are no atoms.
	(3) Negative, if there are some atoms but there are no bonds.

Notes:
	(1) If some atoms are  deleted or inserted,  all bonds have to be
	    updated.  Note that array indices are shifted  after addition
	    or deletion  of atoms;  that's the most important  reason for
	    thorough revision of bonds.

	(2) This function may be used to update bonds, so it is important
	    to reset the total number of bonds for each atom.

	(3) Hydrogen bonds are not treated here.

	(4) Disulfide bonds are not treated here.

	(5) It should be taken  into account that  hydrogen bond  or even
	    stronger bond may connect  atoms from two different macromol.
	    complexes.  TrueBondS structure associated  with a given atom
	    must contain the information  about the macromol.  complex to
	    which the neighboring  atom belongs.

========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		CheckDistance_ (double *, AtomS *, AtomS *, ConfigS *);
int		AddBond_ (AtomS *, int, int, int, size_t, double, int);

/*======prepare strong bonds:================================================*/

size_t StrongBonds_ (MolComplexS *mol_complexSP,
		     int mol_complexI, ConfigS *configSP)
{
size_t		total_bondsN = 0;
size_t		atomsN, atomI;
		/* Use signed int to store the following indices: */
int		neigh_start, neigh_end, neighborI, combinedI;
size_t		neighbor_arrayI;
AtomS		*curr_atomSP, *curr_neighborSP;
char		*symbolP;
int		pairID;
int		bond_typeI;
double		distance;
char		alt_location1, alt_location2; 

/* Return zero if there are no atoms: */
atomsN = mol_complexSP->atomsN;
if (atomsN == 0) return 0;

/* Covalent bonds are treated as type 1: */
bond_typeI = 1;

/* The first and the last neighbor to be checked: */
neigh_start = -1 * configSP->bond_candidates_backward;     /* Note the sign! */
neigh_end   =      configSP->bond_candidates_forward;

/* Scan all atoms: */
for (atomI = 0; atomI < atomsN; atomI++)
	{
	/** Pointer to the current atom: **/
	curr_atomSP = mol_complexSP->atomSP + atomI;

	/** Initialize/reset the number of bonds for a given atom: **/
	curr_atomSP->bondsN = 0;

	/** Ignore imaginary (J and Q) atoms: **/
	symbolP = curr_atomSP->raw_atomS.chemical_symbolA;
	if (strcmp (symbolP, " J") == 0) continue;
	if (strcmp (symbolP, " Q") == 0) continue;

	/** Scan the neighborhood of a given atom: **/
	for (neighborI = neigh_start; neighborI <= neigh_end; neighborI++)
		{
		/** Atom is not chemically bound to itself: **/
		if (neighborI == 0) continue;

		/** Prepare and check the combined index: **/
		combinedI = atomI + neighborI;
		if (combinedI < 0) continue;
		if (combinedI >= (int) atomsN) break;

		/** If combined index is good, use it as array index: **/
		neighbor_arrayI = combinedI;

		/** Pointer to the current neighbor: **/
		curr_neighborSP = mol_complexSP->atomSP + neighbor_arrayI;

		/** Check is there some sort of a chemical bond: **/
		pairID = CheckDistance_ (&distance,
					 curr_atomSP, curr_neighborSP,
					 configSP);

		/** If bond is bad, check the next neighbor: **/
		if (pairID <= 0) continue;

		/** Disulfide bonds should not be counted here: **/
		if (pairID == 11) continue;

		/** Compare the alternate location indicators; **/
		/** if both indicators  are different from ' ' **/
		/** and mutually different,  the bond  is bad! **/
		alt_location1 = curr_atomSP->raw_atomS.alt_location;
		alt_location2 = curr_neighborSP->raw_atomS.alt_location;
		if ((alt_location1 != alt_location2) &&
		    (alt_location1 != ' ') && (alt_location2 != ' '))
			{
			continue;
			}

		/** If this point is reached, the bond does exist! **/

		/** Add bond to the current atom: **/
		AddBond_ (curr_atomSP,
			  pairID, bond_typeI,
			  mol_complexI, neighbor_arrayI,
			  distance, configSP->default_bond_styleI);

		/* Update the number of bonds in a macromolecular complex: **/
		total_bondsN++;
		}
	}

/* If this point is reached, return the total number of bonds: */
return total_bondsN;
}

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


