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

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

				read_config.c

Purpose:
	Read configuration data.  Configuration file is .garlicrc and up to
	six directories are  searched for this file.  The only exception is
	/etc directory: if the configuration file is stored there it should
	be called  garlicrc  (without the leading period).  If all attempts
	fail, default (hard-coded) parameters are used.

Input:
	(1) Pointer to  ConfigS structure,  where some data will be stored.

Output:
	(1) Some data stored to ConfigS structure.
	(2) Return value.

Return value:
	(1) Positive if configuration read from file.
	(2) Zero if default values used for initialization.

Notes:
	(1) This function is quite fast:  on a 233 MHz Pentium MMX, it will
	    take few milliseconds to execute. Therefore do not be surprised
	    that if's are not optimized here.

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

#include <stdio.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:=================================================*/

FILE		*OpenConfigFile_ (void);
int		ExtractInteger_ (char *);
int		ExtractTwoIntegers_ (int *, int *, char *);
int		ExtractPhrase_ (char *, char *);
double		ExtractDouble_ (char *);
int		ExtractTwoDoubles_ (double *, double *, char *);
int		ExtractIndex_ (char *);
int		ExtractRotationSteps_ (ConfigS *, char *);
int		ExtractTranslationSteps_ (ConfigS *, char *);
int		ExtractSlabSteps_ (ConfigS *, char *);
int		ExtractFadingSteps_ (ConfigS *, char *);

/*======read configuration data (.garlicrc file):============================*/

