/*
    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:	velvet.c						*
 *									*
 * Description:	This file contains the routines for the top level of	*
 *		the velvet application.					*
 ************************************************************************/

# include <stdio.h>
# include <unistd.h>
# include <X11/Intrinsic.h>
# include <X11/StringDefs.h>
# include <X11/Xresource.h>
# include <X11/Xaw/AsciiText.h>
# include <X11/Xaw/Command.h>
# include <X11/Xaw/Dialog.h>
# include <X11/Xaw/Form.h>
# include <X11/Xaw/Label.h>
# include <X11/Xaw/MenuButton.h>
# include <X11/Xaw/Reports.h>
# include <X11/Xaw/SimpleMenu.h>
# include <X11/Xaw/Sme.h>
# include <X11/Xaw/SmeBSB.h>
# include <X11/Xaw/Viewport.h>
# include "fe.h"
# include "Drawing.h"
# include "FileDialog.h"
# include "OutputDialog.h"
# include "ElementList.h"
# include "Constraint.h"
# include "Element.h"
# include "Force.h"
# include "Material.h"
# include "Load.h"
# include "Node.h"
# include "Canvas.h"
# include "Solution.h"
# include "dialog.h"
# include "procedures.h"
# include "problem.h"
# include "globals.h"
# include "callbacks.h"
# include "panel.h"
# include "definitions.h"
# include "vfe.h"
# include "error.h"
# include "check.xbm"
# include "question.xbm"
# include "menu16.xbm"
# include "popup.xbm"
# include "FElt.icon"


static char *defaults [ ] = {
# include "velvet.ad.h"
NULL
};

/* the global dialogs that we will create in main() */

FileDialog	  filed;
ConstraintDialog  constraint_d;
ForceDialog	  force_d;
LoadDialog	  load_d;
MaterialDialog	  material_d;
ElementDialog	  element_d;
NodeDialog	  node_d;
ElementList	  element_l;
CanvasDialog	  canvas_d;
SolutionDialog	  solution_d;

Dialog 		*info_dialog;

PanelId  last_command = -1;

/************************************************************************
 * Function:	 PanelCallback						*
 *									*
 * Parameters:	 widget     - callback widget (ignored)			*
 *		 clientData - pointer to panel id			*
 *		 callData   - callback data (ignored)			*
 *									*
 * Return value: none							*
 *									*
 * Calls:	 ???							*
 *									*
 * Called by:	 X11							*
 *									*
 * Global data:	 changeflag may be modified				*
 *									*
 * Description:	 Panelcallback is called when an action is taken on the	*
 *		 control panel.  The client data is a pointer to the	*
 *		 panel id which indicates what action is to be taken.	*
 ************************************************************************/

