/* Copyright (C) 2000 Damir Zucic */

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

				draw_ramachandran.c

Purpose:
	Draw Ramachandran plot.  This function is used if the main window
	drawing mode is equal to one.

Input:
	(1) Pointer to MolComplexS structure, with macromol. complexes.
	(2) Number of macromolecular complexes.
	(3) Pointer to RuntimeS structure, with some runtime data.
	(4) Pointer to ConfigS structure, with configuration data.
	(5) Pointer to GUIS structure, with GUI data.
	(6) Pointer to NearestAtomS structure, with information about the
	    atom occupying the given pixel.
	(7) The number of pixels in the main window free area.
	(8) The refreshI, used to check the  NearestAtomS associated with
	    a given pixel. It is currently unused in this function.

Output:
	(1) Ramachadran plot drawn to the main window.
	(2) Return value.

Return value:
	(1) The number of residues used to prepare Ramachandran plot.

Notes:
	(1) Indentation is exceptionally 4 spaces.

	(2) The initial drawing destination is the hidden pixmap, and the
	    content of this pixmap is  copied  later to  the main window.

	(3) The second index of indexAA is treated as row index.  This is
	    somewhat unusual, but more practical in this function.

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

#include <stdio.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		RefreshPixmap_ (Display *, Pixmap, GC,
				unsigned int, unsigned int, unsigned long);
void		RamaFrame_ (GUIS *);
int		ParseColor_ (RGBS *, unsigned long *, GUIS *, char *, char *);
int		DrawTitles_ (RuntimeS *, GUIS *);

/*======draw Ramachandran plot:==============================================*/

