/**
*** 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 <string.h>
#include <varargs.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/Label.h>
#include <Xm/LabelG.h>
#include <Xm/Text.h>
#include <Xm/Command.h>
#include <Xm/PanedW.h>
#include <Xm/RowColumn.h>
#include "xpg.h"
#include "lib.h"

#define String JUST_A_DUMB_STRING
#include "tmp/libpq.h"       /* postgres */
#undef String

#ifdef MEM_DEBUG
#include "/CS/system/ranen/Src/Lib/Malloc/malloc.h"
#endif

extern void _XEditResCheckMessages();     /* for editres */

extern XtAppContext app;
extern Widget toplevel;


char   *execAndWarn();
void   helpView();
char   *skipSpaces();
char   *createUniqueName();
void   popupExecDialog();
void   popdownExecDialog();
Widget createExecDialog();
void   execCloseCB();
void   execClearCmdCB();
void   execPopupLogCB();
void   execCommandEntered();
void   popupLogDialog();
void   popdownLogDialog();
Widget createLogDialog();
void   logCloseCB();
void   logClearMsgCB();
void   logText();


Widget execDialog=NULL, execCommand, logDialog=NULL, logTextW;
Boolean execTransactionBlock = False;



/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void popupExecDialog(rel)
  relInfo *rel;
{
    permStruct perms;
    
    setBusy(rel, BUSY);
    checkPermissions(rel, "!@#$#%$#%-impossible_name", &perms);
    if (!perms.append || !perms.read || !perms.write || !perms.rules)
    {
	warn(rel->top, "You do not have full access permissions to this database.\nAccess to the Execute Commands dialog denied");
	setBusy(rel, NOBUSY);
	return;
    }
    if (logDialog == NULL)         /* we need it to log our commands */
	createLogDialog(toplevel);
    if (execDialog == NULL)
	createExecDialog(toplevel);
    XtPopup(execDialog, XtGrabNone);  
    setBusy(rel, NOBUSY);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void popdownExecDialog()
{
    XtPopdown(execDialog);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
static Widget createExecDialog(parent)
  Widget parent;
{
    Widget dialog, pane, text, command, label, rowcol;
    Arg args[10];
    static ActionAreaItem actionArea[] = {
      { NULL, "Close",           execCloseCB,    NULL, True, False},
      { NULL, "Clear\nCommands", execClearCmdCB, NULL, True, False},
      { NULL, "View\nLog",       execPopupLogCB, NULL,  True, False}};

    dialog = XtCreatePopupShell("execDialog", topLevelShellWidgetClass, 
                                parent, NULL, 0);
    execDialog = dialog;
    XtVaSetValues(dialog, XmNdeleteResponse, XmUNMAP, NULL);
    pane = XtVaCreateWidget("execPane", xmPanedWindowWidgetClass, dialog, 
			    XmNsashWidth,  1,
                            XmNsashHeight, 1,
                            NULL);
    XtAddCallback(pane, XmNhelpCallback, helpView, "the Execute dialog");
    
    label = XtVaCreateManagedWidget("execHistoryLabel", xmLabelGadgetClass, 
				    pane, 
				    XmNalignment, XmALIGNMENT_BEGINNING,
				    NULL);
    paneSetFixSize(label);

    command = XmCreateCommand(pane, "execCommand", NULL, 0);
    execCommand = command;
    XtAddCallback(command,XmNcommandEnteredCallback,execCommandEntered,NULL);

    CreateActionArea(pane, actionArea, XtNumber(actionArea));

    XtManageChild(command);
    XtManageChild(pane);
    return dialog;
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void execCloseCB(w, data, cbs)
  Widget w;
  XtPointer data, cbs;
{
    if (execTransactionBlock)
    {
	warn(GetTopShell(w), "You are inside a begin/end transaction!\nYou must end the transaction first");
	return;
    }
    popdownExecDialog();
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void execClearCmdCB(w, data, cbs)
  Widget w;
  XtPointer data, cbs;
{
    XtVaSetValues(execCommand, XmNhistoryItemCount, 0, NULL);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void execPopupLogCB(w, clientData, cbs)
  Widget w;
  XtPointer clientData;
  XtPointer cbs;
{
    popupLogDialog(NULL);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
static void execCommandEntered(w, clientData, cbs)
  Widget w;
  XtPointer clientData;
  XmCommandCallbackStruct *cbs;
{
    char *cmd;
    char *ans, *tmp, buf[BUFSIZ], *name;
    XmString compStr;
    
    setCursor(execDialog, XC_watch);
    XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &cmd);
    cmd = skipSpaces(cmd);
    logText(True, "%s", cmd);
    logText(False,"\n");
    XmUpdateDisplay(logDialog);
    /* check for begin/end commands */
    if (!strncmp(cmd, "begin", 5))
	execTransactionBlock = True;
    if (!strncmp(cmd, "end", 3))
	execTransactionBlock = False;
    /* check for a retrieve command which target is the blank portal */
    if (!strncmp(cmd, "retrieve", 8) && ((*(tmp=skipSpaces(cmd+8))=='(') || 
					 !strncmp(tmp, "unique", 6)))
    {
	if (!execTransactionBlock)  /* 'cause we're gonna use a named portal */
	    xpgPQexec("begin");
	sprintf(buf, "retrieve portal %s%s", name=createUniqueName("xpg_tmp"), 
		cmd+8);
	logText(False, "xpg note: retrieving into portal '%s'\n", name);
	ans = execAndWarn(GetTopShell(w), buf, NULL);
	logText(False, "%s\n", ans+1);
	sprintf(buf, "fetch all in %s", name);
	execAndWarn(GetTopShell(w), buf, "Fetch failed!");
	if (!execTransactionBlock)  /* restore to previous state */
	    xpgPQexec("end");
	if (ans[0] != 'R')
	    openView(NULL, name);
    }
    else
    {
	ans = execAndWarn(GetTopShell(w), cmd, NULL);
	logText(False, "%s\n", ans+1);
    }
/*
    if (ans[0] == 'R')
    {
	compStr = XmStringCreateLtoR(ans+1, XmSTRING_DEFAULT_CHARSET);
	XmCommandError(execCommand, compStr);
	XmStringFree(compStr);
    }
*/
    XtFree(cmd);
    setCursor(execDialog, None);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void popupLogDialog(rel)
  relInfo *rel;
{
    if (rel)
	setBusy(rel, BUSY);
    if (logDialog == NULL)
	createLogDialog(toplevel);
    XtPopup(logDialog, XtGrabNone);  
    if (rel)
	setBusy(rel, NOBUSY);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void popdownLogDialog()
{
    XtPopdown(logDialog);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
static Widget createLogDialog(parent)
  Widget parent;
{
    Widget dialog, pane, text, label;
    Arg args[10];
    static ActionAreaItem actionArea[] = {
      { NULL, "Close",           logCloseCB,    NULL, True, False},
      { NULL, "Clear\nMessages", logClearMsgCB, NULL, True, False}};

    dialog = XtCreatePopupShell("logDialog", topLevelShellWidgetClass, 
                                parent, NULL, 0);
    logDialog = dialog;
    XtVaSetValues(dialog, XmNdeleteResponse, XmUNMAP, NULL);
    pane = XtVaCreateWidget("logPane", xmPanedWindowWidgetClass, dialog, 
			    XmNsashWidth,  1,
			    XmNsashHeight, 1,
                            NULL);
    XtAddCallback(pane, XmNhelpCallback, helpView, "the Log dialog");
    
    label = XtVaCreateManagedWidget("logTextLabel", xmLabelGadgetClass, pane,
				    XmNalignment, XmALIGNMENT_BEGINNING,
				    NULL);
    paneSetFixSize(label);

    XtSetArg(args[0],  XmNeditable,               False);
    XtSetArg(args[1],  XmNcursorPositionVisible,  False);
    XtSetArg(args[2],  XmNeditMode,               XmMULTI_LINE_EDIT);
    XtSetArg(args[3],  XmNwordWrap,               True);
    XtSetArg(args[4],  XmNscrollHorizontal,       False);
    XtSetArg(args[5],  XmNblinkRate,              0);
    XtSetArg(args[6],  XmNautoShowCursorPosition, True);
    text = XmCreateScrolledText(pane, "logText", args, 7);
    XtVaSetValues(text,	        /* this prevents user selections */
		  XmNselectionArrayCount,    0,
		  XmNselectThreshold,        10000,
		  NULL);
    logTextW = text;

    CreateActionArea(pane, actionArea, XtNumber(actionArea));

    XtManageChild(text);
    XtManageChild(pane);
    return dialog;
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void logCloseCB(w, data, cbs)
  Widget w;
  XtPointer data, cbs;
{
    popdownLogDialog();
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void logClearMsgCB(w, data, cbs)
  Widget w;
  XtPointer data, cbs;
{
    logText(False, NULL);   /* request to clear the text window */
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* based on Heller's wprint()
 * If highlight is True, the text following this argument (in a printf-like
 * fashion) is highlighted, otherwise it is displayed in the normal colors.
 * If the format string (the 2nd argument to this function) is NULL, logText()
 * clears the entire text window.
 */
void logText(highlight, va_alist)
  Boolean highlight;
  va_dcl
{
    char msgbuf[BUFSIZ]; /* we're not getting huge strings */
    char *fmt;
    static XmTextPosition wpr_position; /* maintain text position */
    int oldPos, len;
    va_list args;
    
    va_start(args);
    fmt = va_arg(args, char *);
    if (fmt)
	vsprintf(msgbuf, fmt, args);
    va_end(args);

    if (logDialog == NULL)         
	createLogDialog(toplevel);  /* no log dialog yet, so create it */

    if (fmt == NULL)     /* text-clear requested */
    {
	wpr_position = 0;
	XmTextSetString(logTextW, " ");  /* it crashed when it was "" !!! */
    }
    else                 /* adding text */
    {
	XmTextInsert(logTextW, wpr_position, msgbuf);
	oldPos = wpr_position;
	len = strlen(msgbuf);
	wpr_position += len;
	if (highlight)
	    XmTextSetHighlight(logTextW, oldPos, oldPos+len, 
			       XmHIGHLIGHT_SELECTED);
    }
    XtVaSetValues(logTextW, XmNcursorPosition, wpr_position, NULL);
    XmTextShowPosition(logTextW, wpr_position);
}