int ReadConfig_ (ConfigS *configSP)
{
FILE		*fileP;
char		s[STRINGSIZE];
int		line_size;
char		phraseA[SHORTSTRINGSIZE];
int		n, n1, n2;
double		d, d1, d2;
int		surfaceI;

/* Default values; used if all attempts to find .garlicrc (or garlicrc) */
/* fail or if the corresponding entry does not exist in .garlicrc file: */

/* Main window geometry: */
strcpy (configSP->geometryA, "default");

/* Font name and cursor name: */
strcpy (configSP->font_nameA, "10x20");
strcpy (configSP->cursor_nameA, "default");

/* Coordinate system in the top left corner is visible by default: */
configSP->show_coord_systemF = 1;

/* Control window in the top right corner is visible by default: */
configSP->show_control_windowF = 1;

/* The sequence neighborhood of the residue under */
/* the pointer is visible and verbose by default: */
configSP->show_sequence_neighborhoodF = 2;

/* Stereo flag (default is mono): */
configSP->stereoF = 0;

/* Light source theta angle (with respect to z): */
configSP->light_theta = 150.0 * DEG_TO_RAD;

/* Light source phi angle (with respect to x): */
configSP->light_phi = 225.0 * DEG_TO_RAD;

/* Window colors: */
strcpy (configSP->bg_colorA, "black");
strcpy (configSP->fg_colorA, "white");
strcpy (configSP->text_bg_colorA, "black");
strcpy (configSP->text_fg_colorA, "white");

/* Slab mode index (default is planar): */
configSP->default_slab_modeI = 1;

/* Color fading mode index (default is planar): */
configSP->default_fading_modeI = 1;

/* Default number of color fading surfaces (up to MAXCOLORSURFACES): */
configSP->default_surfacesN = 3;

/* Default colors for atoms and bonds: */
strcpy (configSP->left_colorAA[0],   "RGB:FFFF/FFFF/0000");
strcpy (configSP->middle_colorAA[0], "RGB:FFFF/AAAA/0000");
strcpy (configSP->right_colorAA[0],  "RGB:FFFF/5555/0000");
strcpy (configSP->left_colorAA[1],   "RGB:FFFF/8888/0000");
strcpy (configSP->middle_colorAA[1], "RGB:FFFF/0000/0000");
strcpy (configSP->right_colorAA[1],  "RGB:AAAA/0000/0000");
strcpy (configSP->left_colorAA[2],   "RGB:7777/0000/0000");
strcpy (configSP->middle_colorAA[2], "RGB:5555/0000/0000");
strcpy (configSP->right_colorAA[2],  "RGB:4444/0000/0000");
for (n = 3; n < MAXCOLORSURFACES; n++)
	{
	strcpy (configSP->left_colorAA[n], "white");
	strcpy (configSP->middle_colorAA[n], "gray");
	strcpy (configSP->right_colorAA[n], "DarkGray");
	}

/* Default color schemes for surfaces: */
strcpy (configSP->surface_outer_color_schemeA, "magenta");
strcpy (configSP->surface_inner_color_schemeA, "blue");

/* Drawing styles for atoms, bonds and backbone: */
configSP->default_atom_styleI = 2;
configSP->default_bond_styleI = 3;
configSP->default_backbone_styleI = 5;

/* Bond lengths (angstroms): */
configSP->max_bond_length = 2.3;
configSP->C_C_bond_length_min = 1.40;
configSP->C_C_bond_length_max = 1.70;
configSP->C_N_bond_length_min = 1.10;
configSP->C_N_bond_length_max = 1.60;
configSP->C_O_bond_length_min = 1.10;
configSP->C_O_bond_length_max = 1.40;
configSP->C_S_bond_length_min = 1.60;
configSP->C_S_bond_length_max = 2.00;
configSP->C_H_bond_length_min = 0.80;
configSP->C_H_bond_length_max = 1.20;
configSP->N_O_bond_length_min = 1.20;
configSP->N_O_bond_length_max = 1.70;
configSP->N_H_bond_length_min = 0.90;
configSP->N_H_bond_length_max = 1.30;
configSP->O_H_bond_length_min = 0.70;
configSP->O_H_bond_length_max = 1.30;
configSP->S_H_bond_length_min = 0.90;
configSP->S_H_bond_length_max = 1.60;
configSP->O_P_bond_length_min = 1.20;
configSP->O_P_bond_length_max = 1.80;
configSP->S_S_bond_length_min = 1.80;
configSP->S_S_bond_length_max = 2.30;
configSP->generic_bond_length_min = 0.8;
configSP->generic_bond_length_max = 2.0;
configSP->hydro_bond_length_min = 2.0;
configSP->hydro_bond_length_max = 5.0;

/* These two bond parameters are obsolete since version 1.3: */
configSP->hydro_bond_angle_min = (double) 125 * DEG_TO_RAD;
configSP->hydro_bond_angle_max = (double) 180 * DEG_TO_RAD;

/* The maximal CA_CA distance for two neighbouring residues (angstroms): */
configSP->CA_CA_dist_max = 4.1;

/* Atomic radii (in angstroms): */
configSP->H_radius =       0.70;
configSP->C_radius =       1.20;
configSP->N_radius =       1.05;
configSP->O_radius =       1.00;
configSP->S_radius =       1.25;
configSP->P_radius =       1.25;
configSP->generic_radius = 1.40;

/* Atomic covalent radii (in angstroms): */
configSP->H_covalent_radius =       0.70;
configSP->C_covalent_radius =       1.20;
configSP->N_covalent_radius =       1.05;
configSP->O_covalent_radius =       1.00;
configSP->S_covalent_radius =       1.25;
configSP->P_covalent_radius =       1.25;
configSP->generic_covalent_radius = 1.40;

/* Atomic small radii (in angstroms): */
configSP->H_small_radius =       0.21;
configSP->C_small_radius =       0.54;
configSP->N_small_radius =       0.49;
configSP->O_small_radius =       0.46;
configSP->S_small_radius =       0.73;
configSP->P_small_radius =       0.77;
configSP->generic_small_radius = 0.84;

/* van der Waals radii (in angstroms): */
configSP->H_van_der_Waals_radius       = 1.00;
configSP->C_van_der_Waals_radius       = 1.70;
configSP->N_van_der_Waals_radius       = 1.50;
configSP->O_van_der_Waals_radius       = 1.40;
configSP->S_van_der_Waals_radius       = 1.80;
configSP->P_van_der_Waals_radius       = 1.80;
configSP->generic_van_der_Waals_radius = 2.00;

/* Default ball radius (used to draw atoms as balls of equal size): */
configSP->default_ball_radius = 0.40;

/* Default bond probe radius (used to draw nice bonds with curved surfaces): */
configSP->default_bond_probe_radius = 0.80;

/* Default stick radius (used to draw bonds as sticks): */
configSP->default_stick_radius = 0.15;

/* Number of neighbors to be checked as bond candidates: */
configSP->bond_candidates_backward = 50;
configSP->bond_candidates_forward  = 50; 

/* Geometric parameters: */
configSP->main_margin_left = 30;
configSP->main_margin_right = 30;
configSP->main_margin_top = 60;
configSP->main_margin_bottom = 30;
configSP->max_main_win_width  = MAXWINWIDTH;
configSP->max_main_win_height = MAXWINHEIGHT;
configSP->nearest_line_thickness = MAXLINES;
configSP->screen_real_width = SCREEN_REAL_WX;
configSP->screen_real_height = SCREEN_REAL_WY;
configSP->user_screen_real_distance = USER_SCREEN_REAL_DIST;
configSP->screen_atomic_width = SCREEN_ATOMIC_WX;
configSP->user_atomic_position = USER_ATOMIC_Z;
configSP->stereo_screen_margin = STEREO_MARGIN;
configSP->stereo_angle = STEREO_ANGLE * DEG_TO_RAD;
configSP->rotation_stepA[0] = 0.2 * DEG_TO_RAD;
configSP->rotation_stepA[1] = 1.0 * DEG_TO_RAD;
configSP->rotation_stepA[2] = 5.0 * DEG_TO_RAD;
configSP->rotation_stepA[3] = 30.0 * DEG_TO_RAD;
configSP->rotation_stepA[4] = 90.0 * DEG_TO_RAD;
configSP->translation_stepA[0] =   0.2;
configSP->translation_stepA[1] =   1.0;
configSP->translation_stepA[2] =   5.0;
configSP->translation_stepA[3] =  25.0;
configSP->translation_stepA[4] = 100.0;
configSP->slab_stepA[0] =  0.2;
configSP->slab_stepA[1] =  1.0;
configSP->slab_stepA[2] =  5.0;
configSP->slab_stepA[3] = 20.0;
configSP->slab_stepA[4] = 80.0;
configSP->fading_stepA[0] =  0.2;
configSP->fading_stepA[1] =  1.0;
configSP->fading_stepA[2] =  5.0;
configSP->fading_stepA[3] = 20.0;
configSP->fading_stepA[4] = 80.0;

/* Try to find the personal or public configuration file: */
if ((fileP = OpenConfigFile_ ()) == NULL) return 0;

/* If this point is reached, file is available - read and parse all lines: */
line_size = sizeof (s);
while (fgets (s, line_size, fileP))
	{
	/* Skip comments: */
	if (strstr (s, "#") == s) continue;

	/* Skip very short lines: */
	if (strlen (s) <= 5) continue;

	/* Main window geometry: */
	if (strstr (s, "main") && strstr (s, "window") &&
	    strstr (s, "geometry"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			strncpy (configSP->geometryA,
				 phraseA, SHORTSTRINGSIZE - 1);
			configSP->geometryA[SHORTSTRINGSIZE - 1] = '\0';
			}
		continue;
		}

	/* Main font name: */
	if (strstr (s, "main") && strstr (s, "font"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			strncpy (configSP->font_nameA,
				 phraseA, SHORTSTRINGSIZE - 1);
			configSP->font_nameA[SHORTSTRINGSIZE - 1] = '\0';
			}
		continue;
		}

        /* Main window cursor: */
        if (strstr (s, "main") && strstr (s, "window") && strstr (s, "cursor"))
                {
                if (ExtractPhrase_ (phraseA, s) > 0)
                        {
                        strncpy (configSP->cursor_nameA,
                                 phraseA, SHORTSTRINGSIZE - 1);
                        configSP->cursor_nameA[SHORTSTRINGSIZE - 1] = '\0';
                        }
		continue;
                }

	/* Coordinate system in the top left corner (yes or no): */
	if (strstr (s, "show") && strstr (s, "coordinate") &&
	    strstr (s, "system"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			if (strstr (phraseA, "no"))	
				{
				configSP->show_coord_systemF = 0;
				}
			}
		continue;
		}

	/* Control window in the top right corner: */
	if (strstr (s, "show") && strstr (s, "control") &&
	    strstr (s, "window"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			if (strstr (phraseA, "no"))
				{
				configSP->show_control_windowF = 0;
				}
			}
		continue;
		}

	/* Sequence neighborhood of the residue under the pointer: */
	if (strstr (s, "show") && strstr (s, "sequence") &&
	    strstr (s, "neighborhood"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			if (strstr (phraseA, "no"))
				{
				configSP->show_sequence_neighborhoodF = 0;
				}
			else if (strstr (phraseA, "yes"))
				{
				configSP->show_sequence_neighborhoodF = 1;
				}
			else if (strstr (phraseA, "verbose"))
				{
				configSP->show_sequence_neighborhoodF = 2;
				}
			}
		continue;
		}
	
	/* Stereo flag (0 = mono, 1 = stereo): */
	if (strstr (s, "display") && strstr (s, "stereo") &&
	    strstr (s, "image"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			if (strstr (phraseA, "yes")) configSP->stereoF = 1;
			}
		continue;
		}

	/* Default slab mode index (see typedefs.h for available modes): */
	if (strstr (s, "default") && strstr (s, "slab") && strstr (s, "mode"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			if (strncmp (phraseA, "off", 50) == 0)
				configSP->default_slab_modeI = 0;
			else if (strncmp (phraseA, "planar", 50) == 0)
				configSP->default_slab_modeI = 1;
			else if (strncmp (phraseA, "sphere", 50) == 0)
				configSP->default_slab_modeI = 2;
			else if (strncmp (phraseA, "half-sphere", 50) == 0)
				configSP->default_slab_modeI = 3;
			else if (strncmp (phraseA, "cylinder", 50) == 0)
				configSP->default_slab_modeI = 4;
			else if (strncmp (phraseA, "half-cylinder", 50) == 0)
				configSP->default_slab_modeI = 5;
			else configSP->default_slab_modeI = 1;    /* Default */
			}
		continue;
		}

	/* Default fading mode index (see typedefs.h for available modes): */
	if (strstr (s, "default") && strstr (s, "fading") &&
	    strstr (s, "mode"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			if (strncmp (phraseA, "off", 50) == 0)
				configSP->default_fading_modeI = 0;
			else if (strncmp (phraseA, "planar", 50) == 0)
				configSP->default_fading_modeI = 1;
			else if (strncmp (phraseA, "sphere", 50) == 0)
				configSP->default_fading_modeI = 2;
			else if (strncmp (phraseA, "half-sphere", 50) == 0)
				configSP->default_fading_modeI = 3;
			else if (strncmp (phraseA, "cylinder", 50) == 0)
				configSP->default_fading_modeI = 4;
			else if (strncmp (phraseA, "half-cylinder", 50) == 0)
				configSP->default_fading_modeI = 5;
			else configSP->default_fading_modeI = 1;  /* Default */
			}
		continue;
		}

	/* Main window left margin: */
	if (strstr (s, "main") && strstr (s, "window") &&
	    strstr (s, "left") && strstr (s, "margin"))
		{
		n = ExtractInteger_ (s);
		if (n >= 0) configSP->main_margin_left = n;
		continue;
		}

	/* Main window right margin: */
	if (strstr (s, "main") && strstr (s, "window") &&
	    strstr (s, "right") && strstr (s, "margin"))
		{
		n = ExtractInteger_ (s);
		if (n >= 0) configSP->main_margin_right = n;
		continue;
		}

	/* Main window top margin: */
	if (strstr (s, "main") && strstr (s, "window") &&
	    strstr (s, "top") && strstr (s, "margin"))
		{
		n = ExtractInteger_ (s);
		if (n >= 0) configSP->main_margin_top = n;
		continue;
		}

	/* Main window bottom margin: */
	if (strstr (s, "main") && strstr (s, "window") &&
	    strstr (s, "bottom") && strstr (s, "margin"))
		{
		n = ExtractInteger_ (s);
		if (n >= 0) configSP->main_margin_bottom = n;
		continue;
		}

	/* Background color specification: */
	if (strstr (s, "main") && strstr (s, "window") &&
	    strstr (s, "background") && strstr (s, "color"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			strncpy (configSP->bg_colorA,
				 phraseA, SHORTSTRINGSIZE - 1);
			configSP->bg_colorA[SHORTSTRINGSIZE - 1] = '\0';
			}
		continue;
		}

	/* Foreground color specification: */
	if (strstr (s, "main") && strstr (s, "window") &&
	    strstr (s, "foreground") && strstr (s, "color"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			strncpy (configSP->fg_colorA,
				 phraseA, SHORTSTRINGSIZE - 1);
			configSP->fg_colorA[SHORTSTRINGSIZE - 1] = '\0';
			}
		continue;
		}

	/* Text background color: */
	if (strstr (s, "text") && strstr (s, "background") &&
	    strstr (s, "color"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			strncpy (configSP->text_bg_colorA,
				 phraseA, SHORTSTRINGSIZE - 1);
			configSP->text_bg_colorA[SHORTSTRINGSIZE - 1] = '\0';
			}
		continue;
		}

	/* Text foreground color: */
	if (strstr (s, "text") && strstr (s, "foreground") &&
	    strstr (s, "color"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			strncpy (configSP->text_fg_colorA,
				 phraseA, SHORTSTRINGSIZE - 1);
			configSP->text_fg_colorA[SHORTSTRINGSIZE - 1] = '\0';
			}
		continue;
		}

	/* Default number of color fading surfaces: */
	if (strstr (s, "number") && strstr (s, "color") &&
	    strstr (s, "surfaces"))
		{
		n = ExtractInteger_ (s);
		if ((n > 0) && (n <= MAXCOLORSURFACES))
			{
			configSP->default_surfacesN = n;
			}
		continue;
		}

	/* Left color: */
	if (strstr (s, "left") && strstr (s, "color"))
		{
		surfaceI = ExtractIndex_ (s);
		if ((surfaceI < 0) || (surfaceI >= MAXCOLORSURFACES)) continue;
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			strncpy (configSP->left_colorAA[surfaceI],
				 phraseA, SHORTSTRINGSIZE - 1);
			n = SHORTSTRINGSIZE - 1;
			configSP->left_colorAA[surfaceI][n] = '\0';
			}
		continue;
		}

	/* Middle color: */
	if (strstr (s, "middle") && strstr (s, "color"))
		{
		surfaceI = ExtractIndex_ (s);
		if ((surfaceI < 0) || (surfaceI >= MAXCOLORSURFACES)) continue;
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			strncpy (configSP->middle_colorAA[surfaceI],
				 phraseA, SHORTSTRINGSIZE - 1);
			n = SHORTSTRINGSIZE - 1;
			configSP->middle_colorAA[surfaceI][n] = '\0';
			}
		continue;
		}

	/* Right color: */
	if (strstr (s, "right") && strstr (s, "color"))
		{
		surfaceI = ExtractIndex_ (s);
		if ((surfaceI < 0) || (surfaceI >= MAXCOLORSURFACES)) continue;
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			strncpy (configSP->right_colorAA[surfaceI],
				 phraseA, SHORTSTRINGSIZE - 1);
			n = SHORTSTRINGSIZE - 1;
			configSP->right_colorAA[surfaceI][n] = '\0';
			}
		continue;
		}

	/* Default color scheme for the outer side of molecular surfaces: */
	if (strstr (s, "surface") && strstr (s, "outer") &&
	    strstr (s, "color") && strstr (s, "scheme"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			strncpy (configSP->surface_outer_color_schemeA,
				 phraseA, SHORTSTRINGSIZE - 1);
			n = SHORTSTRINGSIZE - 1;
			configSP->surface_outer_color_schemeA[n] = '\0';
			}
		continue;
		}

	/* Default color scheme for the inner side of molecular surfaces: */
	if (strstr (s, "surface") && strstr (s, "inner") &&
	    strstr (s, "color") && strstr (s, "scheme"))
		{
		if (ExtractPhrase_ (phraseA, s) > 0)
			{
			strncpy (configSP->surface_inner_color_schemeA,
				 phraseA, SHORTSTRINGSIZE - 1);
			n = SHORTSTRINGSIZE - 1;
			configSP->surface_inner_color_schemeA[n] = '\0';
			}
		continue;
		}

	/* Default drawing style for atoms: */
	if (strstr (s, "default") && strstr (s, "atom") &&
	    strstr (s, "drawing") && strstr (s, "style"))
		{
		n = ExtractInteger_ (s);
		if ((n >= 0) && (n <= MAXATOMSTYLEI))
			{
			configSP->default_atom_styleI = n;
			}
		continue;
		}

	/* Default drawing style for bonds: */
	if (strstr (s, "default") && strstr (s, "bond") &&
	    strstr (s, "drawing") && strstr (s, "style"))
		{
		n = ExtractInteger_ (s);
		if ((n >= 0) && (n <= MAXBONDSTYLEI))
			{
			configSP->default_bond_styleI = n;
			}
		continue;
		}

	/* Default backbone drawing style: */
	if (strstr (s, "default") && strstr (s, "backbone") &&
	    strstr (s, "drawing") && strstr (s, "style"))
		{
		n = ExtractInteger_ (s);
		if ((n >= 0) && (n <= MAXBONESTYLEI))
			{
			configSP->default_backbone_styleI = n;
			}
		continue;
		}

	/* Maximal main window width: */
	if (strstr (s, "maximal") && strstr (s, "window") &&
	    strstr (s, "width"))
		{
		n = ExtractInteger_ (s);
		if (n >= 0) configSP->max_main_win_width = n;
		continue;
		}

	/* Maximal main window height: */
        if (strstr (s, "maximal") && strstr (s, "window") &&
	    strstr (s, "height"))
		{
		n = ExtractInteger_ (s);
		if (n >= 0) configSP->max_main_win_height = n;
		continue;
		}

	/* The nearest line  (i.e. the nearest bond) thickness. */
	/* Used only if line thickness is used for perspective! */
	if (strstr (s, "nearest") && strstr (s, "line") &&
	    strstr (s, "thickness"))
		{
		n = ExtractInteger_ (s);
		if (n >= 0) configSP->nearest_line_thickness = n;
		continue;
		}

	/* Screen width in real world: */
	if (strstr (s, "screen") && strstr (s, "real") && strstr (s, "width"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->screen_real_width = d;
		continue;
		}

	/* Screen height in real world: */
	if (strstr (s, "screen") && strstr (s, "real") && strstr (s, "height"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->screen_real_height = d;
		continue;
		}

	/* Distance between user and screen in real world: */
	if (strstr (s, "distance") && strstr (s, "user") &&
	    strstr (s, "screen") && strstr (s, "real"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->user_screen_real_distance = d;
		continue;
		}

	/* Screen width in atomic world: */
	if (strstr (s, "screen") && strstr (s, "width") &&
	    strstr (s, "atomic"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->screen_atomic_width = d;
		continue;
		}

	/* User z coordinate in atomic world (must be negative!): */
	if (strstr (s, "user") && strstr (s, "position") &&
	    strstr (s, "atomic"))
		{
		d = ExtractDouble_ (s);
		if (d < 0) configSP->user_atomic_position = d;  /* Negative! */
		continue;
		}

	/* Stereo internal margin (separating left and right image): */
	if (strstr (s, "stereo") && strstr (s, "internal") &&
	    strstr (s, "margin"))
		{
		n = ExtractInteger_ (s);
		if (n > 0) configSP->stereo_screen_margin = n;
		continue;
		}

	/* Stereo angle. The right image is rotated around y axis for that */
	/* angle  (right-handed rotation).  Degrees read,  radians stored: */
	if (strstr (s, "stereo") && strstr (s, "angle"))
		{
		d = ExtractDouble_ (s);
		configSP->stereo_angle = d * DEG_TO_RAD;
		continue;
		}

	/* Light source theta angle: */
	if (strstr (s, "light") && strstr (s, "source") &&
	    strstr (s, "theta") && strstr (s, "angle"))
		{
		d = ExtractDouble_ (s);
		configSP->light_theta = d * DEG_TO_RAD;
		continue;
		}

	/* Light source phi angle: */
	if (strstr (s, "light") && strstr (s, "source") &&
	    strstr (s, "phi") && strstr (s, "angle"))
		{
		d = ExtractDouble_ (s);
		configSP->light_phi = d * DEG_TO_RAD;
		continue;
		}

	/* Rotation steps (very small, small, normal, large, very large): */
	if (strstr (s, "rotation") && strstr (s, "steps"))
		{
		ExtractRotationSteps_ (configSP, s);
		continue;
		}

	/* Translation steps (very small, small, normal, large, very large): */
	if (strstr (s, "translation") && strstr (s, "steps"))
		{
		ExtractTranslationSteps_ (configSP, s);
		continue;
		}

	/* Slab steps (very small, small, normal, large, very large): */
	if (strstr (s, "slab") && strstr (s, "steps"))
		{
		ExtractSlabSteps_ (configSP, s);
		continue;
		}

	/* Fading steps (very small, small, normal, large, very large): */
	if (strstr (s, "fading") && strstr (s, "steps"))
		{
		ExtractFadingSteps_ (configSP, s);
		continue;
		}

	/* Maximal  bond length,  used to check */
	/* which atoms and bonds are invisible: */
	if (strstr (s, "maximal") && strstr (s, "bond") &&
	    strstr (s, "length"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->max_bond_length = d;
		continue;
		}

	/* Crude bond length limits for C-C bond: */
	if (strstr (s, "approx") && strstr (s, "C-C") &&
	    strstr (s, "bond") && strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->C_C_bond_length_min = d1;
				configSP->C_C_bond_length_max = d2;
				}
			}
		continue;
		}

	/* Crude bond length limits for C-N bond: */
	if (strstr (s, "approx") && strstr (s, "C-N") &&
	    strstr (s, "bond") && strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->C_N_bond_length_min = d1;
				configSP->C_N_bond_length_max = d2;
				}
			}
		continue;
		}

	/* Crude bond length limits for C-O bond: */
	if (strstr (s, "approx") && strstr (s, "C-O") &&
	    strstr (s, "bond") && strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->C_O_bond_length_min = d1;
				configSP->C_O_bond_length_max = d2;
				}
			}
		continue;
		}

	/* Crude bond length limits for C-S bond: */
	if (strstr (s, "approximate") && strstr (s, "C-S") &&
	    strstr (s, "bond") && strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->C_S_bond_length_min = d1;
				configSP->C_S_bond_length_max = d2;
				}
			}
		continue;
		}

	/* Crude bond length limits for C-H bond: */
	if (strstr (s, "approximate") && strstr (s, "C-H") &&
	    strstr (s, "bond") && strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->C_H_bond_length_min = d1;
				configSP->C_H_bond_length_max = d2;
				}
			}
		continue;
		}

	/* Crude bond length limits for N-O bond: */
	if (strstr (s, "approximate") && strstr (s, "N-O") &&
	    strstr (s, "bond") && strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->N_O_bond_length_min = d1;
				configSP->N_O_bond_length_max = d2;
				}
			}
		continue;
		}

	/* Crude bond length limits for N-H bond: */
	if (strstr (s, "approximate") && strstr (s, "N-H") &&
	    strstr (s, "bond") && strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->N_H_bond_length_min = d1;
				configSP->N_H_bond_length_max = d2;
				}
			}
		continue;
		}

	/* Crude bond length limits for O-H bond: */
	if (strstr (s, "approximate") && strstr (s, "O-H") &&
	    strstr (s, "bond") && strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->O_H_bond_length_min = d1;
				configSP->O_H_bond_length_max = d2;
				}
			}
		continue;
		}

	/* Crude bond length limits for S-H bond: */
	if (strstr (s, "approximate") && strstr (s, "S-H") &&
	    strstr (s, "bond") && strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->S_H_bond_length_min = d1;
				configSP->S_H_bond_length_max = d2;
				}
			}
		continue;
		}

	/* Crude bond length limits for O-P bond: */
	if (strstr (s, "approximate") && strstr (s, "O-P") &&
	    strstr (s, "bond") && strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->O_P_bond_length_min = d1;
				configSP->O_P_bond_length_max = d2;
				}
			}
		continue;
		}

	/* Crude bond length limits for S-S bond: */
	if (strstr (s, "approximate") && strstr (s, "S-S") &&
	    strstr (s, "bond") && strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->S_S_bond_length_min = d1;
				configSP->S_S_bond_length_max = d2;
				}
			}
		continue;
		}

        /* Bond length limits for unrecognized atomic pairs: */
        if (strstr (s, "generic") && strstr (s, "bond") &&
            strstr (s, "length"))
                {
                if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
                        {
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->generic_bond_length_min = d1;
                                configSP->generic_bond_length_max = d2;
				}
                        }
                continue;
                }

	/* Hydrogen bond length range: */
	if (strstr (s, "hydrogen") && strstr (s, "bond") &&
	    strstr (s, "length"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 > 0) && (d2 > d1))
				{
				configSP->hydro_bond_length_min = d1;
				configSP->hydro_bond_length_max = d2;
				}
			}
		continue;
		}

	/* Hydrogen bond angular range (obsolete since version 1.3!): */
	if (strstr (s, "hydrogen") && strstr (s, "bond") &&
	    strstr (s, "angle"))
		{
		if (ExtractTwoDoubles_ (&d1, &d2, s) > 0)
			{
			if ((d1 >= 0.0) && (d1 <= 180.0) &&
			    (d2 > d1) && (d2 <= 180))
				{
				configSP->hydro_bond_angle_min =
							d1 * DEG_TO_RAD;
				configSP->hydro_bond_angle_max =
							d2 * DEG_TO_RAD;
				}
			}
		continue;
		}

	/* The maximal CA-CA distance for two neighbouring residues: */
	if (strstr (s, "maximal") && strstr (s, "CA-CA") &&
	    strstr (s, "distance"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->CA_CA_dist_max = d;
		continue;
		}

	/* Radius of hydrogen atom: */
	if (strstr (s, "radius") &&  strstr (s, "hydrogen") &&
	   !strstr (s, "Waals")  && !strstr (s, "covalent") &&
	   !strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->H_radius = d;
		continue;
		}

	/* Radius of carbon atom: */
	if (strstr (s, "radius") &&  strstr (s, "carbon")   &&
	   !strstr (s, "Waals")  && !strstr (s, "covalent") &&
	   !strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->C_radius = d;
		continue;
		}

	/* Radius of nitrogen atom: */
	if (strstr (s, "radius") &&  strstr (s, "nitrogen") &&
	   !strstr (s, "Waals")  && !strstr (s, "covalent") &&
	   !strstr (s, "small")) 
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->N_radius = d;
		continue;
		}

	/* Radius of oxygen atom: */
	if (strstr (s, "radius") &&  strstr (s, "oxygen")   &&
	   !strstr (s, "Waals")  && !strstr (s, "covalent") &&
	   !strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->O_radius = d;
		continue;
		}

	/* Radius of sulfur atom: */
	if (strstr (s, "radius") &&  strstr (s, "sulfur")   &&
	   !strstr (s, "Waals")  && !strstr (s, "covalent") &&
	   !strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->S_radius = d;
		continue;
		}

	/* Radius of phosphorus atom: */
	if (strstr (s, "radius") &&  strstr (s, "phosphorus") &&
	   !strstr (s, "Waals")  && !strstr (s, "covalent")   &&
	   !strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->P_radius = d;
		continue;
		}

	/* Radius of unknown atom (generic radius): */
	if (strstr (s, "generic") &&  strstr (s, "radius")   &&
	   !strstr (s, "Waals")   && !strstr (s, "covalent") &&
	   !strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->generic_radius = d;
		continue;
		}

	/* Covalent radius of hydrogen atom: */
	if (strstr (s, "hydrogen") && strstr (s, "covalent"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->H_covalent_radius = d;
		continue;
		}

	/* Covalent radius of carbon atom: */
	if (strstr (s, "carbon") && strstr (s, "covalent"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->C_covalent_radius = d;
		continue;
		}

	/* Covalent radius of nitrogen atom: */
	if (strstr (s, "nitrogen") && strstr (s, "covalent"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->N_covalent_radius = d;
		continue;
		}

	/* Covalent radius of oxygen atom: */
	if (strstr (s, "oxygen") && strstr (s, "covalent"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->O_covalent_radius = d;
		continue;
		}

	/* Covalent radius of sulfur atom: */
	if (strstr (s, "sulfur") && strstr (s, "covalent"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->S_covalent_radius = d;
		continue;
		}

	/* Covalent radius of phosphorus atom: */
	if (strstr (s, "phosphorus") && strstr (s, "covalent"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->P_covalent_radius = d;
		continue;
		}

	/* Covalent radius of unknown atom (generic radius): */
	if (strstr (s, "generic") && strstr (s, "covalent"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->generic_covalent_radius = d;
		continue;
		}

	/* Small radius of hydrogen atom: */
	if (strstr (s, "hydrogen") && strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->H_small_radius = d;
		continue;
		}

	/* Small radius of carbon atom: */
	if (strstr (s, "carbon") && strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->C_small_radius = d;
		continue;
		}

	/* Small radius of nitrogen atom: */
	if (strstr (s, "nitrogen") && strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->N_small_radius = d;
		continue;
		}

	/* Small radius of oxygen atom: */
	if (strstr (s, "oxygen") && strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->O_small_radius = d;
		continue;
		}

	/* Small radius of sulfur atom: */
	if (strstr (s, "sulfur") && strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->S_small_radius = d;
		continue;
		}

	/* Small radius of phosphorus atom: */
	if (strstr (s, "phosphorus") && strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->P_small_radius = d;
		continue;
		}

	/* Small radius of unknown atom (generic radius): */
	if (strstr (s, "generic") && strstr (s, "small"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->generic_small_radius = d;
		continue;
		}

	/* Van der Waals radius of hydrogen: */
	if (strstr (s, "hydrogen") && strstr (s, "Waals"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->H_van_der_Waals_radius = d;
		continue;
		}

	/* Van der Waals radius of carbon: */
	if (strstr (s, "carbon") && strstr (s, "Waals"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->C_van_der_Waals_radius = d;
		continue;
		}

	/* Van der Waals radius of nitrogen: */
	if (strstr (s, "nitrogen") && strstr (s, "Waals"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->N_van_der_Waals_radius = d;
		continue;
		}

	/* Van der Waals radius of oxygen: */
	if (strstr (s, "oxygen") && strstr (s, "Waals"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->O_van_der_Waals_radius = d;
		continue;
		}

	/* Van der Waals radius of sulfur: */
	if (strstr (s, "sulfur") && strstr (s, "Waals"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->S_van_der_Waals_radius = d;
		continue;
		}

	/* Van der Waals radius of phosphorus: */
	if (strstr (s, "phosphorus") && strstr (s, "Waals"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->P_van_der_Waals_radius = d;
		continue;
		}

	/* Van der Waals radius of unknown atom (generic radius): */
	if (strstr (s, "generic") && strstr (s, "Waals"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->generic_van_der_Waals_radius = d;
		continue;
		}

	/* Ball radius (used to draw balls and sticks): */
	if (strstr (s, "default") && strstr (s, "ball") &&
	    strstr (s, "radius"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->default_ball_radius = d;
		continue;
		}

	/* Default bond probe radius (used to draw nice bonds): */
	if (strstr (s, "bond") && strstr (s, "probe") && strstr (s, "radius"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->default_bond_probe_radius = d;
		continue;
		}

	/* Default stick radius (used to draw bonds as sticks): */
	if (strstr (s, "default") && strstr (s, "stick") &&
	    strstr (s, "radius"))
		{
		d = ExtractDouble_ (s);
		if (d > 0.0) configSP->default_stick_radius = d;
		continue;
		}

	/* The number of neighboring atoms which should be checked */
	/* as bond candidates,  in each direction of  AtomS array: */
	if (strstr (s, "number") && strstr (s, "bond") &&
	    strstr (s, "candidates"))
		{
		if (ExtractTwoIntegers_ (&n1, &n2, s) > 0)
			{
			if (n1 > 0) configSP->bond_candidates_backward = n1;
			if (n2 > 0) configSP->bond_candidates_forward  = n2;
			}
		continue;
		}

        /* Blur rectangle default width (positive integer expected): */
        if (strstr (s, "blur") && strstr (s, "rectangle") &&
	    strstr (s, "width"))
                {
                n = ExtractInteger_ (s);
                if (n >= 0) configSP->blur_default_width = n;
                continue;
                }

	/* Blur rectangle default height (positive integer expected): */
	if (strstr (s, "blur") && strstr (s, "rectangle") &&
	    strstr (s, "height"))
		{
		n = ExtractInteger_ (s);
		if (n >= 0) configSP->blur_default_height = n;
		continue;
		}
	}

/* Close file: */
fclose (fileP);

return 1;
}

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