size_t DrawRamachandran_ (MolComplexS *mol_complexSP, int mol_complexesN,
			  RuntimeS *runtimeSP, ConfigS *configSP, GUIS *guiSP,
			  NearestAtomS *nearest_atomSP, size_t pixelsN,
			  unsigned int refreshI)
{
size_t		residues_drawnN = 0;
int		free_width, free_height;
int		frame_screen_x0, frame_screen_y0;
int		frame_screen_x1, frame_screen_y1;
int		frame_screen_width, frame_screen_height;
double		scale_x, scale_y;
RGBS		rgbS;
unsigned long	symbol_color1ID, symbol_color2ID, symbol_color3ID;
int		mol_complexI;
MolComplexS	*curr_mol_complexSP;
size_t		residuesN, residueI;
ResidueS	*curr_residueSP;
AtomS		*first_atomSP;
double		delta_x, delta_y, phi, psi;
int		screen_phi, screen_psi;
int		i, j, screen_x, screen_y;
static int	circle_maskAA[9][9] =  {{0, 0, 0, 1, 1, 1, 0, 0, 0},
					{0, 1, 1, 1, 1, 1, 1, 1, 0},
					{0, 1, 1, 1, 1, 1, 1, 1, 0},
					{1, 1, 1, 1, 1, 1, 1, 1, 1},
		/* Be  sure  to */	{1, 1, 1, 1, 1, 1, 1, 1, 1},
		/* read Note 3! */	{1, 1, 1, 1, 1, 1, 1, 1, 1},
					{0, 1, 1, 1, 1, 1, 1, 1, 0},
					{0, 1, 1, 1, 1, 1, 1, 1, 0},
					{0, 0, 0, 1, 1, 1, 0, 0, 0}};
size_t		pixelI;
NearestAtomS	*curr_pixelSP;
static int	indexAA[9][9] =        {{0, 0, 0, 2, 2, 2, 0, 0, 0},
					{0, 2, 0, 0, 1, 1, 2, 2, 0},
					{0, 0, 0, 0, 0, 1, 1, 2, 0},
					{2, 0, 0, 0, 0, 1, 1, 2, 2},
		/* Be  sure  to */	{2, 1, 0, 0, 1, 1, 1, 2, 2},
		/* read Note 3! */	{2, 1, 1, 1, 1, 1, 1, 2, 2},
					{0, 2, 1, 1, 1, 1, 2, 2, 0},
					{0, 2, 2, 2, 2, 2, 2, 2, 0},
					{0, 0, 0, 2, 2, 2, 0, 0, 0}};
int		cis_transF;

/*------refresh hidden pixmap:-----------------------------------------------*/

/* Refresh the hidden pixmap, where drawing will be done: */
RefreshPixmap_ (guiSP->displaySP,
		guiSP->main_hidden_pixmapID,
		guiSP->theGCA[0],
		guiSP->control_winS.x0, guiSP->input_winS.y0,
		guiSP->main_winS.bg_colorID);

/*------draw frame:----------------------------------------------------------*/

/* Draw frame, including labels: */
RamaFrame_ (guiSP);

/*------prepare geometric parameters:----------------------------------------*/

/* Prepare screen parameters: */
free_width  = (int) guiSP->main_win_free_area_width;
free_height = (int) guiSP->main_win_free_area_height;
frame_screen_x0 = guiSP->main_winS.text_line_height + 2;
frame_screen_y0 = frame_screen_x0;
frame_screen_x1 = free_width - frame_screen_x0;
frame_screen_y1 = free_height - frame_screen_y0;
frame_screen_width  = frame_screen_x1 - frame_screen_x0 + 1;
frame_screen_height = frame_screen_y1 - frame_screen_y0 + 1;

/* Prepare scale factors: */
scale_x = (double) frame_screen_width  / 6.2831853;
scale_y = (double) frame_screen_height / 6.2831853;

/*------draw trans residues:-------------------------------------------------*/

/* Prepare three colors: */
ParseColor_ (&rgbS, &symbol_color1ID, guiSP, "RGB:8888/DDDD/FFFF", "white");
ParseColor_ (&rgbS, &symbol_color2ID, guiSP, "RGB:0000/8888/FFFF", "white");
ParseColor_ (&rgbS, &symbol_color3ID, guiSP, "RGB:0000/4444/8888", "black");
XSetForeground (guiSP->displaySP, guiSP->theGCA[0], symbol_color1ID);
XSetForeground (guiSP->displaySP, guiSP->theGCA[1], symbol_color2ID);
XSetForeground (guiSP->displaySP, guiSP->theGCA[2], symbol_color3ID);

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

    /* Check are there any atoms: */
    if (curr_mol_complexSP->atomsN == 0) continue;

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

    /* Scan all residues: */
    residuesN = curr_mol_complexSP->residuesN;
    for (residueI = 0; residueI < residuesN; residueI++)
	{
	/* Pointer to the current residue: */
	curr_residueSP = curr_mol_complexSP->residueSP + residueI;

	/* If only selected residues should be visible: */
	if (runtimeSP->rama_selectionF)
	    {
	    /* Pointer to the first atom of this residue: */
	    first_atomSP = curr_mol_complexSP->atomSP +
			   curr_residueSP->residue_startI;

	    /* Check the selection flag: */
	    if (first_atomSP->selectedF == 0) continue;
	    }

	/* Extract dihedral angles: */
	phi = curr_residueSP->phi;
	psi = curr_residueSP->psi;

	/* Check angles; both should be in the range (-180, 180): */
	if (phi < -180) continue;
	if (phi >  180) continue;
	if (psi < -180) continue;
	if (psi >  180) continue;

	/* Project phi and psi: */
	delta_x = scale_x * (phi + 3.1415927);
	delta_y = scale_y * (psi + 3.1415927);
	screen_phi = frame_screen_x0 + (int) delta_x;
	screen_psi = frame_screen_y1 - (int) delta_y;

	/* Check cis-trans flag; draw only trans residues in this step: */
	cis_transF = (int) curr_residueSP->cis_transF;
	if (cis_transF != 1) continue;

	/* Draw symbol: */

	/* Horizontal scan of the neighbourhood: */
	for (i = 0; i < 9; i++)
	    {
	    /* Vertical scan of the neighbourhood: */
	    for (j = 0; j < 9; j++)
		{
		/* Current pixel coordinates: */
		screen_x = screen_phi + i - 4;
		screen_y = screen_psi + j - 4;

		/* Check the circle mask: */
		if (circle_maskAA[j][i] == 0) continue;

		/* Prepare index  to the array */
		/* of NearestAtomS structures: */
		pixelI = guiSP->main_win_free_area_width * screen_y + screen_x;

		/* Check the pixel index: */
		if (pixelI >= pixelsN) continue;

		/* Draw the pixel: */
		XDrawPoint (guiSP->displaySP,
			    guiSP->main_hidden_pixmapID,
			    guiSP->theGCA[indexAA[j][i]],
			    screen_x, screen_y);

		/* Pointer to  NearestAtomS struct. */
		/* assigned to current coordinates: */
		curr_pixelSP = nearest_atomSP + pixelI;

		/* Refresh the content of NearestAtomS */
		/* array  associated  with this pixel: */
		curr_pixelSP->last_refreshI = refreshI;
		curr_pixelSP->mol_complexI = mol_complexI;
		curr_pixelSP->atomI = curr_residueSP->residue_startI;
		}
	    }

	/* Increase count of residues: */
	residues_drawnN++;
	}
    }

