/*
    This file is part of the FElt finite element analysis package.
    Copyright (C) 1993 Jason I. Gobat and Darren C. Atkinson

    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; either version 2 of the License, or
    (at your option) any later version.

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/************************************************************************
 * File:	solution.c						*
 *									*
 * Description:	This file contains the private and public function and	*
 *		type definitions for the solution dialog box.		*
 ************************************************************************/

# include <stdio.h>
# include <X11/Intrinsic.h>
# include <X11/StringDefs.h>
# include <X11/Shell.h>
# include <X11/Xaw/AsciiText.h>
# include <X11/Xaw/Command.h>
# include <X11/Xaw/Toggle.h>
# include <X11/Xaw/Label.h>
# include "Rheostat.h"
# include "Layout.h"
# include "Solution.h"
# include "TabGroup.h"
# include "util.h"

# ifndef X_NOT_STDC_ENV
# include <stdlib.h>
# else
extern double atof ( );
extern int    atoi ( );
# endif

Solution	solution;

struct solution_dialog {
    Widget  shell;		/* topLevelShell  <specified>	*/
    Widget  layout;		/*	Layout  layout		*/
    Widget  title;		/*	     AsciiText title	*/
    Widget  felt;		/* 	     Toggle felt	*/
    Widget  do_felt;		/*	     Command do_felt	*/
    Widget  xrot;		/*	     Rheostat xrot	*/
    Widget  yrot;		/*	     Rheostat yrot	*/
    Widget  zrot;		/*	     Rheostat zrot	*/
    Widget  zscale;		/*	     AsciiText zscale	*/
    Widget  magnify;		/*	     AsciiText magnify	*/
    Widget  structure;		/*	     Toggle structure	*/
    Widget  do_structure;	/*	     Command do_struct	*/
    Widget  component;		/*	     AsciiText compon	*/
    Widget  equalize;		/*	     Toggle equalize	*/
    Widget  stress;		/*	     Toggle stress	*/
    Widget  do_stress;		/*	     Command do_stress  */
    Widget  solve;		/* 	     Command solve	*/
    Widget  help;		/*	     MenuButton  help	*/
    Widget  accept;		/*	     Command  accept	*/
    Widget  dismiss;		/*	     Command  dismiss	*/
};


static String labels [ ] = {
    "title:","felt output on solution","x-rot","y-rot","z-rot","z-scale:",
    "magnify:","plot structure on solution","component:",
    "equalize output","plot stresses on solution"
};

static String label_names [ ] = {
    "title_name","felt_name","xrot_name","yrot_name","zrot_name",
    "zscale_name","magnify_name","structure_name","component_name",
    "equalize_name","stress_name"
};


/* Resources */

static Pixel highlight;

static char layout_string [ ] =
"vertical { \
     horizontal { \
        vertical { \
            4 \
            horizontal { \
                4 \
                title_name \
                2 \
                title <+inf -100% *> \
                4 \
            } \
            8 \
            separator1 <+inf -100% *> \
            8 \
            horizontal { \
                4 \
                felt \
                2 \
                felt_name \
                4 \
            } \
            4 \
            horizontal { \
                4 \
                do_felt <+inf -100% *> \
                4 \
            } \
            8 \
            separator3 <+inf -100% *> \
            8 \
            horizontal { \
                4 \
                component_name \
                2 \
                component \
                4 \
            } \
            4 \
            horizontal { \
                4 \
                equalize \
                2 \
                equalize_name \
                4 \
            } \
            4 \
            horizontal { \
                4 \
                stress \
                2 \
                stress_name \
                4 \
            } \
            4 \
            horizontal { \
                4 \
                do_stress <+inf -100% *> \
                4 \
            } \
            4 \
        } \
        separator2 <* +inf -100%> \
        vertical { \
            4 \
            horizontal { \
                4 \
                xrot \
                4 \
                yrot \
                4 \
                zrot \
                4 \
            } \
            1 \
            horizontal { \
                4 \
                ((width xrot - width xrot_name) / 2) \
                xrot_name \
                ((width xrot - width xrot_name) / 2) \
                4 \
                ((width yrot - width yrot_name) / 2) \
                yrot_name \
                ((width yrot - width yrot_name) / 2) \
                4 \
                ((width zrot - width zrot_name) / 2) \
                zrot_name \
                ((width zrot - width zrot_name) / 2) \
                4 \
            } \
            4 \
            horizontal { \
                4 \
                zscale_name \
                2 \
                zscale \
            } \
            4 \
            horizontal { \
                4 \
                magnify_name \
                2 \
                magnify \
            } \
            4 \
            horizontal { \
                4 \
                structure \
                2 \
                structure_name \
            } \
            4 \
            horizontal { \
                4 \
                do_structure <+inf -100% *> \
                4 \
            } \
            4 \
        } \
    } \
    separator4 <+inf -100% *> \
    4 \
    horizontal { \
	4 \
        help \
        4 <+inf -100%> \
        solve \
        4 <+inf -100%> \
        accept \
 	4 <+inf -100%> \
 	dismiss \
 	4 \
    } \
    4 \
}";

