/**
*** XPG - Graphical User Interface for Postgres
*** Copyright (C) 1993  Ranen Goren (ranen@cs.huji.ac.il).

*** 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.
**/


#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h> 
#include <X11/cursorfont.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Xm/LabelG.h>
#include <Xm/Text.h>
#include <Xm/List.h>
#include <Xm/MessageB.h>
#include <Xm/DialogS.h>
#include <Xm/PanedW.h>
#include "xpg.h"
#include "lib.h"
#include "Bitmaps/about.xbm"
#include "Bitmaps/question.xbm"



extern char *sys_errlist[];               /* for classHelp() */
extern int errno;
extern toplevel;


void classHelp();
void classHelpExit();
void aboutXpg();
void aboutXpgExit();
void helpView();
void createHelpView();
void helpViewOk();
void helpIndexCB();
Pixmap createIcon();
Widget GetTopShell();


String indexTitles[] = {
    "using this help",
    "xpg overview",
    "the viewer",
    "key attributes",
    "the Search dialog",
    "class operations",
    "printing",
    "scripts",
    "permissions",
    "math operations",
    "arrays",
    "class help",
    "the Execute dialog",
    "the Log dialog",
    "command-line switches",
    "xpg resources",
    "COPYRIGHT",
    "DONATIONS",
    "THANKS"
};

String indexFiles[] = {
    "using.olh",
    "overview.olh",
    "viewer.olh",
    "keys.olh",
    "search.olh",
    "class_ops.olh",
    "print.olh",
    "scripts.olh",
    "permissions.olh",
    "math_ops.olh",
    "array.olh",
    "class_help.olh",
    "execute.olh",
    "log.olh",
    "cmd_line.olh",
    "resources.olh",
    "copyright.olh",
    "donate.olh",
    "thanks.olh"
};



/* global widgets of the on-line help dialog */
Widget olhDialog, olhText, olhIndex;