void PanelCallback (widget, clientData, callData)
    Widget    widget;
    XtPointer clientData;
    XtPointer callData;
{
    if (!edit_mode) {

       last_command = *(PanelId *) clientData;
       switch (*(PanelId *) clientData) {
       case AddNode:
           EditAddNode ();
           break;

       case DeleteNode:
	   EditDeleteNode ();
	   break;

       case EditNode:
           EditNodeNumber ();
           break;

       case MoveNodeId:
	   MoveNodeNumber ();
	   break;

       case AddElt:
           EditAddElement ();
	   break;

       case DeleteElt:
	   EditDeleteElement ();
	   break;

       case EditElement:
           EditElementNumber ();
           break;

       case SetType:
           ElementListPopup (element_l);
           break;

       case Generate:
           GenerateElements ();
	   break;

       case DefMaterial:
           MaterialDialogPopup (material_d);
	   break;

       case OpenMaterial:
           OpenMaterialFile ();
	   break;

       case SaveMaterial:
           WriteMaterialFile ();
	   break;

       case ApplyMaterial:
           EditApplyMaterial ();
           break;

       case ApplyForce:
	   EditApplyForce ();
	   break;

       case ApplyLoad:
	   EditApplyLoad ( );
	   break;

       case ApplyConstraint:
	   EditApplyConstraint ();
	   break;

       case DefForce:
           ForceDialogPopup (force_d);
	   break;

       case DefLoad:
           LoadDialogPopup (load_d);
	   break;

       case DefConstraint:
           ConstraintDialogPopup (constraint_d);
	   break;

       case Define:
           SolutionDialogPopup (solution_d);
           break;

       case Solve:
	   CompactOperation (NULL);
           break;

       case PlotStress:
           SetupStresses (True);
           break;

       case PlotStructure:
           SetupStructure (True);
           break;

       case Configure:
           CanvasDialogPopup (canvas_d);
	   break;

       case ZoomOut:
           ZoomAll ();
           break;

       case ZoomIn:
           ZoomStart ();
           break;
 
       case SaveXWD:
           SaveWidgetXWD (drawing);
           break;

       case NodeNumbersOnOff:
           ToggleNodeNumberStatus ();
           break;

       case EltNumbersOnOff:
           ToggleEltNumberStatus ();
           break;

       case SnapOnOff:
           ToggleSnapStatus ();
           break;

       case GridOnOff:
           ToggleGridStatus ();
           break;

       case LineTool:
           ToolsDrawLine ();
	   break;

       case Circle:
           ToolsDrawCircle ();
	   break;

       case Arc:
           ToolsDrawArc ();
	   break;

       case Rectangle:
           ToolsDrawRectangle ();
	   break;

       case Polygon:
           ToolsDrawPolygon ();
	   break;

       case Text:
	   ToolsDrawText ();
           break;

       case DeleteTool:
	   ToolsDeleteFigure ();
           break;

       case NewId:
           StartNew ();
	   break;

       case Open:
           OpenFile ();
	   break;

       case Save:
	   if (!filename [0])
	      WriteNamedFile ();
	   else {
              if (!WriteVFeltFile ()) {
                 WriteVelvetFile ();
	 	 changeflag = False;
	      }
	   }
	   break;

       case SaveAs:
           WriteNamedFile ();
	   break;

       case Restore:
           RestoreOriginal ();
	   break;

       case Exit:
           QuitVelvet ();
           break;

       case Info:
	   PopupDialog (info_dialog, "Velvet v1.3 copyright 1993 by\nJason I. Gobat (jgobat@ucsd.edu) and\nDarren C. Atkinson (atkinson@ucsd.edu)", 
                        NULL, NULL);
	   break;

       case Quit:
       case Abort:
	   break;

       } /* end switch top of control panel */

    } /* end if !edit_mode */
  
    else {

       switch (*(PanelId *) clientData) {
       case SnapOnOff:
           ToggleSnapStatus ();
           break;

       case GridOnOff:
           ToggleGridStatus ();
           break;

       case NodeNumbersOnOff:
           ToggleNodeNumberStatus ();
           break;

       case EltNumbersOnOff:
           ToggleEltNumberStatus ();
           break;

       default:
           XBell (XtDisplay (toplevel), 20);

       } /* end switch bottom of control panel */
    }
}


/************************************************************************
 * Function:	SelectCallback
 ************************************************************************/

void SelectCallback (w, clientData, callData)
    Widget    w;
    XtPointer clientData;
    XtPointer callData;
{
    DrawingReport   *report;
    FigureAttributes attributes;
    Figure           figure;
    Node             node;
    Element          element;
    Drawn            drawn;


    report = (DrawingReport *) callData;

    if (report -> event -> type != ButtonPress)
	return;

    figure = DW_FindFigure (w, report -> unsnapped.x, report -> unsnapped.y);

    if (figure == NULL)
	return;

    DW_GetAttributes (w, figure, &attributes);
    if (attributes.user_data == NULL)
	return;

    node = (Node) attributes.user_data;
    element = (Element) attributes.user_data;
    drawn = (Drawn) node -> aux;

    if (drawn -> type == DrawnNode) {
        if (report -> event -> xbutton.button == 1) {
	   NodeDialogDisplay (node_d, node);
	   NodeDialogPopup (node_d);
	} else if (report -> event -> xbutton.button == 2)
	   DoMoveNode (node, True);
        else if (report -> event -> xbutton.button == 3) {
	   NodeDialogDisplay (node_d, node);
	   NodeDialogPopup (node_d);
	}
    } else if (drawn -> type == DrawnElement) {
        if (report -> event -> xbutton.button != 2) {
	    ElementDialogDisplay (element_d, element);
	    ElementDialogPopup (element_d);
	}
    }
}


static XrmOptionDescRec options [ ] = {
    {"-sensitive",    "*sensitiveMenus", XrmoptionNoArg, "True"},
    {"+sensitive",    "*sensitiveMenus", XrmoptionNoArg, "False"},
    {"-numbers",      "*numbers",        XrmoptionNoArg, "True"},
    {"+numbers",      "*numbers",        XrmoptionNoArg, "False"},
    {"-nodeColor",    "*nodeColor",      XrmoptionSepArg, NULL},
    {"-elementColor", "*elementColor",   XrmoptionSepArg, NULL},
    {"-toolColor",    "*toolColor",      XrmoptionSepArg, NULL},
    {"-labelFont",    "*labelFont",      XrmoptionSepArg, NULL},
    {"-toolFont",     "*toolFont",       XrmoptionSepArg, NULL},
};

