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

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

				check_dist.c

Purpose:
	Try to recognize the atomic pair. If pair is recognized, check
	the distance between two atoms. If this distance fits into the
	bond length  range  which  corresponds to  given  atomic pair,
	return positive value.  Otherwise return  negative value.  See
	bellow for a list of pairs this routine recognizes. This array
	is called known_pairAA. Add more to the list, but don't forget
	to update  the array size.  Changes in  PDB format may require
	the modification of this function. It is assumed that chemical
	symbol is right justified and  that exactly two characters are
	used for representation. Pairs like " C N" and " N C" etc. are
	treated as  equivalent and thus  should have  equal ID's.  The
	array with pair ID's  is called  known_pairsIDA.  Unrecognized
	pairs are also checked,  using generic bond length limits.

Input:
	(1) Pointer to inter-atomic distance.
	(2) Pointer to AtomS structure with data about one atom.
	(3) Pointer to AtomS structure with data about another atom.
	(4) Pointer to ConfigS structure, with configuration data,

Output:
	(1) Bond length, if bond is recognized.
	(2) Return value.

Return value:
	(1) If atomic pair is recognized and  the distance corresponds
	    to a valid bond length, atomic pair ID is returned.
	(2) Negative if inter-atomic distance is bad.

Notes:
	(1) The pair identifier value of zero is reserved for hydrogen
	    bonds.

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

#include <stdio.h>

#include <string.h>
#include <math.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>

#include "defines.h"
#include "typedefs.h"

/*======check inter-atomic distance:=========================================*/

int CheckDistance_ (double *distanceP,
		    AtomS *atom1SP, AtomS *atom2SP, ConfigS *configSP)
{
char			atomic_pairA[40];
static char		known_pairAA[KNOWNPAIRS][PAIRSIZE] =
			    {" C C", " C C", " C N", " N C", " C O", " O C",
			     " C S", " S C", " C H", " H C", " N O", " O N",
			     " N H", " H N", " O H", " H O", " S H", " H S",
			     " O P", " P O", " S S", " S S"};
static int		known_pairIDA[KNOWNPAIRS] = {1,  1,  2,  2,  3,  3,
						     4,  4,  5,  5,  6,  6,
						     7,  7,  8,  8,  9,  9,
						    10, 10, 11, 11};
int			pair_string_len;
int			i;
int			pairID;
double			delta_x, delta_y, delta_z;
double			distance_squared;

/* Auxiliary integer: */
pair_string_len = PAIRSIZE - 1;

/* Prepare the string which will contain both chemical symbols: */
strcpy (atomic_pairA, atom1SP->raw_atomS.chemical_symbolA);
strncat (atomic_pairA, atom2SP->raw_atomS.chemical_symbolA, 2);
atomic_pairA[pair_string_len] = '\0';

/* Hydrogen to hydrogen bond  is not allowed in garlic: */
/* (Note: H_TO_H_BOND must be negative, see defines.h!) */
if (strncmp (" H H", atomic_pairA, pair_string_len) == 0) return H_TO_H_BOND;

/* Try to recognize the atomic pair: */
pairID = GENERICID;		/* The initial value */

for (i = 0; i < KNOWNPAIRS; i++)
	{
	if (strncmp (known_pairAA[i], atomic_pairA, pair_string_len) == 0)
		{
		pairID = known_pairIDA[i];
		break;
		}
	}

/* Calculate the squared distance: */
delta_x = atom1SP->raw_atomS.x[0] - atom2SP->raw_atomS.x[0];
delta_y = atom1SP->raw_atomS.y    - atom2SP->raw_atomS.y; 
delta_z = atom1SP->raw_atomS.z[0] - atom2SP->raw_atomS.z[0];
distance_squared = delta_x * delta_x + delta_y * delta_y + delta_z * delta_z;

/* Check the squared distance: if it doesn't fit into */
/* the range for a given pair, return negative value: */
switch (pairID)
	{
	/* C-C: */
	case 1:
		if (distance_squared > configSP->C_C_max_squared) return -1;
		if (distance_squared < configSP->C_C_min_squared) return -2;
		break;

	/* C-N: */
	case 2:
		if (distance_squared > configSP->C_N_max_squared) return -3;
		if (distance_squared < configSP->C_N_min_squared) return -4;
		break;

	/* C-O: */
	case 3:
		if (distance_squared > configSP->C_O_max_squared) return -5;
		if (distance_squared < configSP->C_O_min_squared) return -6;
		break;

	/* C-S: */
	case 4:
		if (distance_squared > configSP->C_S_max_squared) return -7;
		if (distance_squared < configSP->C_S_min_squared) return -8;
		break;

	/* C-H: */
	case 5:
		if (distance_squared > configSP->C_H_max_squared) return  -9;
		if (distance_squared < configSP->C_H_min_squared) return -10;
		break;

	/* N-O: */
	case 6:
		if (distance_squared > configSP->N_O_max_squared) return -11;
		if (distance_squared < configSP->N_O_min_squared) return -12;

	/* N-H: */
	case 7:
		if (distance_squared > configSP->N_H_max_squared) return -13;
		if (distance_squared < configSP->N_H_min_squared) return -14;
		break;

	/* O-H: */
	case 8:
		if (distance_squared > configSP->O_H_max_squared) return -15;
		if (distance_squared < configSP->O_H_min_squared) return -16;
		break;

	/* S-H: */
	case 9:
		if (distance_squared > configSP->S_H_max_squared) return -17;
		if (distance_squared < configSP->S_H_min_squared) return -18;
		break;

	/* O-P: */
	case 10:
		if (distance_squared > configSP->O_P_max_squared) return -19;
		if (distance_squared < configSP->O_P_min_squared) return -20;
		break;

	/* S-S (disulfide bond): */
	case 11:
		if (distance_squared > configSP->S_S_max_squared) return -21;
		if (distance_squared < configSP->S_S_min_squared) return -22;
		break;

	/* If this happens, pair was not recognized: */
	case GENERICID:
		if (distance_squared > configSP->generic_max_squared)
			return -23;
		if (distance_squared < configSP->generic_min_squared)
			return -24;
		break;

	/* The impossible option: */
	default:
		return -9999;

	}

/* If this point is reached, the bond fits */
/* into the range; calculate the distance: */
*distanceP = sqrt (distance_squared);

/* Return pair ID on success: */
return pairID;
}

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


