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

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

			    color_schemes.c

Purpose:
	This function handles the simple color schemes. The first call to
	this function prepares color specifications.  Later calls to this
	function may be used to:
	- Assign required color scheme to selected atoms.
	- Define default color scheme for molecular surfaces.
	- Assign required color scheme to the active surface.
	The active surface belongs to default macromolecular complex. The
	index of the active surface is kept in RuntimeS structure.

Input:
	(1) Pointer to MolComplexS structure, with macromol. complexes.
	(2) Number of macromolecular complexes.
	(3) Pointer to  ConfigS,  where surface colors  will be stored on
	    request (if mode index is equal to one).
	(4) Pointer to GUIS structure, with GUI data.
	(5) Color scheme name.
	(6) The mode index:
	    0 = assign colors to atoms.
	    1 = initialize default colors for the outer side of molecular
		surfaces. The colors should be stored to ConfigS.
	    2 = initialize default colors for the inner side of molecular
		surfaces. The colors should be stored to ConfigS.
	    3 = set  the outer  surface colors  for the active surface of
		default macromolecular complexes.
	    4 = set  the inner  surface colors  for the active surface of
		default macromolecular complexes.

Output:
	(1) Return value.

Return value:
	(1) Positive on success.
	(2) Zero, if this function is called for the first time.
	(2) Negative on failure (scheme not recognized).

Notes:
	(1) Simple color schemes are hard-coded in the program.

	(2) The active surface index is stored to RuntimeS structure.

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

#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		InitializeColors_ (ColorSchemeS *, GUIS *);
int		CPK_ (MolComplexS *, int, GUIS *, ColorSchemeS *);
int		Zebra_ (MolComplexS *, int, GUIS *, ColorSchemeS *);
int		Chain_ (MolComplexS *, int, GUIS *, ColorSchemeS *);
int		ColorHyphob_ (MolComplexS *, int, GUIS *, ColorSchemeS *);
int		ColorModel_ (MolComplexS *, int, GUIS *, ColorSchemeS *);
int		ColorSize_ (MolComplexS *, int, GUIS *, ColorSchemeS *);
int		ColorWeighted_ (MolComplexS *, int, GUIS *, ColorSchemeS *);

/*======simple color schemes:================================================*/