struct resources {
    Boolean sensitive;
    Boolean numbers;
    String  nodecolor;
    String  elementcolor;
    String  toolcolor;
    String  labelfont;
    String  toolfont;
} appResources;

# define offset(field) XtOffsetOf (struct resources, field)
static XtResource Resources [ ] = {
{"sensitiveMenus", "SensitiveMenus", XtRBoolean, sizeof (Boolean),
    offset (sensitive), XtRImmediate, (XtPointer) True},
{"numbers", "Numbers", XtRBoolean, sizeof (Boolean),
    offset (numbers), XtRImmediate, (XtPointer) True},
{"nodeColor", "NodeColor", XtRString, sizeof (String),
    offset (nodecolor), XtRImmediate, (XtPointer) "blue"},
{"elementColor", "ElementColor", XtRString, sizeof (String),
    offset (elementcolor), XtRImmediate, (XtPointer) "black"},
{"toolColor", "ToolColor", XtRString, sizeof (String),
    offset (toolcolor), XtRImmediate, (XtPointer) "red"},
{"labelFont", "LabelFont", XtRString, sizeof (String),
    offset (labelfont), XtRImmediate, (XtPointer) "5x8"},
{"toolFont", "ToolFont", XtRString, sizeof (String),
    offset (toolfont), XtRImmediate, (XtPointer) "fg-22"},
};
# undef offset


static void GetArgs ( )
{
    XtGetApplicationResources (toplevel, &appResources, Resources,
				XtNumber (Resources), NULL, 0);

    sensitive_menus = appResources.sensitive;
    canvas -> node_color      = appResources.nodecolor;
    canvas -> element_color   = appResources.elementcolor;
    canvas -> tool_color      = appResources.toolcolor;
    canvas -> label_font      = appResources.labelfont;
    canvas -> tool_font       = appResources.toolfont;
    canvas -> node_numbers    = appResources.numbers;
    canvas -> element_numbers = appResources.numbers;
}


/************************************************************************
 * Function:	 main							*
 *									*
 * Parameters:	 argc - number of command line arguments		*
 *		 argv - array of command line arguments			*
 *									*
 * Return value: 0 on success; nonzero on error				*
 *									*
 * Calls:	 ???							*
 *									*
 * Called by:	 none							*
 *									*
 * Global data:	 ???							*
 *									*
 * Description:	 Main is the startup function for the velvet program.	*
 ************************************************************************/