/* Add symbol for trans residues to the legend: */

/* Position of symbol center: */
screen_phi = frame_screen_x0;
screen_psi = frame_screen_y1 + guiSP->main_winS.text_line_height -
	     guiSP->main_winS.text_line_height / 5 - 5;

/* Horizontal scan of the neighbourhood: */
for (i = 0; i < 9; i++)
    {
    /* Vertical scan of the neighbourhood: */
    for (j = 0; j < 9; j++)
	{
	/* Current pixel coordinates: */
	screen_x = screen_phi + i - 4;
	screen_y = screen_psi + j - 4;

	/* Check the circle mask: */
	if (circle_maskAA[j][i] == 0) continue;

	/* Draw the pixel: */
	XDrawPoint (guiSP->displaySP,
		    guiSP->main_hidden_pixmapID,
		    guiSP->theGCA[indexAA[j][i]],
		    screen_x, screen_y);
	}
    }

/*------draw cis residues:---------------------------------------------------*/

/* Prepare three colors: */
ParseColor_ (&rgbS, &symbol_color1ID, guiSP, "RGB:FFFF/9999/FFFF", "white");
ParseColor_ (&rgbS, &symbol_color2ID, guiSP, "RGB:FFFF/0000/FFFF", "white");
ParseColor_ (&rgbS, &symbol_color3ID, guiSP, "RGB:8888/0000/8888", "black");
XSetForeground (guiSP->displaySP, guiSP->theGCA[0], symbol_color1ID);
XSetForeground (guiSP->displaySP, guiSP->theGCA[1], symbol_color2ID);
XSetForeground (guiSP->displaySP, guiSP->theGCA[2], symbol_color3ID);

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

    /* Check are there any atoms: */
    if (curr_mol_complexSP->atomsN == 0) continue;

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

    /* Scan all residues: */
    residuesN = curr_mol_complexSP->residuesN;
    for (residueI = 0; residueI < residuesN; residueI++)
	{
	/* Pointer to the current residue: */
	curr_residueSP = curr_mol_complexSP->residueSP + residueI;

	/* If only selected residues should be visible: */
	if (runtimeSP->rama_selectionF)
	    {
	    /* Pointer to the first atom of this residue: */
	    first_atomSP = curr_mol_complexSP->atomSP +
			   curr_residueSP->residue_startI;

	    /* Check the selection flag: */
	    if (first_atomSP->selectedF == 0) continue;
	    }

	/* Extract dihedral angles: */
	phi = curr_residueSP->phi;
	psi = curr_residueSP->psi;

	/* Check angles; both should be in the range (-180, 180): */
	if (phi < -180) continue;
	if (phi >  180) continue;
	if (psi < -180) continue;
	if (psi >  180) continue;

	/* Project phi and psi: */
	delta_x = scale_x * (phi + 3.1415927);
	delta_y = scale_y * (psi + 3.1415927);
	screen_phi = frame_screen_x0 + (int) delta_x;
	screen_psi = frame_screen_y1 - (int) delta_y;

	/* Check cis-trans flag; draw only cis residues in this step: */
	cis_transF = (int) curr_residueSP->cis_transF;
	if (cis_transF != 2) continue;

	/* Draw symbol: */

	/* Horizontal scan of the neighbourhood: */
	for (i = 0; i < 9; i++)
	    {
	    /* Vertical scan of the neighbourhood: */
	    for (j = 0; j < 9; j++)
		{
		/* Current pixel coordinates: */
		screen_x = screen_phi + i - 4;
		screen_y = screen_psi + j - 4;

		/* Check the circle mask: */
		if (circle_maskAA[j][i] == 0) continue;

		/* Prepare index  to the array */
		/* of NearestAtomS structures: */
		pixelI = guiSP->main_win_free_area_width * screen_y + screen_x;

		/* Check the pixel index: */
		if (pixelI >= pixelsN) continue;

		/* Draw the pixel: */
		XDrawPoint (guiSP->displaySP,
			    guiSP->main_hidden_pixmapID,
			    guiSP->theGCA[indexAA[j][i]],
			    screen_x, screen_y);

		/* Pointer to  NearestAtomS struct. */
		/* assigned to current coordinates: */
		curr_pixelSP = nearest_atomSP + pixelI;

		/* Refresh the content of NearestAtomS */
		/* array  associated  with this pixel: */
		curr_pixelSP->last_refreshI = refreshI;
		curr_pixelSP->mol_complexI = mol_complexI;
		curr_pixelSP->atomI = curr_residueSP->residue_startI;
		}
	    }

	/* Increase count of residues: */
	residues_drawnN++;
	}
    }