int ColorSchemes_ (MolComplexS *mol_complexSP, int mol_complexesN,
		   ConfigS *configSP,
		   GUIS *guiSP, char *scheme_nameP, int modeI)
{
static int		called_beforeF;
static ColorSchemeS	color_schemeSA[COLORSCHEMES];
static char		scheme_nameAA[COLORSCHEMES][SHORTSTRINGSIZE] =
				{"RED", "GREEN", "BLUE",
				 "YELLOW", "CYAN", "MAGENTA",
				 "WHITE", "YELLOW-GREEN", "CYAN-GREEN",
				 "CYAN-BLUE", "MAGENTA-BLUE", "MAGENTA-RED",
				 "ORANGE", "HOT", "COLD",
				 "MONOCHROME", "CPK", "ZEBRA",
				 "CHAIN", "HYPHOB", "MODEL",
				 "ORANGE-YELLOW", "ORANGE-RED", "SKIN",
				 "SIZE", "WEIGHTED"};
int			schemeI = -1;
ColorSchemeS		*color_schemeSP;
int			i;
int			surfaceI, surfacesN;
int			mol_complexI;
MolComplexS		*curr_mol_complexSP;
size_t			atomsN, atomI;
AtomS			*curr_atomSP;
size_t			rgb_struct_size;

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

/* If this function is called for the first time, initialize colors: */
if (called_beforeF == 0)
	{
	InitializeColors_ (color_schemeSA, guiSP);
	called_beforeF = 1;
	return 0;
	}

/* Recognize the scheme name: */
for (i = 0; i < COLORSCHEMES; i++)
	{
	if (strcmp (scheme_nameAA[i], scheme_nameP) == 0)
		{
		schemeI = i;
		break;
		}
	}

/* If scheme name was not recognized, return negative value: */
if (schemeI == -1) return -1;

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

/* If the mode index is equal to one, initialize default */
/* colors for the outer sides of the molecular surfaces. */
if (modeI == 1)
	{
	switch (schemeI)
		{
		/* The following color schemes are suitable for surfaces: */
		case 0:		/* RED           */
		case 1:		/* GREEN         */
		case 2:		/* BLUE          */
		case 3:		/* YELLOW        */
		case 4:		/* CYAN          */
		case 5:		/* MAGENTA       */
		case 6:		/* WHITE         */
		case 7:		/* YELLOW-GREEN  */
		case 8:		/* CYAN-GREEN    */
		case 9:		/* CYAN-BLUE     */
		case 10:	/* MAGENTA-BLUE  */
		case 11:	/* MAGENTA-RED   */
		case 12:	/* ORANGE        */
		case 21:	/* ORANGE-YELLOW */
		case 22:	/* ORANGE-RED    */
		case 23:	/* SKIN          */

			/* Pointer to the color scheme: */
			color_schemeSP = color_schemeSA + schemeI;

			/* Six colors for  the outer side  of the */
			/* surface (3 near colors, 3 far colors): */
			memcpy (&configSP->out_left_near_rgbS,
				 color_schemeSP->left_rgbSA,
				 rgb_struct_size);
			memcpy (&configSP->out_middle_near_rgbS,
				 color_schemeSP->middle_rgbSA,
				 rgb_struct_size);
			memcpy (&configSP->out_right_near_rgbS,
				 color_schemeSP->right_rgbSA,
				 rgb_struct_size);
			memcpy (&configSP->out_left_far_rgbS,
				 color_schemeSP->left_rgbSA + 1,
				 rgb_struct_size);
			memcpy (&configSP->out_middle_far_rgbS,
				 color_schemeSP->middle_rgbSA + 1,
				 rgb_struct_size);
			memcpy (&configSP->out_right_far_rgbS,
				 color_schemeSP->right_rgbSA + 1,
				 rgb_struct_size);

			/* Return  the positive value after */
			/* setting the surface outer color: */
			return 1;
			break;

		/* If color scheme is not suitable for */
		/* surfaces,  return  negative  value: */
		default:
			return -2;
		}
	}

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

/* If the mode index is equal to two, initialize default */
/* colors for the inner sides of the molecular surfaces. */
if (modeI == 2)
	{
	switch (schemeI)
		{
		/* The following color schemes are suitable for surfaces: */
		case 0:		/* RED           */
		case 1:		/* GREEN         */
		case 2:		/* BLUE          */
		case 3:		/* YELLOW        */
		case 4:		/* CYAN          */
		case 5:		/* MAGENTA       */
		case 6:		/* WHITE         */
		case 7:		/* YELLOW-GREEN  */
		case 8:		/* CYAN-GREEN    */
		case 9:		/* CYAN-BLUE     */
		case 10:	/* MAGENTA-BLUE  */
		case 11:	/* MAGENTA-RED   */
		case 12:	/* ORANGE        */
		case 21:	/* ORANGE-YELLOW */
		case 22:	/* ORANGE-RED    */
		case 23:	/* SKIN          */

			/* Pointer to the color scheme: */
			color_schemeSP = color_schemeSA + schemeI;

			/* Six colors for  the inner side  of the */
			/* surface (3 near colors, 3 far colors): */
			memcpy (&configSP->in_left_near_rgbS,
				 color_schemeSP->left_rgbSA,
				 rgb_struct_size);
			memcpy (&configSP->in_middle_near_rgbS,
				 color_schemeSP->middle_rgbSA,
				 rgb_struct_size);
			memcpy (&configSP->in_right_near_rgbS,
				 color_schemeSP->right_rgbSA,
				 rgb_struct_size);
			memcpy (&configSP->in_left_far_rgbS,
				 color_schemeSP->left_rgbSA + 1,
				 rgb_struct_size);
			memcpy (&configSP->in_middle_far_rgbS,
				 color_schemeSP->middle_rgbSA + 1,
				 rgb_struct_size);
			memcpy (&configSP->in_right_far_rgbS,
				 color_schemeSP->right_rgbSA + 1,
				 rgb_struct_size);

			/* Return  the positive value after */
			/* setting the surface inner color: */
			return 2;
			break;

		/* If color scheme is not suitable for */
		/* surfaces,  return  negative  value: */
		default:
			return -3;
		}
	}

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

/* If this point is reached, the mode index is zero; assign colors to atoms! */

/*......CPK:.................................................................*/

if (schemeI == 16)
	{
	return CPK_ (mol_complexSP, mol_complexesN, guiSP, color_schemeSA);
	}

/*......ZEBRA:...............................................................*/

else if (schemeI == 17)
	{
	return Zebra_ (mol_complexSP, mol_complexesN, guiSP, color_schemeSA);
	}

/*......CHAIN:...............................................................*/

else if (schemeI == 18)
	{
	return Chain_ (mol_complexSP, mol_complexesN, guiSP, color_schemeSA);
	}

/*......HYPHOB:..............................................................*/

else if (schemeI == 19)
	{
	return ColorHyphob_ (mol_complexSP, mol_complexesN,
			     guiSP, color_schemeSA);
	}

/*......MODEL:...............................................................*/

else if (schemeI == 20)
	{
	return ColorModel_ (mol_complexSP, mol_complexesN,
			    guiSP, color_schemeSA);
	}

/*......SIZE:...............................................................*/

else if (schemeI == 24)
	{
	return ColorSize_ (mol_complexSP, mol_complexesN,
			   guiSP, color_schemeSA);
	}

/*......WEIGHTED:............................................................*/

else if (schemeI == 25)
	{
	return ColorWeighted_ (mol_complexSP, mol_complexesN,
			       guiSP, color_schemeSA);
	}

/*......other schemes:.......................................................*/

/* The number of color surfaces: */
surfacesN = color_schemeSA[schemeI].surfacesN;

/* Pointer to the color scheme: */
color_schemeSP = color_schemeSA + schemeI;

/* 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;

	/* Number of atoms in a macromolecular complex: */
	atomsN = curr_mol_complexSP->atomsN;

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

		/* Check is atom selected: */
		if (curr_atomSP->selectedF == 0) continue;

		/* Set the number of color surfaces: */
		curr_atomSP->surfacesN = surfacesN;

		/* Copy the color specifications: */
		for (surfaceI = 0; surfaceI < surfacesN; surfaceI++)
			{
			/* Left color: */
			memcpy (curr_atomSP->left_rgbSA + surfaceI,
				color_schemeSP->left_rgbSA + surfaceI,
				rgb_struct_size);

			/* Middle color: */
			memcpy (curr_atomSP->middle_rgbSA + surfaceI,
				color_schemeSP->middle_rgbSA + surfaceI,
				rgb_struct_size);

			/* Right color: */
			memcpy (curr_atomSP->right_rgbSA + surfaceI,
				color_schemeSP->right_rgbSA + surfaceI,
				rgb_struct_size);
			}
		}

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

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

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

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


