/* Copyright (C) 2004-2006 Damir Zucic */

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

				color_weighted.c

Purpose:
	Weighted  color scheme:  colors are assigned  according  to weighted
	hydrophobicity. The array of weights may be seen below. The absolute
	weighted hydrophobicity values are used.  The residue  which has the
	minimal absolute weighted hydrophobicity value  will be colored blue
	and the residue which has the maximal value of the absolute weighted
	hydrophobicity  will be colored red.  Almost the entire  spectrum of
	"rainbow" colors is used, except magenta: blue, cyan, green, yellow,
	orange and red.

Input:
	(1) Pointer to MolComplexS structure, with macromol. complexes.
	(2) Number of macromolecular complexes.
	(3) Pointer to GUIS structure, with GUI data.
	(4) Pointer to ColorSchemeS structure.

Output:
	(1) Return value.

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

Notes:
	(1) Indentation is exceptionally four spaces.

	(2) The minimal and maximal value are calculated separately for each
	    macromolecular complex.

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

#include <stdio.h>

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

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

void		ErrorMessage_ (char *, char *, char *, 
			       char *, char *, char *, char *);
int		MixColors_ (AtomS *, ColorSchemeS *, ColorSchemeS *,
			    double, GUIS *);

/*======weighted color scheme:===============================================*/

