/**
*** 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 <X11/StringDefs.h>
#include <X11/Intrinsic.h> 
#include <X11/Shell.h>
#include <X11/cursorfont.h>
#include <Xm/Xm.h>
#include <Xm/SelectioB.h>
#include "xpg.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



void browseArrayField();
int  popupArrayBroswer();
void popdownArrayBroswer();
void arrayElemSelected1();
void arrayElemSelected2();
void arrayElemSelected3();
void execRegularAction();


/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void browseArrayField(w, rel, cbs)
  Widget w;
  relInfo *rel;
  XmListCallbackStruct *cbs;
{
    int i,  field = -1;
    PortalBuffer *p;
    char *val, *valDup, *tokStart, *tokEnd;
    int len;
    XmString compStr;
    Widget list;
    int numItems;
    int braceCnt;
    Boolean endReached;

    if (rel->arrayName == NULL)
	return;
    for (i=ATTR_1ST(rel);  i<rel->numFields;  i++)
	if (!strcmp(rel->attrInfo[i].name, rel->arrayName))
	{
	    field = i;
	    break;
	}
    XtVaGetValues(rel->arraySh, XmNlistItemCount, &numItems, NULL);
    list = XmSelectionBoxGetChild(rel->arraySh, XmDIALOG_LIST);
    if (numItems > 0)
	XmListDeleteAllItems(list);
    compStr = XmStringCreateSimple("");
    XtVaSetValues(rel->arraySh, XmNtextString, compStr, NULL);
    XmStringFree(compStr);
    if (field == -1)
	return;     /* array name is invalid (should also close the viewer) */
    if ((p = PQparray(rel->portal)) == NULL)
	return;
    if ((val = PQgetvalue(p, cbs->item_position-1, field)) == NULL)
    {
	status(rel, "Array is empty");
	return;
    }
    if (((len = strlen(val)) < 2) || val[0]!='{' || val[len-1]!='}')
    {
	status(rel, "Not an array!");
	return;      /* should also close the viewer */
    }
    /* parse the array's contents */
    valDup = (char *)malloc(sizeof(char) * len);
    strncpy(valDup, val+1, len-2);     /*  skip the '{' and '}' */
    valDup[len-2] = '\0';
    endReached = False;
    braceCnt = 0;
    tokStart = valDup;
    while (! endReached)
    {
	tokEnd = tokStart;
	for (;  (*tokEnd!='\0' && (*tokEnd!=',' || braceCnt!=0));  tokEnd++)
	{
	    if (*tokEnd == '{')
		braceCnt++;
	    else if (*tokEnd == '}')
		braceCnt--;
	}
	if (braceCnt != 0)
	{
	    status(rel, "Array is corrupted: unbalanced number of braces!");
	    free(valDup);
	    return;       /* maybe it isn't even possible, but anyway */
	}
	if (*tokEnd == '\0')
	    endReached = True;
	else
	    *tokEnd = '\0';
	compStr = XmStringCreateSimple(tokStart);
	XmListAddItemUnselected(list, compStr, 0);
	XmStringFree(compStr);
	tokStart = tokEnd + 1;     /* go for next token */
    }
    free(valDup);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
