/* Copyright (C) 2000 Damir Zucic */

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

			docking_project.c

Purpose:
	Prepare orthogonal projection of  the specified complex.  There
	are two complexes: bottom (1) and top (2).  The purpose of this
	function is to find the exposed  candidates for hydrogen bonds.
	Atomic positions are taken  relative to the plane center of the
	first complex and projected to xz plane.

Input:
	(1) Pointer to RuntimeS structure.
	(2) The index of  the complex   which should  be projected.  Do
	    not confuse  this index with  the actual  macromol. complex
	    index!  The values allowed here are 1 (bottom) and 2 (top).

Output:
	(1) The array of indices, which are listing exposed atoms, will
	    be prepared.
	(2) Return value.

Return value:
	(1) Positive on success.
	(2) Negative on failure.

Notes:
	(1) The index of exposed atom is of the type int, though size_t
	    is used elsewhere. The reason is that int may have negative
	    value,  while size_t is unsigned on many systems.  Negative
	    values are used to signal that data  stored to a given cell
	    are obsolete.

	(2) Indentation is exceptionally 4 spaces.

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

#include <stdio.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"

/*======function prototypes:=================================================*/

void		ErrorMessage_ (char *, char *, char *,
			       char *, char *, char *, char *);

/*======prepare orthogonal projection of the specified complex:==============*/

int DockingProject_ (RuntimeS *runtimeSP, int docking_complexI)
{
MolComplexS		*curr_mol_complexSP;
int			*exposed_atomIP;
ExposedResidueS		*exposed_polarSP;
double			x0, z0;
size_t			atomsN, atomI;
double			reciprocal_denominator;
int			matrix_width, elementsN, matrixI;
int			exposed_polarI;
int			atom_half_width;
AtomS			*curr_atomSP;
double			x, y, z;
double			relative_x, relative_z;
double			d;
int			central_rowI, central_columnI;
int			row0I, row1I, column0I, column1I;
int			rowI, columnI, combinedI;
int			*curr_cellP;
int			prev_atomI;
double			old_y;

/* Check the complex index and prepare the pointers: */
if (docking_complexI == 1)
    {
    curr_mol_complexSP = runtimeSP->mol_complex1SP;
    exposed_atomIP = runtimeSP->exposed_atom1IP;
    exposed_polarSP = runtimeSP->exposed_polar1SP;
    }
else if (docking_complexI == 2)
    {
    curr_mol_complexSP = runtimeSP->mol_complex2SP;
    exposed_atomIP = runtimeSP->exposed_atom2IP;
    exposed_polarSP = runtimeSP->exposed_polar2SP;
    }
else
    {
    ErrorMessage_ ("garlic", "DockingProject_", "",
		   "Bad macromolecular complex index!\n",
		   "", "", "");
    return -1;
    }

/* The reference (central) point is the center of the */
/* plane associated with  the first (bottom) complex. */
/* Here it is shifted for half of docking area width: */
x0 = runtimeSP->mol_complex1SP->planeS.center_x[0] -
     runtimeSP->docking_area_width / 2;
z0 = runtimeSP->mol_complex1SP->planeS.center_z[0] -
     runtimeSP->docking_area_width / 2;

/* Prepare and check the number of atoms: */
atomsN = curr_mol_complexSP->atomsN;
if (atomsN == 0) return -2;

/* Initialize the matrix of indices; negative value in some cell */
/* is used  to signal  that no atom was projected  to this cell: */
matrix_width = runtimeSP->docking_matrix_width;
elementsN = matrix_width * matrix_width;
for (matrixI = 0; matrixI < elementsN; matrixI++)
    {
    *(exposed_atomIP + matrixI) = -1;
    }

/* Reset excludedF flags: */
for (exposed_polarI = 0;
     exposed_polarI < MAX_EXPOSED_RESIDUES;
     exposed_polarI++)
	{
	(exposed_polarSP + exposed_polarI)->excludedF = 0;
	}

/* Atom radius in cells: */
if (runtimeSP->docking_cell_width != 0.0)
    {
    d = DOCKING_ATOM_RADIUS / runtimeSP->docking_cell_width;
    atom_half_width = (int) d;
    }
else atom_half_width = 0;

/* Auxilliary variable: */
if (runtimeSP->docking_cell_width != 0.0)
    {
    reciprocal_denominator = 1.0 / runtimeSP->docking_cell_width;
    }
else reciprocal_denominator = 0.0;

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

    /* x and z coordinate of the current atom: */
    x = curr_atomSP->raw_atomS.x[0];
    z = curr_atomSP->raw_atomS.z[0];

    /* y coordinate of the current atom: */
    y = curr_atomSP->raw_atomS.y;

    /* Coordinates  relative to  the upper left corner */
    /* of the area which is covered by docking matrix: */
    relative_x = x - x0;
    relative_z = z - z0;

    /* Matrix indices of the central point: row index depends on */
    /* relative_x and column index  depends on relative_z value: */
    d = floor (relative_x * reciprocal_denominator); 
    central_rowI = (int) d;
    d = floor (relative_z * reciprocal_denominator);
    central_columnI = (int) d;

    /* Scan the neighbourhood: */
    row0I = central_rowI - atom_half_width;
    row1I = central_rowI + atom_half_width;
    column0I = central_columnI - atom_half_width;
    column1I = central_columnI + atom_half_width;
    for (rowI = row0I; rowI <= row1I; rowI++)
	{
	/* The allowed range is from 0 to matrix_width: */
	if ((rowI < 0) || (rowI >= matrix_width)) continue;

	for (columnI = column0I; columnI <= column1I; columnI++)
	    {
	    /* The allowed range is from 0 to matrix_width: */
	    if ((columnI < 0) || (columnI >= matrix_width)) continue;

	    /* Prepare the combined array index (the matrix is */
	    /* stored in  the form of  one-dimensional array): */
	    combinedI = rowI * matrix_width + columnI;

	    /* Prepare the pointer to the current cell: */
	    curr_cellP = exposed_atomIP + combinedI;

	    /* The index of the atom reffered by the stored atomic index: */
	    prev_atomI = *curr_cellP;

	    /* If some atomic index was stored to the cell defined by */
	    /* rowI and columnI,  compare  y coordinates  of the atom */
	    /* reffered by this index and  the current atom.  For the */
	    /* bottom complex,  the obscured atom has higher y, while */
	    /* for  the top complex  the obscured atom  has lower  y. */
	    if (prev_atomI >= 0)
		{
		/* The y coordinate of the atom reffered by stored index: */
		old_y = (curr_mol_complexSP->atomSP + prev_atomI)->raw_atomS.y;

		/* If projecting bottom complex: */
		if (docking_complexI == 1)
		    {
		    if (old_y < y) continue;
		    }

		/* If projecting top complex: */
		else
		    {
		    if (old_y > y) continue;
		    }
		}

	    /* If this point is reached, the current atom is not obscured. */

	    /* Store the index of the current atom to the matrix: */
	    *curr_cellP = atomI;
	    }
	}
    }

/* Return positive value on success: */
return 1;
}

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