static Arg color_args [ ] = {
    {XtNborderColor, (XtArgVal) &highlight},
};

static Arg shell_args [ ] = {
    {XtNtitle, (XtArgVal) NULL},
};

static Arg layout_args [ ] = {
    {XtNlayout, (XtArgVal) NULL},
};

static Arg text_args [ ] = {
    {XtNeditType,    (XtArgVal) XawtextEdit},
    {XtNborderWidth, (XtArgVal) 0},
    {XtNpieceSize,   (XtArgVal) 32},
    {XtNcursorName,  (XtArgVal) "left_ptr"},
};

static Arg label_args [ ] = {
    {XtNlabel,	            (XtArgVal) ""},
    {XtNborderWidth,        (XtArgVal) 0},
};

static Arg core_args [ ] = {
    {XtNwidth,	(XtArgVal) 1},
    {XtNheight, (XtArgVal) 1},
};

static Arg rheostat_args [ ] = {
    {XtNminimumAngle, (XtArgVal) 0},
    {XtNmaximumAngle, (XtArgVal) 360},
    {XtNminimumValue, (XtArgVal) 0},
    {XtNmaximumValue, (XtArgVal) 360},
    {XtNtickGravity,  (XtArgVal) True},
};

static Arg toggle_args [ ] = {
    {XtNlabel,		    (XtArgVal) " "},
};

/* Translation tables */

static String text_table =
"<Key>Return: SolutionDialogAction(accept)\n\
 <Key>Escape: SolutionDialogAction(dismiss)\n\
 Ctrl<Key>h:  SolutionDialogAction(help)\n\
 <Btn1Down>:  SetFocus() select-start()";

static XtTranslations text_translations;

static String command_table =
"<Key>Return:   AutoRepeat(off) set()\n\
 <KeyUp>Return: AutoRepeat(saved) notify() unset()\n\
 <Key>space:    AutoRepeat(off) set()\n\
 <KeyUp>space:  AutoRepeat(saved) notify() unset()\n\
 <Key>Escape:   SolutionDialogAction(dismiss)";

static XtTranslations command_translations;

static String toggle_table =
"<Key>Return:	toggle()\n\
 <Key>space:	toggle()\n\
 Ctrl<Key>h:	SolutionDialogAction(help)\n\
 <Btn1Down>:	SetFocus()";

static XtTranslations toggle_translations;

/* Help message. */

static String help_message ="\
Use this form to configure / determine the display of results which \
velvet produces when a problem is solved (with the toggle buttons \
labeled '... on solution') or after a problem has been solved (with \
the '... now' push buttons).";


/************************************************************************
 * Function:	Action							*
 *									*
 * Description:	An action procedure which emulates pressing of the	*
 *		specified button.					*
 ************************************************************************/

static void Action (w, event, params, num_params)
    Widget    w;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
{
    if (XtClass (w) == topLevelShellWidgetClass)
	w = XtNameToWidget (w, "layout.dismiss");
    else
	w = XtNameToWidget (XtParent (w), params [0]);

    XtCallCallbacks (w, XtNcallback, NULL);
}


/************************************************************************
 * Function:	Accept							*
 *									*
 * Description:								*
 ************************************************************************/

static void Accept (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    Arg		   args [1];
    SolutionDialog solutiond;
    String	   value;
    Boolean	   state;
    int		   angle;

    solutiond = (SolutionDialog) client_data;

    XtSetArg (args [0], XtNstring,  &value);

    XtGetValues (solutiond -> title, args, 1);
    solution -> title = XtNewString (value);
    XtGetValues (solutiond -> zscale, args, 1);
    solution -> zscale = atof (value);
    XtGetValues (solutiond -> magnify, args, 1);
    solution -> magnify = atof (value);
    XtGetValues (solutiond -> component, args, 1);
    solution -> component = atoi (value);

    XtSetArg (args [0], XtNstate, &state);

    XtGetValues (solutiond -> felt, args, 1);
    solution -> felt = state;
    XtGetValues (solutiond -> stress, args, 1);
    solution -> stress = state;
    XtGetValues (solutiond -> structure, args, 1);
    solution -> structure = state;
    XtGetValues (solutiond -> equalize, args, 1);
    solution -> equalize = state;

    XtSetArg (args [0], XtNvalue, &angle);
   
    XtGetValues (solutiond -> xrot, args, 1);
    solution -> xrot = (float) angle;
    XtGetValues (solutiond -> yrot, args, 1);
    solution -> yrot = (float) angle;
    XtGetValues (solutiond -> zrot, args, 1);
    solution -> zrot = (float) angle;
    
    SolutionDialogUpdate (solutiond);
}