int  popupArrayBroswer(rel, attr)
  relInfo *rel;
  char *attr;
{
    XmString compStr;
    Widget list, but;
    int numItems;
    int n;
    Arg wargs[5];
    
    if (rel->arrayName)
	free(rel->arrayName);
    rel->arrayName = strdup(attr);
    if (rel->arraySh == NULL)
    {
	n=0;
	XtSetArg(wargs[n], XmNautoUnmanage, False); n++;
	rel->arraySh = XmCreateSelectionDialog(rel->top,"arrayList",wargs,n);
	setWidgetPos(XtParent(rel->arraySh), rel->top, 0.8, 0, 0.8, 0);
	compStr = XmStringCreateSimple("CLOSE VIEWER");
	XtVaSetValues(rel->arraySh,
		      XmNdialogStyle, XmDIALOG_MODELESS,
		      XmNmustMatch, False,
		      XmNokLabelString,     rel->res.arrayCmdName1,
		      XmNapplyLabelString,  rel->res.arrayCmdName2,
		      XmNcancelLabelString, rel->res.arrayCmdName3,
		      XmNhelpLabelString,   compStr,
		      NULL);
	XmStringFree(compStr);
	XtVaSetValues(XtParent(rel->arraySh), XmNtransient, False, NULL);
	XtAddCallback(rel->arraySh, XmNokCallback, arrayElemSelected1,rel);
	XtAddCallback(rel->arraySh, XmNapplyCallback, arrayElemSelected2,rel);
	XtAddCallback(rel->arraySh, XmNcancelCallback, arrayElemSelected3,rel);
	XtAddCallback(rel->arraySh, XmNhelpCallback, popdownArrayBroswer, rel);
	but = XmSelectionBoxGetChild(rel->arraySh, XmDIALOG_OK_BUTTON);
	if (!strcmp(rel->res.arrayCmd1, ""))
	    XtUnmanageChild(but);
	but = XmSelectionBoxGetChild(rel->arraySh, XmDIALOG_APPLY_BUTTON);
	if (!strcmp(rel->res.arrayCmd2, ""))
	    XtUnmanageChild(but);
	but = XmSelectionBoxGetChild(rel->arraySh, XmDIALOG_CANCEL_BUTTON);
	if (!strcmp(rel->res.arrayCmd3, ""))
	    XtUnmanageChild(but);
    }
    compStr = XmStringCreateSimple(attr);
    XtVaSetValues(rel->arraySh, XmNlistLabelString, compStr, NULL);
    XmStringFree(compStr);
    compStr = XmStringCreateSimple("");
    XtVaSetValues(rel->arraySh, XmNtextString,      compStr, NULL);
    XmStringFree(compStr);
    XtVaGetValues(rel->arraySh, XmNlistItemCount, &numItems, NULL);
    list = XmSelectionBoxGetChild(rel->arraySh, XmDIALOG_LIST);
    if (numItems > 0)
	XmListDeleteAllItems(list);
    XtManageChild(rel->arraySh);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void popdownArrayBroswer(w, rel, cbs)
  Widget w;
  relInfo *rel;
  XtPointer cbs;
{
    XtUnmanageChild(rel->arraySh);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void arrayElemSelected1(w, rel, cbs)
  Widget w;
  relInfo *rel;
  XmSelectionBoxCallbackStruct *cbs;
{
    char *val, *valPtr;
    
    XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &val);
    valPtr = val;
    if (val[0] == '\"')
    {
	val[strlen(val)-1] = '\0';
	valPtr++;
    }
    if (!strcmp(valPtr, ""))
    {
	XtFree(valPtr);
	return;
    }
    if (rel->res.arrayCmd1[0] == '|')
	getLargeObj(valPtr, rel->res.arrayCmd1);
    else
	execRegularAction(valPtr, rel->res.arrayCmd1, 
			  rel->res.arrayCmdPath1);
    XtFree(val);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void arrayElemSelected2(w, rel, cbs)
  Widget w;
  relInfo *rel;
  XmSelectionBoxCallbackStruct *cbs;
{
    char *val, *valPtr;
    
    XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &val);
    valPtr = val;
    if (val[0] == '\"')
    {
	val[strlen(val)-1] = '\0';
	valPtr++;
    }
    if (!strcmp(valPtr, ""))
    {
	XtFree(valPtr);
	return;
    }
    if (rel->res.arrayCmd2[0] == '|')
	getLargeObj(valPtr, rel->res.arrayCmd2);
    else
	execRegularAction(valPtr, rel->res.arrayCmd2, 
			  rel->res.arrayCmdPath2);
    XtFree(val);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void arrayElemSelected3(w, rel, cbs)
  Widget w;
  relInfo *rel;
  XmSelectionBoxCallbackStruct *cbs;
{
    char *val, *valPtr;
    
    XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &val);
    valPtr = val;
    if (val[0] == '\"')
    {
	val[strlen(val)-1] = '\0';
	valPtr++;
    }
    if (!strcmp(valPtr, ""))
    {
	XtFree(valPtr);
	return;
    }
    if (rel->res.arrayCmd3[0] == '|')
	getLargeObj(valPtr, rel->res.arrayCmd3);
    else
	execRegularAction(valPtr, rel->res.arrayCmd3, 
			  rel->res.arrayCmdPath3);
    XtFree(val);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void execRegularAction(name, cmd, path)
  char *name, *cmd, *path;
{
    if (!fork())
    {
	char *buf, *pholder, *ptr, *bufP;
	char *preCmd = "chdir";
	int size;
	int numPholder = 0;
	
	
	/* buf will be: "<preCmd> <path>; <cmd>... <name> ...<cmd>"
	   where <name> replaces the appearances of the VAL_PHOLDER
	   string inside <cmd>. */
	
	for(ptr=cmd; (ptr=strstr(ptr, VAL_PHOLDER))!=NULL; 
	    ptr+=strlen(VAL_PHOLDER))
	    numPholder++;
	size = strlen(preCmd) + strlen(path) + 4 + numPholder*strlen(name) + 
	    strlen(cmd);
	if ((buf = (char *)malloc(size)) == NULL)
	    XtError("Out of memory!");
	sprintf(buf, "%s %s; ", preCmd, path);
	bufP = buf+strlen(buf);
	for(ptr=cmd; (pholder=strstr(ptr, VAL_PHOLDER))!=NULL; 
	    ptr=pholder+strlen(VAL_PHOLDER))
	{
	    strncpy(bufP, ptr, pholder-ptr);
	    bufP += pholder-ptr;
	    strcpy(bufP, name);
	    bufP += strlen(name);
	}
	strcat(bufP, ptr);
#ifdef XPG_DEBUG
	printf("%d %% app, Buf: %s\n", numPholder, buf);
#endif
	system(buf);
	exit(0);
    }
}