int main (argc, argv)
    int   argc;
    char *argv [ ];
{
    int		   i, j;
    char	   string [32];
    Arg		   arglist [14];
    Dimension	   width;
    Dimension      height;
    float	   xscale;
    float     	   yscale;
    Cardinal	   count;
    XtTranslations trans;
    Window	   window;
    Pixmap	   icon_pixmap;
    Pixmap 	   question;
    Pixmap 	   menu16;
    Pixmap	   popup;
    Widget	   form,
                   control,
                   bottom;
    Widget	   coord;
    static String  error_buttons [ ]   = {"okay"};
    static String  output_buttons [ ]  = {"dismiss", "save"};
    static String  proceed_buttons [ ] = {"okay", "cancel"};
    static String  qsave_buttons [ ]   = {"yes", "no", "cancel"};

    /* Create the top level widgets. */

    toplevel = XtAppInitialize (&app_context, "Velvet", options,
		XtNumber (options), &argc, argv, defaults, NULL, 0);

    icon_pixmap = XCreateBitmapFromData (XtDisplay (toplevel),
                      RootWindowOfScreen (XtScreen (toplevel)),
                      FElt_bits, FElt_width, FElt_height);

    XtSetArg (arglist [0], XtNiconPixmap, icon_pixmap);
    XtSetValues (toplevel, arglist, 1);

    form     = XtCreateManagedWidget
		("form", formWidgetClass, toplevel, NULL, 0);

    control  = XtCreateManagedWidget
		("control", formWidgetClass, form, NULL, 0);

    viewport = XtCreateManagedWidget
		("viewport", viewportWidgetClass, form, NULL, 0);

    drawing  = XtCreateManagedWidget
		("drawing", drawingWidgetClass, viewport, NULL, 0);

    coord    = XtCreateManagedWidget
		("coord", labelWidgetClass, form, NULL, 0);

    bottom   = XtCreateManagedWidget
		("bottom", formWidgetClass, form, NULL, 0);

    status   = XtCreateManagedWidget
		("status", labelWidgetClass, bottom, NULL, 0);

    count = 0;
    XtSetArg (arglist [count], XtNeditType, XawtextEdit); count ++;

    entry    = XtCreateManagedWidget
		("entry", asciiTextWidgetClass, bottom, arglist, count);


    /* Focus all keyboard input to the text entry widget. */

    XtSetKeyboardFocus (form, entry);


    /* Create the bitmaps. */

    window = RootWindowOfScreen (XtScreen (toplevel));
    checkmark = XCreateBitmapFromData (XtDisplay(toplevel), window,
				        check_bits, check_width, check_height);

    question = XCreateBitmapFromData (XtDisplay (toplevel), window,
			        question_bits, question_width, question_height);

    menu16 = XCreateBitmapFromData (XtDisplay (toplevel), window,
				    menu16_bits, menu16_width, menu16_height);

    popup  = XCreateBitmapFromData (XtDisplay (toplevel), window,
				    popup_bits, popup_width, popup_height);


    /* Create the control panel menus and buttons. */

    for (i = 0; i < XtNumber (panel); i ++) {
        count = 0;
	if (panel [i].class == &menuButtonWidgetClass) {
	    XtSetArg (arglist [0], XtNleftBitmap, menu16); count++;
        }
	else if (strcmp(panel [i].name,"info") == 0) {
	    XtSetArg (arglist [0], XtNleftBitmap, question); count++;
        }
	else if (strcmp(panel [i].name,"materials_d") == 0) {
	    XtSetArg (arglist [0], XtNleftBitmap, popup); count++;
        }
	else if (strcmp(panel [i].name,"forces_d") == 0) {
	    XtSetArg (arglist [0], XtNleftBitmap, popup); count++;
        }
	else if (strcmp(panel [i].name,"loads_d") == 0) {
	    XtSetArg (arglist [0], XtNleftBitmap, popup); count++;
        }
	else if (strcmp(panel [i].name,"constraints_d") == 0) {
	    XtSetArg (arglist [0], XtNleftBitmap, popup); count++;
        }
	else if (panel [i].class != &commandWidgetClass) {
	    XtSetArg (arglist [0], XtNlabel, ""); count++;
        }

	panel [i].button = XtCreateManagedWidget (panel [i].name,
                                 *panel [i].class,control,arglist, count);

	if (panel [i].class == &menuButtonWidgetClass) {
	    sprintf (string, "%sMenu", panel [i].name);
	    panel [i].menu = XtCreatePopupShell
			     (string, simpleMenuWidgetClass, control, NULL, 0);

	    for (j = 0; j < panel [i].numentries; j ++) {
		panel [i].menuentry [j].widget = XtCreateManagedWidget
		 (panel [i].menuentry [j].name, smeBSBObjectClass,
		  panel [i].menu, NULL, 0);

		XtAddCallback (panel [i].menuentry [j].widget, XtNcallback,
		 PanelCallback, &panel [i].menuentry [j].id);
	    }

	} else if (panel [i].class == &commandWidgetClass)
	    XtAddCallback (panel [i].button, XtNcallback, PanelCallback,
	     &panel [i].menuentry [0].id);
    }

    quitbutton = XtCreateManagedWidget ("quit", commandWidgetClass,
                      control, NULL, 0);
    XtAddCallback (quitbutton, XtNcallback, QuitEdit, NULL);

    abortbutton = XtCreateManagedWidget ("abort", commandWidgetClass,
                      control, NULL, 0);
    XtAddCallback (abortbutton, XtNcallback, AbortEdit, NULL);
 

    /* Create the canvas configuration so we can do the args */

    canvas_d     = CanvasDialogCreate (toplevel, drawing, 
                                       "canvasDialog", "Canvas");

    GetArgs ( );


    /* Create the dialogs. */

    info_dialog    = CreateDialog (toplevel, "infod", Okay);

    filed          = FileDialogCreate (toplevel, "fileDialog"); 

    error_dialog   = OutputDialogCreate (toplevel, "errorDialog",
                          error_buttons, XtNumber (error_buttons));
    proceed_dialog = OutputDialogCreate (toplevel, "proceedDialog",
                          proceed_buttons, XtNumber (proceed_buttons));
    qsave_dialog   = OutputDialogCreate (toplevel, "qsaveDialog",
                          qsave_buttons, XtNumber (qsave_buttons));
    output_dialog  = OutputDialogCreate (toplevel, "outputDialog",
                          output_buttons, XtNumber (output_buttons));

    XtSetArg (arglist [0], XtNicon, icon_pixmap);
    XtSetValues (info_dialog -> dialogwidget, arglist, 1);

    element_l    = ElementListCreate (toplevel, "elementList", "Element Type");

    solution_d   = SolutionDialogCreate (toplevel, "solutionDialog",
		   "Solutions");

    element_d	 = ElementDialogCreate (toplevel, "elementDialog",
		   "Elements", ElementDialogChanged, (XtPointer) NULL);

    node_d	 = NodeDialogCreate (toplevel, "nodeDialog",
		   "Nodes", NodeDialogChanged, (XtPointer) element_d);

    load_d       = LoadDialogCreate (toplevel, "loadDialog",
		   "Loads", LoadDialogChanged, (XtPointer) element_d);

    material_d   = MaterialDialogCreate (toplevel, "materialDialog",
		   "Materials", MaterialDialogChanged, (XtPointer) element_d);

    constraint_d = ConstraintDialogCreate (toplevel, "constraintDialog",
		   "Constraints", ConstraintDialogChanged, (XtPointer) node_d);

    force_d      = ForceDialogCreate (toplevel, "forceDialog",
		   "Forces", ForceDialogChanged, (XtPointer) node_d);


    /* register the action table and set-up the translations */

    XtAppAddActions (app_context, actiontable, XtNumber (actiontable));
    trans = XtParseTranslationTable (default_translations);

    XtOverrideTranslations (entry, trans);


    /* Realize the top level widget */

    XtRealizeWidget (toplevel);

    /* Configure the drawing widget */

    count = 0;
    XtSetArg (arglist [count], XtNheight, &height); count++;
    XtSetArg (arglist [count], XtNwidth, &width); count++;
    XtGetValues (drawing, arglist, count);

    canvas -> xmin         = 0.0;
    canvas -> xmax         = 10.0;
    canvas -> ymin         = 0.0;
    canvas -> ymax         = 10.0;
    canvas -> grid_size    = 1.0;
    canvas -> snap_size    = 0.25;
    canvas -> snap         = False;
    canvas -> grid         = False;

    xscale = (float) width / (canvas -> xmax - canvas -> xmin);
    yscale = (float) height / (canvas -> ymax - canvas -> ymin);

    count = 0;
    XtSetArg (arglist [count], XtNxScale, Float2Arg (xscale)); count++;
    XtSetArg (arglist [count], XtNyScale, Float2Arg (yscale)); count++;
    XtSetArg (arglist [count], XtNcoordinates, coord); count++;
    XtSetValues (drawing, arglist, count); 

    CanvasDialogSet (canvas_d);

    /* Configure the initial solution parameters */

    solution -> felt = True;
    solution -> stress = False;
    solution -> structure = False;
    solution -> magnify = 100.0;
    solution -> component = 1;
    solution -> equalize = True;
    solution -> zscale = 0.2;
    solution -> title = NULL;
    solution -> xrot = 40.0;
    solution -> yrot = -20.0;
    solution -> zrot = 0.0;

    SolutionDialogUpdate (solution_d);

    /* Initialize the element and node arrays */

    node = NULL;
    element = NULL;
    numnodes = 0;
    numelts = 0;

    /* check to see if the user started with a filename */

    StartNew ( );
    if (argc > 1) {
       if (access (argv[1], F_OK) == 0) {
          if (access (argv[1], R_OK) != 0)
             error ("File %s is not accessible, check file permissions.",
                    argv[1]);
          else {
	     strcpy (filename, argv [1]);
             ReadFeltFile (); 
             ReadVelvetFile ();
          }
       }
       else
	  strcpy (filename, argv [1]);
    }
    else 
       filename [0] = 0;
    
    UpdateFilenameDisplay ();
    SetNormalMode ( );
    canvas -> node_numbers = !canvas -> node_numbers;
    canvas -> element_numbers = !canvas -> element_numbers;
    ToggleNodeNumberStatus ( );
    ToggleEltNumberStatus ( );

    /* Enter the main event loop */

    changeflag = False;
    XtAppMainLoop (app_context);

    return 0; /* NOTREACHED */
}