/* Add symbol for cis residues to the legend: */

/* Position of symbol center: */
screen_phi = frame_screen_x0 + (frame_screen_x1 - frame_screen_x0) / 4;
screen_psi = frame_screen_y1 + guiSP->main_winS.text_line_height -
	     guiSP->main_winS.text_line_height / 5 - 5;

/* Horizontal scan of the neighbourhood: */
for (i = 0; i < 9; i++)
    {
    /* Vertical scan of the neighbourhood: */
    for (j = 0; j < 9; j++)
	{
	/* Current pixel coordinates: */
	screen_x = screen_phi + i - 4;
	screen_y = screen_psi + j - 4;

	/* Check the circle mask: */
	if (circle_maskAA[j][i] == 0) continue;

	/* Draw the pixel: */
	XDrawPoint (guiSP->displaySP,
		    guiSP->main_hidden_pixmapID,
		    guiSP->theGCA[indexAA[j][i]],
		    screen_x, screen_y);
	}
    }

/*------draw bad residues:---------------------------------------------------*/

/* Prepare three colors: */
ParseColor_ (&rgbS, &symbol_color1ID, guiSP, "RGB:FFFF/8888/8888", "white");
ParseColor_ (&rgbS, &symbol_color2ID, guiSP, "RGB:FFFF/0000/0000", "white");
ParseColor_ (&rgbS, &symbol_color3ID, guiSP, "RGB:8888/0000/0000", "black");
XSetForeground (guiSP->displaySP, guiSP->theGCA[0], symbol_color1ID);
XSetForeground (guiSP->displaySP, guiSP->theGCA[1], symbol_color2ID);
XSetForeground (guiSP->displaySP, guiSP->theGCA[2], symbol_color3ID);

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

    /* Check are there any atoms: */
    if (curr_mol_complexSP->atomsN == 0) continue;

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

    /* Scan all residues: */
    residuesN = curr_mol_complexSP->residuesN;
    for (residueI = 0; residueI < residuesN; residueI++)
	{
	/* Pointer to the current residue: */
	curr_residueSP = curr_mol_complexSP->residueSP + residueI;

	/* If only selected residues should be visible: */
	if (runtimeSP->rama_selectionF)
	    {
	    /* Pointer to the first atom of this residue: */
	    first_atomSP = curr_mol_complexSP->atomSP +
			   curr_residueSP->residue_startI;

	    /* Check the selection flag: */
	    if (first_atomSP->selectedF == 0) continue;
	    }

	/* Extract dihedral angles: */
	phi = curr_residueSP->phi;
	psi = curr_residueSP->psi;

	/* Check angles; both should be in the range (-180, 180): */
	if (phi < -180) continue;
	if (phi >  180) continue;
	if (psi < -180) continue;
	if (psi >  180) continue;

	/* Project phi and psi: */
	delta_x = scale_x * (phi + 3.1415927);
	delta_y = scale_y * (psi + 3.1415927);
	screen_phi = frame_screen_x0 + (int) delta_x;
	screen_psi = frame_screen_y1 - (int) delta_y;

	/* Check cis-trans flag; draw only bad residues in this step: */
	cis_transF = (int) curr_residueSP->cis_transF;
	if (cis_transF != 0) continue;

	/* Draw symbol: */

	/* Horizontal scan of the neighbourhood: */
	for (i = 0; i < 9; i++)
	    {
	    /* Vertical scan of the neighbourhood: */
	    for (j = 0; j < 9; j++)
		{
		/* Current pixel coordinates: */
		screen_x = screen_phi + i - 4;
		screen_y = screen_psi + j - 4;

		/* Check the circle mask: */
		if (circle_maskAA[j][i] == 0) continue;

		/* Prepare index  to the array */
		/* of NearestAtomS structures: */
		pixelI = guiSP->main_win_free_area_width * screen_y + screen_x;

		/* Check the pixel index: */
		if (pixelI >= pixelsN) continue;

		/* Draw the pixel: */
		XDrawPoint (guiSP->displaySP,
			    guiSP->main_hidden_pixmapID,
			    guiSP->theGCA[indexAA[j][i]],
			    screen_x, screen_y);

		/* Pointer to  NearestAtomS struct. */
		/* assigned to current coordinates: */
		curr_pixelSP = nearest_atomSP + pixelI;

		/* Refresh the content of NearestAtomS */
		/* array  associated  with this pixel: */
		curr_pixelSP->last_refreshI = refreshI;
		curr_pixelSP->mol_complexI = mol_complexI;
		curr_pixelSP->atomI = curr_residueSP->residue_startI;
		}
	    }

	/* Increase count of residues: */
	residues_drawnN++;
	}
    }