/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void classHelp(rel)
  relInfo *rel;
{
    Widget sh, form, helpText, exitBut;
    char *filename = rel->res.helpFile;
    Arg arg[15];
    int n;
    char *text;
    FILE *fp;
    struct stat statb;
    
    if (rel->portal == NULL)
    {
	warn(rel->top, "No class in viewer!");
	return;
    }
    if (filename == NULL)
    {
	warn(rel->top, "Help not defined for this class");
	return;
    }
    if (stat(filename, &statb) == -1) 
    {
	warn(rel->top, "Error opening class help file: %s\n%s",
	     filename, sys_errlist[errno]);
	return;
    }
    if ((statb.st_mode & S_IFMT) != S_IFREG) {
	warn(rel->top, "Error opening class help file: %s\nNot a regular file",
	     filename);
	return;
    }
    if  (!(fp = fopen(filename, "r"))) {
	warn(rel->top, "Error opening class help file: %s\n%s",
	     filename, sys_errlist[errno]);
	return;
    }
    text = XtMalloc((unsigned)(statb.st_size+1));
    if (!fread(text, sizeof(char), statb.st_size+1, fp)) 
    {
	warn(rel->top, "Error reading class help file: %s\n%s",
	     filename, sys_errlist[errno]);
	fclose(fp);
	XtFree(text);
	return;
    }
    text[statb.st_size] = 0; /* be sure to NULL-terminate */
    fclose(fp);
    
    sh = XtVaCreatePopupShell("classHelpShell", topLevelShellWidgetClass, 
			      rel->top, NULL);
    form = XtVaCreateManagedWidget("classHelpForm", xmFormWidgetClass, sh,
				   NULL);
    XtAddCallback(form, XmNhelpCallback, helpView, "class help");

    n=0;
    XtSetArg(arg[n], XmNleftAttachment,   XmATTACH_FORM);    n++;
    XtSetArg(arg[n], XmNrightAttachment,  XmATTACH_FORM);    n++;  
    XtSetArg(arg[n], XmNbottomAttachment, XmATTACH_FORM);    n++;  
    exitBut = XtCreateManagedWidget("classHelpExitButton",
				    xmPushButtonWidgetClass,
				    form, arg, n);
    n=0;
    XtSetArg(arg[n], XmNeditable,         False);            n++;
    XtSetArg(arg[n], XmNcursorPositionVisible, False);       n++;
    XtSetArg(arg[n], XmNeditMode,         XmMULTI_LINE_EDIT);n++;
    XtSetArg(arg[n], XmNtopAttachment,    XmATTACH_FORM);    n++;
    XtSetArg(arg[n], XmNleftAttachment,   XmATTACH_FORM);    n++;
    XtSetArg(arg[n], XmNrightAttachment,  XmATTACH_FORM);    n++;  
    XtSetArg(arg[n], XmNbottomAttachment, XmATTACH_WIDGET);  n++;
    XtSetArg(arg[n], XmNbottomWidget,     exitBut);          n++;
    helpText = XmCreateScrolledText(form, "classHelpText", arg, n);
    XtAddCallback(exitBut, XmNactivateCallback, classHelpExit, sh);
    
    XmTextSetString(helpText, text);
    XtFree(text);
    XtManageChild(helpText);
    XtPopup(sh, XtGrabNone);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void classHelpExit(w, sh, cbs)
  Widget w, sh;
  XtPointer cbs;
{
    XtDestroyWidget(sh);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void aboutXpg(rel)
  relInfo *rel;
{
    Widget dialog;
    Arg wargs[10];
    int n;
    char text[200];
    XmString compStr;
    Pixmap icon;
    
    sprintf(text, "XPG\nVersion %s\nX/Motif interface to Postgres\n\nwritten 1993 by Ranen Goren\nranen@cs.huji.ac.il", VERSION);
    compStr = XmStringCreateLtoR(text, XmSTRING_DEFAULT_CHARSET);
    n=0;
    XtSetArg(wargs[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);  n++;
    XtSetArg(wargs[n], XmNmessageString, compStr);                        n++;
    XtSetArg(wargs[n], XmNmessageAlignment, XmALIGNMENT_CENTER);          n++;
    dialog = XmCreateMessageDialog(rel->top, "aboutXpg", wargs, n);
    icon = createIcon(dialog, about_bits, about_width, about_height);
    XtVaSetValues(dialog, XmNsymbolPixmap, icon, NULL);
    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
    XtAddCallback(dialog, XmNokCallback, aboutXpgExit, dialog);
    XtManageChild(dialog);
    XmStringFree(compStr);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void aboutXpgExit(dialog)
  Widget dialog;
{
    XtDestroyWidget(dialog);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void commandLineHelp()
{
    fprintf(stderr, 
"\nxpg version %s - written 1993 by Ranen Goren\n\n", VERSION);
    fprintf(stderr, 
"Command-line options:\n");
    fprintf(stderr, 
"    -db <database>          set the Postgres database\n");
    fprintf(stderr, 
"    -class <class>          view <class> upon startup\n");
    fprintf(stderr, 
"    -showPgClasses          allow viewing of catalog classes\n");
    fprintf(stderr, 
"    -hidePgClasses          hide catalog classes\n");
    fprintf(stderr, 
"    -key <attrs>            set <attrs> to be key attributes\n");
    fprintf(stderr, 
"    -printCmd <cmd>         set the printer command to <cmd>\n");
    fprintf(stderr, 
"    -autoSort               sort all viewed classes\n");
    fprintf(stderr, 
"    -noAutoSort             never sort classes by key attributes\n");
    fprintf(stderr, 
"    -floatPrecision <prec>  set FP display precision to <prec>.\n");
    fprintf(stderr, 
"                            negative value disables FP display formatting\n");
    fprintf(stderr, 
"    -help                   displays this help (as if you didn't know!)\n");
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Context-Sensitive Help
** (from Martin G C Davies, mgcd@se.alcbel.be)
*/
void ContextHelp(w, tag, callback_struct)
  Widget w;
  Opaque *tag;
  XmAnyCallbackStruct *callback_struct;
{
    static Cursor   context_cursor = NULL;
    Widget          context_widget, sh;
    
    sh = GetTopShell(w);

    if ( context_cursor == NULL )
        context_cursor = XCreateFontCursor(XtDisplay(sh), XC_question_arrow);
    
    context_widget = XmTrackingLocate(sh, context_cursor, FALSE ) ;
    
    if ( context_widget != NULL ) /* otherwise its not a widget */
    {
        XmAnyCallbackStruct cb ;
	
        cb.reason = XmCR_HELP ;
        cb.event = callback_struct->event ;
        /*
	 * If there's no help at this widget we'll track back
	 * up the hierarchy trying to find some.
	 */
	
        do
        {
            if ( ( XtHasCallbacks( context_widget, XmNhelpCallback ) ==
		  XtCallbackHasSome ) )
            {
                XtCallCallbacks( context_widget, XmNhelpCallback, & cb ) ;
                return ;
            }
            else
                context_widget = XtParent( context_widget ) ;
        } while ( context_widget != NULL ) ;
    }
    
    warn(sh, "No context-sensitive help found\nfor the selected object");
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
static void createHelpView(parent)
  Widget parent;
{
    Widget  pane, form, sep, widget, label;
    Widget pixLabel;
    extern void helpViewOk();
    Pixmap pixmap;
    Pixel fg, bg;
    Arg args[12];
    int i,n;
    XmString compStr;
    static ActionAreaItem actionArea[] = {
      { NULL, "Ok", helpViewOk, NULL, True, True}};
   

    olhDialog = XtVaCreatePopupShell("helpDialog",
				     topLevelShellWidgetClass, parent,
				     NULL);

    /* Create a PanedWindow to manage the stuff in this dialog. */
    pane = XtVaCreateWidget("helpPane", xmPanedWindowWidgetClass, olhDialog,
			    XmNsashWidth,  1,
			    XmNsashHeight, 1,
			    NULL);
    XtAddCallback(pane, XmNhelpCallback, helpView, "using this help");

    /* Create a RowColumn in the form for Label and Text widgets.
     * This is the control area.
     */
    form = XtVaCreateWidget("helpForm", xmFormWidgetClass, pane, NULL);

    pixmap = createIcon(form, question_bits, question_width, question_height);

    /* Create a label gadget using this pixmap */
    pixLabel = XtVaCreateManagedWidget("helpIcon", xmLabelGadgetClass, form,
				       XmNlabelType,        XmPIXMAP,
				       XmNlabelPixmap,      pixmap,
				       XmNrightAttachment,  XmATTACH_FORM,
				       XmNtopAttachment,    XmATTACH_FORM,
				       NULL);

    label = XtVaCreateManagedWidget("helpIndexLabel", xmLabelGadgetClass, form,
			    XmNleftAttachment,   XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
			    XmNbottomWidget,     pixLabel,
			    NULL);

    n=0;
    XtSetArg(args[n], XmNselectionPolicy,          XmBROWSE_SELECT); n++;
    XtSetArg(args[n], XmNlistSizePolicy,           XmVARIABLE);      n++;
    XtSetArg(args[n], XmNscrollingPolicy,          XmAUTOMATIC);     n++;
    XtSetArg(args[n], XmNscrollHorizontal,         False);           n++;
    XtSetArg(args[n], XmNleftAttachment,           XmATTACH_FORM);   n++;
    XtSetArg(args[n], XmNbottomAttachment,         XmATTACH_FORM);   n++;
    XtSetArg(args[n], XmNtopAttachment,            XmATTACH_WIDGET); n++;
    XtSetArg(args[n], XmNtopWidget,                label);           n++;
    olhIndex = XmCreateScrolledList(form, "helpIndex", args, n);
    for (i=0;  i < XtNumber(indexTitles);  i++)
    {
	compStr = XmStringCreateSimple(indexTitles[i]);
	XmListAddItemUnselected(olhIndex, compStr, 0);
	XmStringFree(compStr);
    }
    XtManageChild(olhIndex);
    
    XtSetArg(args[0], XmNscrollVertical,        True);
    XtSetArg(args[1], XmNscrollHorizontal,      False);
    XtSetArg(args[2], XmNeditMode,              XmMULTI_LINE_EDIT);
    XtSetArg(args[3], XmNeditable,              False);
    XtSetArg(args[4], XmNcursorPositionVisible, False);
    XtSetArg(args[5], XmNwordWrap,              True);
    olhText = XmCreateScrolledText(form, "helpText", args, 6);
    /* Attachment values must be set on the Text widget's PARENT,
     * the ScrolledWindow. This is the object that is positioned.
     */
    XtVaSetValues(XtParent(olhText),
        XmNleftAttachment,   XmATTACH_WIDGET,
        XmNleftWidget,       olhIndex,
        XmNtopAttachment,    XmATTACH_WIDGET,
        XmNtopWidget,        label,
        XmNrightAttachment,  XmATTACH_FORM,
        XmNbottomAttachment, XmATTACH_FORM,
        NULL);
    XtManageChild(olhText);
    XtManageChild(form);

    /* Create action area with the Ok button */
    CreateActionArea(pane, actionArea, XtNumber(actionArea));

    XtAddCallback(olhIndex, XmNbrowseSelectionCallback, helpIndexCB, NULL);
    XtManageChild(pane);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* label stands for the label in the index, as it is found in the
   indexTitles array. helpView() will view the help page for this
   index label. If label is NULL, helpView() will open the last help
   page viewed, and if there is no such page - the "using this help" 
   page. */
void helpView(w, label)
  Widget w;
  String label;
{
    int item_no;
    
    if (label == NULL)
	if (olhDialog != NULL)
	{
	    XtPopup(olhDialog, XtGrabNone);
	    return;
	}
	else
	    label = "using this help";
    for (item_no=1;  item_no <= XtNumber(indexTitles);  item_no++)
	if (!strcmp(label, indexTitles[item_no-1]))
	{
	    if (olhDialog == NULL)
		createHelpView(toplevel);
	    XmListSelectPos(olhIndex, item_no, True);
	    XtPopup(olhDialog, XtGrabNone);
	    break;
	}
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
static void helpIndexCB(w, clientData, cbs)
  Widget w;
  XtPointer clientData;
  XmListCallbackStruct *cbs;
{
    int itemPos = cbs->item_position - 1;
    char *text;
    struct stat statb;
    char filename[BUFSIZ];
    FILE *fp;

    sprintf(filename, "%s/%s", ONLINE_HELP_DIR, indexFiles[itemPos]);
    if (stat(filename, &statb) == -1) 
    {
	warn(olhDialog, "Error opening on-line help file: %s\n%s",
	     filename, sys_errlist[errno]);
	return;
    }
    if ((statb.st_mode & S_IFMT) != S_IFREG) {
	warn(olhDialog, 
	     "Error opening on-line help file: %s\nNot a regular file",
	     filename);
	return;
    }
    if  (!(fp = fopen(filename, "r"))) {
	warn(olhDialog, "Error opening on-line help file: %s\n%s",
	     filename, sys_errlist[errno]);
	return;
    }
    text = XtMalloc((unsigned)(statb.st_size+1));
    if (!fread(text, sizeof(char), statb.st_size+1, fp)) 
    {
	warn(olhDialog, "Error reading on-line help file: %s\n%s",
	     filename, sys_errlist[errno]);
	fclose(fp);
	XtFree(text);
	return;
    }
    text[statb.st_size] = 0; /* be sure to NULL-terminate */
    fclose(fp);

    XmTextSetString(olhText, text);
    XtFree(text);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void helpViewOk(widget)
  Widget widget;
{
    XtPopdown(olhDialog);
}
