/**
*** 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 <Xm/Xm.h>
#include <Xm/List.h>
#include <Xm/LabelG.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/PanedW.h>
#include <Xm/TextF.h>
#include "xpg.h"

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

enum actions
{
    SELECT,
    DESELECT,
    SELECT_ALL,
    DESELECT_ALL,
};


void helpView();


extern Widget toplevel;
XmStringCharSet charset = XmSTRING_DEFAULT_CHARSET;


/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
searchPopup(rel)
  relInfo *rel;
{
    Widget        list_w = rel->records;
    Widget        text_w;
    Widget	  searchBox, searchLabel;
    Widget        searchButtonBox;
    Widget        searchSelButton, searchDeselButton,
                  searchSelAllButton, searchDeselAllButton, 
                  searchFindNextButton, searchCancelButton;
    Arg           wargs[10];
    int           n;
    XmString      label;
    int           action;
    void          search_item(), searchPopdown();
    void          sel(), desel(), selAll(), deselAll(), searchFindNext();

    if (rel->searchSh != NULL)    /* popupSearch() has already been called */
    {
        XtPopup(rel->searchSh, XtGrabNone);               /* popup shell */
        return;        /* no need to create widgets */
    }    

    rel->searchSh = XtVaCreatePopupShell("searchSh", topLevelShellWidgetClass, 
					 rel->top, 
					 XmNallowShellResize, False,
					 XmNresizable, False,
					 NULL);
    setWidgetPos(rel->searchSh, rel->top, 0.0, 0, 1.0, 0);
    
    /* Create a container box for the search widgets defined below */
    searchBox = XtVaCreateManagedWidget("searchBox",
					xmFormWidgetClass,
					rel->searchSh,
					XmNresizable, False,
					NULL);
    XtAddCallback(searchBox, XmNhelpCallback, helpView, "the Search dialog");
    
    label = XmStringCreateSimple("Enter regexp to search:");
    searchLabel = XtVaCreateManagedWidget("searchLabel", xmLabelWidgetClass, 
			    searchBox,
			    XmNtopAttachment,   XmATTACH_FORM,
			    XmNrightAttachment, XmATTACH_FORM,
			    XmNleftAttachment,  XmATTACH_FORM,
			    XmNlabelString,  label,
			    NULL);
    XmStringFree(label);
    text_w = XtVaCreateManagedWidget("searchText",
		            xmTextFieldWidgetClass, searchBox,
			    XmNtopAttachment,   XmATTACH_WIDGET,
			    XmNtopWidget,       searchLabel,
			    XmNrightAttachment, XmATTACH_FORM,
			    XmNleftAttachment,  XmATTACH_FORM,
			    NULL);
    XtAddCallback(text_w, XmNactivateCallback, sel, rel);
    XtVaSetValues(XtParent(rel->records), XmNuserData, text_w, NULL);
    searchButtonBox = XtVaCreateManagedWidget("searchButtonBox", 
				xmFormWidgetClass, searchBox,
				XmNtopAttachment,   XmATTACH_WIDGET,
				XmNtopWidget,       text_w,
				XmNrightAttachment, XmATTACH_FORM,
			        XmNleftAttachment,  XmATTACH_FORM,
			        XmNbottomAttachment,XmATTACH_FORM,
				NULL);
    searchSelButton = XtVaCreateManagedWidget("searchSelButton", 
				xmPushButtonWidgetClass, searchButtonBox,
				XmNrightAttachment, XmATTACH_POSITION,
				XmNrightPosition,   50,
			        XmNleftAttachment,  XmATTACH_FORM,
			        XmNtopAttachment,   XmATTACH_FORM,
				NULL);
    XtAddCallback(searchSelButton, XmNactivateCallback, sel, rel);
    searchDeselButton = XtVaCreateManagedWidget("searchDeselButton", 
				xmPushButtonWidgetClass, searchButtonBox,
				XmNrightAttachment, XmATTACH_FORM,
			        XmNleftAttachment,  XmATTACH_WIDGET,
			        XmNleftWidget,      searchSelButton,
			        XmNtopAttachment,   XmATTACH_FORM,
				NULL);
    XtAddCallback(searchDeselButton, XmNactivateCallback, desel, rel);
    searchSelAllButton = XtVaCreateManagedWidget("searchSelAllButton", 
				xmPushButtonWidgetClass, searchButtonBox,
				XmNrightAttachment, XmATTACH_POSITION,
				XmNrightPosition,   50,
			        XmNleftAttachment,  XmATTACH_FORM,
			        XmNtopAttachment,   XmATTACH_WIDGET,
			        XmNtopWidget,       searchSelButton,
				NULL);
    XtAddCallback(searchSelAllButton, XmNactivateCallback, selAll, rel);
    searchDeselAllButton = XtVaCreateManagedWidget("searchDeselAllButton", 
				xmPushButtonWidgetClass, searchButtonBox,
				XmNrightAttachment, XmATTACH_FORM,
			        XmNleftAttachment,  XmATTACH_WIDGET,
			        XmNleftWidget,      searchSelAllButton,
			        XmNtopAttachment,   XmATTACH_WIDGET,
			        XmNtopWidget,       searchSelButton,
				NULL);
    XtAddCallback(searchDeselAllButton, XmNactivateCallback, deselAll, rel);
    searchFindNextButton = XtVaCreateManagedWidget("searchFindNextButton", 
        			xmPushButtonWidgetClass, searchButtonBox,
				XmNrightAttachment, XmATTACH_FORM,
			        XmNleftAttachment,  XmATTACH_FORM,
			        XmNtopAttachment,   XmATTACH_WIDGET,
			        XmNtopWidget,       searchSelAllButton,
				NULL);
    XtAddCallback(searchFindNextButton, XmNactivateCallback, searchFindNext,
		  rel);
    searchCancelButton = XtVaCreateManagedWidget("searchCancelButton", 
				xmPushButtonWidgetClass, searchButtonBox,
				XmNrightAttachment, XmATTACH_FORM,
				XmNleftAttachment,  XmATTACH_FORM,
			        XmNtopAttachment,   XmATTACH_WIDGET,
			        XmNtopWidget,       searchFindNextButton,
			        XmNbottomAttachment,XmATTACH_FORM,
				NULL);
    XtAddCallback(searchCancelButton, XmNactivateCallback, searchPopdown,
		  rel->searchSh);
    XtPopup(rel->searchSh, XtGrabNone);               /* popup shell */
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void searchPopdown(w, client_data, call_data)
  Widget     w;
  XtPointer  client_data;
  XtPointer  call_data;
{
    XtPopdown(client_data);   /* sh passed as client_data */
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* find the item in the list that matches the specified pattern */
void search_item(rel, action)
  relInfo *rel;
  int action;
{
    Widget list_w = rel->records;
    Widget text_w;
    char *exp, *text, *newtext;
    XmString *strlist, *selectlist = NULL;
    int cnt, j=0;
    unsigned char selectionPolicy;
    extern char *re_comp();
    
    XtVaGetValues(XtParent(rel->records), XmNuserData, &text_w, NULL);
    if (action==SELECT_ALL || action==DESELECT_ALL)
	newtext = strdup(".*");
    else
	newtext = XmTextFieldGetString(text_w);
    if (action==SELECT_ALL)
	action=SELECT;
    if (action==DESELECT_ALL)
	action=DESELECT;
    if (!newtext || !*newtext) {
        /* non-null strings must be entered */
        XtFree(newtext);
        return;
    }
    XtVaGetValues(list_w, XmNselectionPolicy, &selectionPolicy, NULL);
    XtVaSetValues(list_w, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
    
    /* compile expression into pattern matching library */
#ifdef SYSV
    if (!(exp = regcmp(newtext, NULL))) {
        printf("error with regcmp(%s)\n", newtext);
	XtVaSetValues(list_w, XmNselectionPolicy, selectionPolicy, NULL);
        return;
    }
#else /* BSD */
    if (exp = re_comp(newtext)) {
        printf("error with re_comp(%s): %s\n", newtext, exp);
	XtVaSetValues(list_w, XmNselectionPolicy, selectionPolicy, NULL);
        return;
    }
#endif /* SYSV */

    /* get all the items in the list ... we're going to search each one */
    XtVaGetValues(list_w,
        XmNitemCount, &cnt,
        XmNitems,     &strlist,
        NULL);
    while (cnt--) {
        /* convert item to C string */
        if (!XmStringGetLtoR(strlist[cnt], charset, &text))
            break;
        /* do pattern match against search string */
#ifdef SYSV
        /* returns NULL if match failed */
        if (regex(exp, text, NULL)) {
	    XmListDeselectPos(list_w, cnt+1);
	    if (action == SELECT)
		XmListSelectPos(list_w, cnt+1, False);
        }
#else /* BSD */
        /* -1 on error, 0 if no-match, 1 if match */
        if (re_exec(text) > 0) {
	    XmListDeselectPos(list_w, cnt+1);
	    if (action == SELECT)
		XmListSelectPos(list_w, cnt+1, False);
        }
#endif /* SYSV */
        XtFree(text);
    }
#ifdef SYSV
    free(exp);  /* this must be freed for regcmp() */
#endif /* SYSV */
    XtFree(newtext);
    XmListSetPos(list_w, 1);
    equalizeLists(list_w, rel, NULL);
    searchFindNext(NULL, rel);
    while (j--)
        XmStringFree(selectlist[j]);
    /* XmTextFieldSetString(text_w, ""); */
    XtVaSetValues(list_w, XmNselectionPolicy, selectionPolicy, NULL);
    XtVaGetValues(list_w, XmNselectedItemCount, &cnt, NULL);
    status(rel, "%d tuples selected", cnt);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void sel(w, rel)
  Widget w;
  relInfo *rel;
{
    search_item(rel, SELECT);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void desel(w, rel)
  Widget w;
  relInfo *rel;
{
    search_item(rel, DESELECT);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void selAll(w, rel)
  Widget w;
  relInfo *rel;
{
    search_item(rel, SELECT_ALL);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void deselAll(w, rel)
  Widget w;
  relInfo *rel;
{
    search_item(rel, DESELECT_ALL);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void searchFindNext(w, rel)
  Widget w;
  relInfo *rel;
{
    Widget list_w = rel->records;
    int posCount;
    int *posList;
    int topItem;
    int pos;

    if (!XmListGetSelectedPos(list_w, &posList, &posCount))
	return;
    XtVaGetValues(list_w, XmNtopItemPosition, &topItem, NULL);
    for (pos=0; pos<posCount; pos++)
	if (posList[pos] > topItem)
	{
	    XmListSetPos(list_w, posList[pos]);
	    XmListSetPos(rel->key, posList[pos]);
	    XtFree(posList);
	    status(rel, "Located tuple %d (selection %d out of %d)", 
		   posList[pos], pos+1, posCount);
	    return;
	}
    XmListSetPos(list_w, posList[0]);
    XmListSetPos(rel->key, posList[0]);
    status(rel, "Located tuple %d (first selection out of %d)", posList[0],
	   posCount);
    XtFree(posList);
}