/************************************************************************
 * Function:	Dismiss							*
 *									*
 * Description:	sets the dismiss flag					*
 ************************************************************************/

static void Dismiss (w, client_data, call_data)
    Widget    w;
    XtPointer client_data;
    XtPointer call_data;
{
    SolutionDialog solutiond;

    solutiond = (SolutionDialog) client_data;
    XtPopdown (solutiond -> shell);
}

/************************************************************************
 ************************************************************************/

static void ExternalCallback (w, client_data, call_data)
    Widget 	w;
    XtPointer	client_data;
    XtPointer	call_data;
{
    SolutionDialog	solutiond;

    solutiond = (SolutionDialog) client_data;

    SolutionDialogUpdate (solutiond);

    if (w == solutiond -> solve) {
       CompactOperation (NULL);
       return;
    }
    else if (w == solutiond -> do_felt) {
       OutputWindowPopup ();
       return;
    }
    else if (w == solutiond -> do_structure) {
       SetupStructure (True);
       return;
    }
    else if (w == solutiond -> do_stress) 
       SetupStresses (True);
}

/************************************************************************
 * Function:	SolutionDialogUpdate					*
 *									*
 * Description:	sets the widgets based on current solution settings 	*
 ************************************************************************/

void SolutionDialogUpdate (solutiond)
    SolutionDialog	solutiond;
{
    Arg		args [1];
    char	buffer [80];

    SetTextString (solutiond -> title, solution -> title);

    sprintf (buffer,"%g",solution -> zscale);
    SetTextString (solutiond -> zscale, buffer);
    sprintf (buffer,"%g",solution -> magnify);
    SetTextString (solutiond -> magnify, buffer);
    sprintf (buffer,"%d",solution -> component);
    SetTextString (solutiond -> component, buffer);

    XtSetArg (args [0], XtNstate, solution -> felt);
    XtSetValues (solutiond -> felt, args, 1);
    XtSetArg (args [0], XtNstate, solution -> structure);
    XtSetValues (solutiond -> structure, args, 1);
    XtSetArg (args [0], XtNstate, solution -> equalize);
    XtSetValues (solutiond -> equalize, args, 1);
    XtSetArg (args [0], XtNstate, solution -> stress);
    XtSetValues (solutiond -> stress, args, 1);

    XtSetArg (args [0], XtNvalue, (int) solution -> xrot);
    XtSetValues (solutiond -> xrot, args, 1);
    XtSetArg (args [0], XtNvalue, (int) solution -> yrot);     
    XtSetValues (solutiond -> yrot, args, 1);
    XtSetArg (args [0], XtNvalue, (int) solution -> zrot);     
    XtSetValues (solutiond -> zrot, args, 1);
}

/************************************************************************
 * Function:	SolutionDialogCreate					*
 *									*
 * Description:	Creates a new solution dialog.  You would never want to	*
 *		have more than one of these but the interface is kept	*
 *		consistent with those of the other dialogs.		*
 ************************************************************************/