/* Add symbol for bad residues to the legend: */

/* Position of symbol center: */
screen_phi = frame_screen_x0 + 2 * (frame_screen_x1 - frame_screen_x0) / 4;
screen_psi = frame_screen_y1 + guiSP->main_winS.text_line_height -
	     guiSP->main_winS.text_line_height / 5 - 5;

/* Horizontal scan of the neighbourhood: */
for (i = 0; i < 9; i++)
    {
    /* Vertical scan of the neighbourhood: */
    for (j = 0; j < 9; j++)
	{
	/* Current pixel coordinates: */
	screen_x = screen_phi + i - 4;
	screen_y = screen_psi + j - 4;

	/* Check the circle mask: */
	if (circle_maskAA[j][i] == 0) continue;

	/* Draw the pixel: */
	XDrawPoint (guiSP->displaySP,
		    guiSP->main_hidden_pixmapID,
		    guiSP->theGCA[indexAA[j][i]],
		    screen_x, screen_y);
	}
    }

/*------draw titles:---------------------------------------------------------*/

DrawTitles_ (runtimeSP, guiSP);

/*------copy hidden pixmap to the main window:-------------------------------*/

XCopyArea (guiSP->displaySP,
	   guiSP->main_hidden_pixmapID, guiSP->main_winS.ID,
	   guiSP->theGCA[0],
	   0, 0,
	   guiSP->main_win_free_area_width, guiSP->main_win_free_area_height,
	   0, 0);

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

return residues_drawnN;
}

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