int ColorWeighted_ (MolComplexS *mol_complexSP, int mol_complexesN,
		    GUIS *guiSP, ColorSchemeS *color_schemeSP)
{
size_t			rgb_struct_size;
ColorSchemeS		*blue_schemeSP, *cyan_schemeSP, *green_schemeSP,
			*yellow_schemeSP, *orange_schemeSP, *red_schemeSP;
int			max_residuesN;
int			mol_complexI;
MolComplexS		*curr_mol_complexSP;
int			residuesN;
static double		*weightedP;
int			residueI;
double			min_abs_value, max_abs_value;
double			weighted;
int			windowI, combinedI;
ResidueS		*curr_residueSP;
int			first_atomI, last_atomI, atomI;
AtomS			*first_atomSP;
double			hydrophobicity;
static double		weightA[11] =
			{ 1.0,  1.0,  1.0,  1.0,  1.0,
			  0.0,
			 -1.0, -1.0, -1.0, -1.0, -1.0};
double			abs_value;
double			range, inverse_range;
double			delta_range, inverse_delta_range;
int			rangeI;
double			scale_factor;
AtomS			*curr_atomSP;

/*------auxiliary parameters and pointers:-----------------------------------*/

/* The size of RGBS structure: */
rgb_struct_size = sizeof (RGBS);

/* Pointer to color schemes: */
blue_schemeSP   = color_schemeSP +  2;
cyan_schemeSP   = color_schemeSP +  4;
green_schemeSP  = color_schemeSP +  1;
yellow_schemeSP = color_schemeSP +  3;
orange_schemeSP = color_schemeSP + 12;
red_schemeSP    = color_schemeSP +  0;

/*------find the maximal number of residues:---------------------------------*/

/* Initialize the maximal number of residues: */
max_residuesN = 0;

/* Scan every macromolecular complex: */
for (mol_complexI = 0; mol_complexI < mol_complexesN; mol_complexI++)
    {
    /* Pointer to the current macromolecular complex: */
    curr_mol_complexSP = mol_complexSP + mol_complexI;

    /* Check is the current macromolecular complex caught: */
    if (curr_mol_complexSP->catchF == 0) continue;

    /* Check the number of residues: */
    residuesN = curr_mol_complexSP->residuesN;
    if (residuesN > max_residuesN) max_residuesN = residuesN;
    }

/* Check was there anything at all: */
if (max_residuesN == 0)
    {
    ErrorMessage_ ("garlic", "ColorSchemes_", "",
		   "No residues found!\n",
		   "", "", "");
		   return -1;
    }

/*------allocate the storage for weighted hydrophobicity:--------------------*/

weightedP = (double *) calloc (max_residuesN, sizeof (double));
if (weightedP == NULL)
    {
    ErrorMessage_ ("garlic", "ColorSchemes_", "",
		   "Failed to allocate memory!\n",
		   "", "", "");
    return -2;
    }

/*------calculate the absolute weighted hydrophobicity values:---------------*/

/* Scan every macromolecular complex: */
for (mol_complexI = 0; mol_complexI < mol_complexesN; mol_complexI++)
    {
    /* Pointer to the current macromolecular complex: */
    curr_mol_complexSP = mol_complexSP + mol_complexI;

    /* Check is the current macromolecular complex caught: */
    if (curr_mol_complexSP->catchF == 0) continue;

    /* Copy the number of residues: */
    residuesN = curr_mol_complexSP->residuesN;
    if (residuesN == 0) continue;

    /* Reset the extreme absolute values of weighted hydrophobicity: */
    min_abs_value = +999999.0;
    max_abs_value = -999999.0;

    /* Scan all residues: */
    for (residueI = 5; residueI < residuesN - 5; residueI++)
	{
	/* Reset the weighted hydrophobicity: */
	weighted = 0.0;

	/* Scan the window of 15 residues: */
	for (windowI = 0; windowI < 11; windowI++)
	    {
	    /* Prepare and check the combined index: */
	    combinedI = residueI + windowI - 5;
	    if (combinedI < 0) continue;
	    if (combinedI >= residuesN) continue;
	
	    /* Pointer to the current residue: */
	    curr_residueSP = curr_mol_complexSP->residueSP + combinedI;

	    /* Pointer to the first atom of this residue: */
	    first_atomI = curr_residueSP->residue_startI;
	    first_atomSP = (curr_mol_complexSP->atomSP + first_atomI);

	    /* Copy the hydrophobicity associated with this residue: */
	    hydrophobicity = first_atomSP->raw_atomS.hydrophobicity;

	    /* Update the weighted hydrophobicity: */
	    weighted += hydrophobicity * weightA[windowI];
	    }

	/* Store the absolute value of weighted hydrophobicity: */
	abs_value = fabs (weighted);
	*(weightedP + residueI) = abs_value;

	/* Check is this the minimal or the maximal */
	/* value  for this  macromolecular complex: */
	if (abs_value < min_abs_value) min_abs_value = abs_value;
	if (abs_value > max_abs_value) max_abs_value = abs_value;
	}

    /* Prepare and check two auxiliary parameters required for color mixing: */
    range = max_abs_value - min_abs_value;
    if (range <= 0.0) continue;
    inverse_range = 1.0 / range;                 /* The first parameter */
    delta_range = range / 5.0;
    inverse_delta_range = 1.0 / delta_range;     /* The second parameter */

    /* Scan the current macromolecular complex again, residue by residue: */
    for (residueI = 0; residueI < residuesN; residueI++)
	{
	/* Pointer to the current residue: */
	curr_residueSP = curr_mol_complexSP->residueSP + residueI;

	/* The indices of the first  and the */
	/* last atom of the current residue: */
	first_atomI = curr_residueSP->residue_startI;
	last_atomI  = curr_residueSP->residue_endI;

	/* The absolute weighted hydrophobicity assigned to this residue: */
	abs_value = *(weightedP + residueI);

	/* Range index (between zero and four): */
	rangeI = (abs_value - min_abs_value) * inverse_delta_range;

	/* The scale factor, required for color mixing (the */
	/* value of scale factor must be  between 0 and 1). */
	scale_factor = (abs_value - (double) rangeI * delta_range) *
			inverse_delta_range;

	/* Scan the residue, atom by atom: */
	for (atomI = first_atomI; atomI <= last_atomI; atomI++)
	    {
	    /* Pointer to the current atom: */
	    curr_atomSP = curr_mol_complexSP->atomSP + atomI;

	    /* Mix colors: */
	    if (rangeI == 0)
		{
		MixColors_ (curr_atomSP, blue_schemeSP, cyan_schemeSP,
			    scale_factor, guiSP);
		}
	    else if (rangeI == 1)
		{
		MixColors_ (curr_atomSP, cyan_schemeSP, green_schemeSP,
			    scale_factor, guiSP);
		}
	    else if (rangeI == 2)
		{
		MixColors_ (curr_atomSP, green_schemeSP, yellow_schemeSP,
			    scale_factor, guiSP);
		}
	    else if (rangeI == 3)
		{
		MixColors_ (curr_atomSP, yellow_schemeSP, orange_schemeSP,
			    scale_factor, guiSP);
		}
	    else
		{
		MixColors_ (curr_atomSP, orange_schemeSP, red_schemeSP,
			    scale_factor, guiSP);
		}
	    }
	}

    /* Reset the position_changedF: */
    curr_mol_complexSP->position_changedF = 1;
    }

/*------free storage:--------------------------------------------------------*/

free (weightedP);

/*---------------------------------------------------------------------------*/

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

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