SolutionDialog SolutionDialogCreate (parent, name, title)
    Widget parent;
    String name;
    String title;
{
    Cardinal		i;
    Arg			args [1];
    Widget		group [18];
    SolutionDialog	solutiond;
    Dimension		width;
    Position		x;
    int			depth;
    static XtAppContext	app_context = NULL;
    static XtActionsRec	actions [ ] = {{"SolutionDialogAction", Action}};


    /* Perform one time initialization. */

    if (app_context == NULL) {
	app_context = XtWidgetToApplicationContext (parent);
	XtAppAddActions (app_context, actions, XtNumber (actions));
	AddAutoRepeatAction (app_context);

        layout_args [0].value = StringToLayout (parent, layout_string);

        toggle_translations = XtParseTranslationTable (toggle_table);
	text_translations = XtParseTranslationTable (text_table);
	command_translations = XtParseTranslationTable (command_table);
    }


    /* Create the material dialog and its widgets. */

    XtSetArg (shell_args [0], XtNtitle, title);

    solutiond = XtNew (struct solution_dialog);

    solution = XtNew (struct solution);

    solutiond -> shell    = XtCreatePopupShell (name,
			 topLevelShellWidgetClass, parent,
			 shell_args, XtNumber (shell_args));

    solutiond -> layout   = XtCreateManagedWidget ("layout",
			 layoutWidgetClass, solutiond -> shell,
			 layout_args, XtNumber (layout_args));

    solutiond -> title	  = XtCreateManagedWidget ("title",
                         asciiTextWidgetClass, solutiond -> layout,
                         text_args, XtNumber (text_args));

    solutiond -> felt     = XtCreateManagedWidget ("felt",
                         toggleWidgetClass, solutiond -> layout,
                         toggle_args, XtNumber (toggle_args));

    XtSetArg (args [0], XtNlabel, "felt output now");
    solutiond -> do_felt  = XtCreateManagedWidget ("do_felt",
                         commandWidgetClass, solutiond -> layout,
                         args, 1);

    solutiond -> structure     = XtCreateManagedWidget ("structure",
                         toggleWidgetClass, solutiond -> layout,
                         toggle_args, XtNumber (toggle_args));

    XtSetArg (args [0], XtNlabel, "plot structure now");
    solutiond -> do_structure  = XtCreateManagedWidget ("do_structure",
                         commandWidgetClass, solutiond -> layout,
                         args, 1);

    solutiond -> stress     = XtCreateManagedWidget ("stress",
                         toggleWidgetClass, solutiond -> layout,
                         toggle_args, XtNumber (toggle_args));

    XtSetArg (args [0], XtNlabel, "plot stresses now");
    solutiond -> do_stress  = XtCreateManagedWidget ("do_stress",
                         commandWidgetClass, solutiond -> layout,
                         args, 1);

    solutiond -> xrot     = XtCreateManagedWidget ("xrot",
                         rheostatWidgetClass, solutiond -> layout,
                         rheostat_args, XtNumber (rheostat_args));

    solutiond -> yrot     = XtCreateManagedWidget ("yrot",
                         rheostatWidgetClass, solutiond -> layout,
                         rheostat_args, XtNumber (rheostat_args));

    solutiond -> zrot     = XtCreateManagedWidget ("zrot",
                         rheostatWidgetClass, solutiond -> layout,
                         rheostat_args, XtNumber (rheostat_args));

    solutiond -> zscale  = XtCreateManagedWidget ("zscale",
                         asciiTextWidgetClass, solutiond -> layout,
                         text_args, XtNumber (text_args));

    solutiond -> magnify = XtCreateManagedWidget ("magnify",
                         asciiTextWidgetClass, solutiond -> layout,
                         text_args, XtNumber (text_args));

    solutiond -> component = XtCreateManagedWidget ("component",
                         asciiTextWidgetClass, solutiond -> layout,
                         text_args, XtNumber (text_args));

    solutiond -> equalize = XtCreateManagedWidget ("equalize",
                         toggleWidgetClass, solutiond -> layout,
                         toggle_args, XtNumber (toggle_args));

    solutiond -> accept   = XtCreateManagedWidget ("accept",
			 commandWidgetClass, solutiond -> layout,
			 NULL, 0);

    solutiond -> solve   = XtCreateManagedWidget ("solve",
			 commandWidgetClass, solutiond -> layout,
			 NULL, 0);

    solutiond -> dismiss  = XtCreateManagedWidget ("dismiss",
			 commandWidgetClass, solutiond -> layout,
			 NULL, 0);

    solutiond -> help     = CreateHelpButton (solutiond -> layout, "help");

    for (i = 0 ; i < XtNumber (labels) ; i++) {
        label_args [0].value = (XtArgVal) labels [i];
        XtCreateManagedWidget (label_names [i], labelWidgetClass,
                   solutiond -> layout, label_args, XtNumber (label_args));
    }

    XtCreateManagedWidget ("separator1", coreWidgetClass, 
               solutiond -> layout, core_args, XtNumber (core_args));
    XtCreateManagedWidget ("separator2", coreWidgetClass, 
               solutiond -> layout, core_args, XtNumber (core_args));
    XtCreateManagedWidget ("separator3", coreWidgetClass, 
               solutiond -> layout, core_args, XtNumber (core_args));
    XtCreateManagedWidget ("separator4", coreWidgetClass, 
               solutiond -> layout, core_args, XtNumber (core_args));


    /* Create a tab group for the solution dialog. */

    group [0]  = solutiond -> title;
    group [1]  = solutiond -> felt;
    group [2]  = solutiond -> do_felt;
    group [3]  = solutiond -> component;
    group [4]  = solutiond -> equalize;
    group [5]  = solutiond -> stress;
    group [6]  = solutiond -> do_stress;
    group [7]  = solutiond -> xrot;
    group [8]  = solutiond -> yrot;
    group [9]  = solutiond -> zrot;
    group [10] = solutiond -> zscale;
    group [11] = solutiond -> magnify;
    group [12] = solutiond -> structure;
    group [13] = solutiond -> do_structure;
    group [14] = solutiond -> help;
    group [15] = solutiond -> solve;
    group [16] = solutiond -> accept;
    group [17] = solutiond -> dismiss;

    XtGetValues (solutiond -> layout, color_args, XtNumber (color_args));
    CreateTabGroup (solutiond -> shell, group, XtNumber (group), 
                    highlight, True);

    XtRealizeWidget (solutiond -> shell);
    SetFocus (solutiond -> title);

    XtSetArg (args [0], XtNwidth, &width);
    XtGetValues (solutiond -> layout, args, 1);
    XtSetArg (args [0], XtNx, &x);
    XtGetValues (solutiond -> help, args, 1);
    UpdateHelpMessage (solutiond -> help, help_message, width - 2 * x);


    /* Add the translations to each widget. */

    AddDeleteWindowProtocol   (solutiond -> shell, "SolutionDialogAction()");

    XtOverrideTranslations (solutiond -> title,	    text_translations);
    XtOverrideTranslations (solutiond -> zscale,    text_translations);
    XtOverrideTranslations (solutiond -> magnify,   text_translations);
    XtOverrideTranslations (solutiond -> component, text_translations);
    XtOverrideTranslations (solutiond -> felt,      toggle_translations);
    XtOverrideTranslations (solutiond -> stress,    toggle_translations);
    XtOverrideTranslations (solutiond -> structure, toggle_translations);
    XtOverrideTranslations (solutiond -> equalize,  toggle_translations);
    XtOverrideTranslations (solutiond -> do_felt,      command_translations);
    XtOverrideTranslations (solutiond -> do_stress,    command_translations);
    XtOverrideTranslations (solutiond -> do_structure, command_translations);
    XtOverrideTranslations (solutiond -> solve,        command_translations);
    XtOverrideTranslations (solutiond -> dismiss,      command_translations);
    XtOverrideTranslations (solutiond -> accept,       command_translations);


    /* Add the necessary callbacks. */

    XtAddCallback(solutiond->accept, XtNcallback,Accept, (XtPointer) solutiond);
    XtAddCallback(solutiond->dismiss,XtNcallback,Dismiss,(XtPointer) solutiond);

 
    XtAddCallback (solutiond -> do_stress, XtNcallback, 
                   Accept, (XtPointer)solutiond);
    XtAddCallback (solutiond -> do_structure, XtNcallback, 
                   Accept, (XtPointer)solutiond);
    XtAddCallback (solutiond -> do_felt, XtNcallback, 
                   Accept, (XtPointer)solutiond);
    XtAddCallback (solutiond -> solve, XtNcallback, 
                   Accept, (XtPointer)solutiond);

    XtAddCallback (solutiond -> solve, XtNcallback, 
                   ExternalCallback, (XtPointer) solutiond);
    XtAddCallback (solutiond -> do_felt, XtNcallback, 
                   ExternalCallback, (XtPointer) solutiond);
    XtAddCallback (solutiond -> do_stress, XtNcallback, 
                   ExternalCallback, (XtPointer) solutiond);
    XtAddCallback (solutiond -> do_structure, XtNcallback, 
                   ExternalCallback, (XtPointer) solutiond);

	/*
	 * a check to see if the current display is only 1-bit deep,
	 * if so, stresses are a non-no
	 */

    XtSetArg (args [0], XtNdepth, &depth);
    XtGetValues (parent, args, 1);
    if (depth != 8) {
        XtSetSensitive (solutiond -> do_stress, False);
        XtSetSensitive (solutiond -> stress, False);
        XtSetSensitive (solutiond -> equalize, False);
        XtSetSensitive (solutiond -> component, False);

        solution -> equalize = False;
        solution -> stress = False;
    }
       

    return solutiond;
}


/************************************************************************
 * Function:	SolutionDialogPopup					*
 *									*
 * Description:	Pops up the specified material dialog.			*
 ************************************************************************/

void SolutionDialogPopup (solutiond)
    SolutionDialog solutiond;
{
    XtPopup (solutiond -> shell, XtGrabNone);
}
