/* Copyright (C) 2001 Damir Zucic */

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

			    ex_template_residues.c

Purpose:
	Extract template residues. Remove whitespace from residue names.
	In addition, add residue array index to each atom.

Input:
	(1) Pointer to RuntimeS structure, which should contain template
	    atoms.

Output:
	(1) An array of ResidueS structures allocated and initialized.
	(2) Return value.

Return value:
	(1) The number of template residues (positive or zero).
	(2) Negative on failure.

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

#include <stdio.h>

#include <stdlib.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		CountTemplateResidues_ (RuntimeS *);
void		ErrorMessage_ (char *, char *, char *,
			       char *, char *, char *, char *);

/*======extract template residues:===========================================*/

int ExtractTemplateResidues_ (RuntimeS *runtimeSP)
{
int		template_atomsN, template_atomI;
int		template_residuesN, template_residueI = 0;
size_t		struct_size, elementsN;
AtomS		*curr_atomSP;
int		previous_residueI, current_residueI;
int		previous_insertion_code, current_insertion_code;
ResidueS	*current_residueSP;
ResidueS	*previous_residueSP;

/* Initialize the number of template residues: */
runtimeSP->template_residuesN = 0;

/* Check the number of template atoms: */
template_atomsN = runtimeSP->template_atomsN;
if (template_atomsN == 0) return 0;

/* Count the template residues; return negative if there are no residues: */
template_residuesN = CountTemplateResidues_ (runtimeSP);
if (template_residuesN == 0) return -1;

/* Store the number of template residues: */
runtimeSP->template_residuesN = template_residuesN;

/* Allocate the storage for template residues: */
struct_size = sizeof (ResidueS);
elementsN = template_residuesN + 10;
runtimeSP->template_residueSP = (ResidueS *) calloc (elementsN, struct_size);
if (runtimeSP->template_residueSP == NULL)
	{
	ErrorMessage_ ("garlic", "ExtractTemplateResidues_", "",
		       "Failed to allocate memory for template residues!\n",
		       "", "", "");
	return -2;
	}

/* The first atom has a special treatment: */
curr_atomSP = runtimeSP->template_atomSP;
curr_atomSP->residue_arrayI = 0;
previous_residueI = curr_atomSP->raw_atomS.residue_sequenceI;
previous_insertion_code = curr_atomSP->raw_atomS.residue_insertion_code;

/* Extract residue information, but skip the first atom: */
for (template_atomI = 1; template_atomI < template_atomsN; template_atomI++)
	{
	/* Pointer to raw atomic data: */
	curr_atomSP = runtimeSP->template_atomSP + template_atomI;

	/* Copy the residue sequence number and residue insertion code: */
	current_residueI = curr_atomSP->raw_atomS.residue_sequenceI;
	current_insertion_code = curr_atomSP->raw_atomS.residue_insertion_code;

	/* Compare the current residue sequence number with the old one */
	/* and  the current residue  insertion code  with the old code. */

	/* If this atom belongs to the same residue as the previous */
	/* one, set the residue array index and take the next atom: */
	if ((current_residueI == previous_residueI) &&
	    (current_insertion_code == previous_insertion_code))
		{
		curr_atomSP->residue_arrayI = template_residueI;
		continue;
		}

	/* If this atom  does not belong to  the same residue as */
	/* the previous one,  increment  the residue array index */
	/* by one and assign the incremented value to this atom: */
	else
		{
		template_residueI++;
		curr_atomSP->residue_arrayI = template_residueI;
		}

	/* If this point is reached, a new residue is found. */

	/* Prepare the pointer to the current residue: */
	current_residueSP = runtimeSP->template_residueSP + template_residueI;

	/* The residue start index for the current residue: */
	current_residueSP->residue_startI = template_atomI;

	/* The initial (dummy) residue end index for the current residue: */
	current_residueSP->residue_endI = template_atomI;

	/* The residue end index for the previous residue: */
	if (template_residueI != 0)
		{
		previous_residueSP = runtimeSP->template_residueSP +
				     template_residueI - 1;
		if (template_atomI != 0)
			{
			previous_residueSP->residue_endI = template_atomI - 1;
			}
		}

	/* Copy the residue sequence index and residue insertion code: */
	previous_residueI = current_residueI;
	previous_insertion_code = current_insertion_code;
	}

/* The residue end index for the last residue: */
if (template_residueI != 0)
	{
	previous_residueSP = runtimeSP->template_residueSP + template_residueI;
	if (template_atomI != 0)
		{
		previous_residueSP->residue_endI = template_atomI - 1;
		}
	}

/* If this point is reached, return the number of template residues: */
return template_residuesN;
}

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


