/*

    o-------------------------------------------------------------------o
    |                                                                   |
    | Copyright (C) 2000-2006 Damir Zucic                               |
    |                                                                   |
    | This program is free software; you can redistribute it and/or     |
    | modify it under the terms of the GNU General Public License       |
    | as published by the Free Software Foundation, version 2.          |
    |                                                                   |
    | This program is distributed in the hope that it will be useful,   |
    | but WITHOUT ANY WARRANTY; without even the implied warranty of    |
    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     |
    | GNU General Public License for more details.                      |
    |                                                                   |
    | You should have received a copy of the GNU General Public License |
    | along with this program; if not, write to the                     |
    | Free Software Foundation, Inc.,                                   |
    | 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.         |
    |                                                                   |
    o-------------------------------------------------------------------o

*/

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

				garlic.c
		Molecular visualization and analyzing tool

General description:
	Garlic is molecular visualization program written for investigation
	of membrane proteins.  It may be used to visualize  other proteins,
	as well  as some  geometric  objects.  This version  is  capable to
	recognize the PDB format version 2.1;  check pdb_atom.c for details
	about this format.

Author:
	Damir Zucic (zucic@garlic.mefos.hr), University of Osijek, Croatia.

-------------------------------------------------------------------------------

Naming conventions:
	 (1) xxx_yyy	   Simple variable;  lowercase, underline separates
			   adjacent words.
	 (2) xxx_yyyI	   Index (array index usually).
	 (3) xxx_yyyN	   Number of array elements.
	 (4) xxx_yyyID	   Identifier (integer or long integer).
	 (5) xxx_yyyF	   Flag (usually integer, value 0 or 1).
	 (6) XxxYyyS	   New data type (typedef struct XxxYyyS).
	 (7) xxx_yyyS	   Structure (type: XxxYyyS).
	 (8) xxx_yyyP	   Pointer.
	 (9) xxx_yyySP	   Pointer to structure.
	(10) xxx_yyyA[]	   Array; no space before left bracket.
	(11) xxx_yyyAA[][] Two dimensional array.
	(12) xxx_yyySA[]   Array of structures.
	(13) xxx_yyyPA[]   Array of pointers.
	(14) XXXYYYZZZ	   Symbol (#define).
	(15) XxxYyy_ ()	   Function; the first character in each word is in
			   uppercase;  the last character is underline; one
			   space (exactly one!) used  to separate underline
			   and left parenthesis;  underline is  not used to
			   separate words.
	(16) xxx_yyyGC	 Graphics context (pointer to _XGC structure).

Programming style:
	When this project was started RAM and hard disk became quite cheap.
	Thus:
	(1) Whenever choosing between  brute force and intelligence,  chose
	    force: it is cheaper, simpler and more reliable. Of course, use
	    brain if there is no other choice.
	(2) Comment everything,  including trivial things,  so that hackers
	    find this program disgusting.
	(3) Never put two functions in  the same file,  even if it seems to
	    be reasonable.
	(4) Use verbose function and variable names.
	(5) Indentation is one tab (eight characters),  except in functions
	    which draw atoms and bonds (four characters).
	(6) Each brace should be placed in a separate line.
	(7) Avoid global scope data.
	(8) Use auxiliary structures  when some function requires  a lot of
	    input data.  Pass  pointer  to the structure to  this function,
	    instead of a large number of arguments.

Portability:
	Garlic should be  ANSI C and/or POSIX compliant.  All functions fit
	into one of these standards:
	(1) ANSI C programming language.
	(2) Xlib, X Window System (X11R6).

From /usr/games/fortunes/fortunes file (Linux Slackware 3.4):
"What garlic is to food, insanity is to art."

-------------------------------------------------------------------------------

Purpose of this file:
        The  main function is in this file.  The real job is done by called
	functions.

Return value / exit status:
         (1)    EXIT_SUCCESS on success.
         (2)    EXIT_FAILURE on failure.
         (3)    EXIT_SUCCESS if help, version info or registr. is required.

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

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

/*======defines:=============================================================*/

/* See defines.h for all other symbols! */

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

void		PrintUsage_ (void);
void		PrintHelp_ (void);
void		PrintVersion_ (void);
int		Register_ (void);
void		ErrorMessage_ (char *, char *, char *,
			       char *, char *, char *, char *);
void		WarningMessage_ (char *, char *, char *,
				 char *, char *, char *, char *);
GUIS		*AllocateGUIS_ (void);
ConfigS		*AllocateConfigS_ (void);
MolComplexS	*AllocateMolComplexSA_ (size_t);
void		FreeMemory_ (GUIS *, MolComplexS *, int,
			     NearestAtomS *, size_t *);
int		ReadConfig_ (ConfigS *);
int		ExtractArgs_ (ConfigS *, GUIS *, char *, int, char **);
void		PrintCursorNames_ (void);
int		DisplayInit_ (GUIS *);
int		DisplayColorCapabilities_ (GUIS *);
int		ParseOptions_ (GUIS *, ConfigS *);
int		CreateWindows_ (GUIS *, ConfigS *, int, char **);
int		CalculateParameters_ (ConfigS *, GUIS *);
void		PrintConfig_ (ConfigS *, GUIS *);
int		LoadComplex_ (int *, MolComplexS *, int *, int *,
			      char *, ConfigS *, GUIS *);
NearestAtomS	*AllocateNearest_ (size_t *, GUIS *);
void		InitNearest_ (NearestAtomS *, size_t);
int		ColorSchemes_ (MolComplexS *, int, ConfigS *,
			       GUIS *, char *, int);
int		IdentifyButton_ (XButtonEvent *, GUIS *);
int		EventLoop_ (MolComplexS *, int *, int *,
			    NearestAtomS **, size_t *, ConfigS *, GUIS *);

/*======main:================================================================*/

int main (int argc, char *argv[])
{
int			mainI = 0;		/* Positive on success */
int			n;			/* Auxiliary integer */
static GUIS		*guiSP;			/* See typedefs.h */
static ConfigS		*configSP;		/* Read from .garlicrc */
static char		mol_file_nameA[STRINGSIZE];       /* Input file name */
static MolComplexS	*mol_complexSP;		/* Macromolecular data */
int			mol_complexesN = 0;	/* Number of  mol. complexes */
int			next_mol_complexID = 1;	/* Initial value should be 1 */
static NearestAtomS	*nearest_atomSP;	/* Replaces depth sorting */
size_t			pixelsN;		/* The number of pixels */
int			dummy_groupF;		/* Has no special meaning */

/* Write brief introduction - if requested - and exit: */
for (n = 0; n < argc; n++)
	{
	if ((strcmp (argv[n], "-h") == 0) ||
	    (strcmp (argv[n], "--help") == 0) ||
	    (strcmp (argv[n], "-help") == 0))
		{
		PrintHelp_ ();
		exit (EXIT_SUCCESS);
		}
	}

/* Print version information - if requested - and exit: */
for (n = 0; n < argc; n++)
	{
	if ((strcmp (argv[n], "-v") == 0) ||
	    (strcmp (argv[n], "--version") == 0))
		{
		PrintVersion_ ();
		exit (EXIT_SUCCESS);
		}
	}

/* Register user (send e-mail to the author) - if requested - and exit: */
for (n = 0; n < argc; n++)
	{
	if ((strcmp (argv[n], "-r") == 0) ||
	    (strcmp (argv[n], "--register") == 0))
		{
		Register_ ();
		fprintf (stdout, "A short e-mail message with registration");
		fprintf (stdout, " was send to the author.\n");
		exit (EXIT_SUCCESS);
		}
	}

/* Formal, single pass loop (many things happen here): */
do
	{
	/* Allocate memory for GUI data: */
	mainI--;
	guiSP = AllocateGUIS_ ();
	if (guiSP == NULL) break;

	/* Initialize the main window refreshing flag: */
	mainI--;
	guiSP->main_window_refreshF = 1;

	/* Initialize the main window drawing mode index: */
	mainI--;
	guiSP->main_window_modeI = 0;

	/* Allocate memory for configuration data: */
	mainI--;
	configSP = AllocateConfigS_ ();
	if (configSP == NULL) break;

	/* Allocate memory for macromolecular data: */
	mainI--;
	mol_complexSP = AllocateMolComplexSA_ (MAXCOMPLEXES);
	if (mol_complexSP == NULL) break;

	/* Read configuration from $HOME.garlicrc file: */
	mainI--;
	n = ReadConfig_ (configSP);

	/* Extract command line arguments: */
	mainI--;
	n = ExtractArgs_ (configSP, guiSP, mol_file_nameA, argc, argv);
	if (n < 0) break;

	/* Print cursor names and exit on request: */
	mainI--;
	if (configSP->print_cursor_namesF)
		{
		PrintCursorNames_ ();
		break;
		}

	/* Display related initializations: */
	mainI--;
	n = DisplayInit_ (guiSP);
	if (n < 0)
		{
		PrintUsage_ ();
		fprintf (stderr, "\nUnable to connect to  X  server,");
		fprintf (stderr, "  exiting ...\n");
		break;
		}

	/* Display color properties: */
	mainI--;
	n = DisplayColorCapabilities_ (guiSP); 
	if (n < 0) break;

	/* Parse options which require connection to X server: */
	mainI--;
	n = ParseOptions_ (guiSP, configSP);
	if (n < 0) break;

	/* Create windows: */
	mainI--;
	n = CreateWindows_ (guiSP, configSP, argc, argv);
	if (n < 0) break;

	/* Calculate the remaining parameters: */
	mainI--;
	n = CalculateParameters_ (configSP, guiSP);
	if (n < 0) break;

	/* Load macromolecular complex if input file name is specified: */
	mainI--;
	LoadComplex_ (&dummy_groupF,
		      mol_complexSP, &mol_complexesN, &next_mol_complexID,
		      mol_file_nameA, configSP, guiSP);

	/* Print configuration data, if requested: */
	mainI--;
	if (configSP->print_configF)
		{
		PrintConfig_ (configSP, guiSP);
		mainI *= -1;
		break;
		}

	/* Allocate the array of NeareastAtomS structures: */
	mainI--;
	nearest_atomSP = AllocateNearest_ (&pixelsN, guiSP);
	if (nearest_atomSP == NULL) break;

	/* Initialize the array of NearestAtomS structures: */
	InitNearest_ (nearest_atomSP, pixelsN);

	/* Prepare the simple color schemes: */
	mainI--;
	ColorSchemes_ (mol_complexSP, mol_complexesN, configSP,
		       guiSP, "dummy", 0);

	/* Initialize default colors for molecular surfaces: */
	mainI--;
	ColorSchemes_ (mol_complexSP, mol_complexesN, configSP,
		       guiSP, configSP->surface_outer_color_schemeA, 1);
	ColorSchemes_ (mol_complexSP, mol_complexesN, configSP,
		       guiSP, configSP->surface_inner_color_schemeA, 2);

	/* Define dummy buttons in control window: */
	mainI--;
	IdentifyButton_ ((XButtonEvent *) NULL, guiSP);

	/* Take and process events: */
	mainI--;
	n = EventLoop_ (mol_complexSP, &mol_complexesN, &next_mol_complexID,
			&nearest_atomSP, &pixelsN, configSP, guiSP);
	if (n < 0) break;

	/* If this point is reached, everything worked */
	/* fine; change the sign of mainI to positive: */
	mainI *= -1;
	} while (0);

/* Free storage used for pixmaps and other data: */
FreeMemory_ (guiSP, mol_complexSP, mol_complexesN, nearest_atomSP, &pixelsN);

/* Close connection to X server: */
if (guiSP->displaySP) XCloseDisplay (guiSP->displaySP);

/* Free the array of MolComplexS structures: */
if (mol_complexSP) free (mol_complexSP);

/* Close log file if used at all: */
if (configSP->log_fileF != 0) fclose (configSP->log_fileP);

/* Free ConfigS structure: */
if (configSP) free (configSP);

/* Free GUIS structure: */
if (guiSP) free (guiSP);

/* Return on failure: */
if (mainI < 0) return EXIT_FAILURE;

/* Return on success: */
return EXIT_SUCCESS;
}

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


