/**
*** 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 <X11/StringDefs.h>
#include <X11/Intrinsic.h> 
#include <X11/cursorfont.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/Frame.h>
#include <Xm/RowColumn.h>
#include <Xm/ToggleBG.h>
#include <Xm/PushB.h>
#include <Xm/Label.h>
#include <Xm/LabelG.h>
#include <Xm/Separator.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


extern APP_RESOURCE_STRUCT appResources;


void helpView();
Widget openClassOpsShell();
void printOptions();
void printOptionsClose();
void printTotalActionsCB();


/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void printMenuHandler(w, item, cbs)
  Widget w;
  int item;
  XtPointer cbs;
{
    relInfo *rel;
    PortalBuffer *p;
    int i, j, m, n;
    Boolean isFirst;
    FILE *pipe;
    char *t, *val;
    int posCount;
    int *posList, ipos, jpos, jfirst;
    char fieldBuf[BUFSIZ];
    Boolean isList=False, isKey=False;
    Widget list;
    String *totals;
    mathCbsStruct *mathCbs;
    static String mathActionNames[] = {"Sum", "Product", "Count", "Average",
				       "Std. Deviation", "Min", "Max"};
    
    XtVaGetValues(XtParent(XtParent(XtParent(w))), XmNuserData, &rel, NULL);
    if (item == 4)  /* the Options item */
    {
	printOptions(rel);
	return;
    }
    list = rel->records;
    if (rel->portal == NULL)
    {
	warn(rel->top, "No class in viewer!");
	return;
    }
    p = PQparray(rel->portal);
    n = PQntuples(p);
    if (!n)
    {
	warn(rel->top, "Class is empty, nothing to print");
	return;
    }
    m = PQnfields(p,0);
    jfirst = ATTR_1ST(rel);
    if (item >= 2)
    {
	isKey = True;
	list = rel->key;
	jfirst = 0;
	for (m=0; ; m++)
	    if (rel->attrInfo[m].keyList == (-1))
		break;
	if (!m)
	{
	    warn(rel->top, "No key attributes!");
	    return;
	}
    }
    if (item==1 || item==3)
    {
	isList = True;
	if (!XmListGetSelectedPos(list, &posList, &posCount))
	{
	    warn(rel->top, "No selected tuples!");	
	    return;
	}
	n = posCount;
    }

    totals = (String *)XtCalloc(PQnfields(p,0)*NUM_MATH_ACTIONS, sizeof(String));
    mathCbs = (mathCbsStruct *)XtMalloc(sizeof(mathCbsStruct));
    mathCbs->allAttr = !isKey;
    mathCbs->allTuples = !isList;
    mathCbs->rel = rel;
    mathCbs->numFields = m;
    mathCbs->fields = NULL;
    mathCbs->results = totals;
    mathCbs->opsSh = NULL;
    mathOk(NULL, mathCbs, NULL);

    setBusy(rel, PRINT);
    status(rel, "Piping class data to printer command...");
    if ((pipe = popen(rel->res.printCmd, "w")) == NULL)
    {
	warn(rel->top, "Cannot execute the print pipe command!");
	XtFree(totals);
	XtFree(mathCbs);
	setBusy(rel, NOBUSY);
	return;
    }
    fprintf(pipe, "%s\n", (rel->class ? rel->class : rel->portal));
    fprintf(pipe, "%s\n", appResources.database);

    for (j=jfirst; j<m; j++)
    {
	jpos = (isKey ? rel->attrInfo[j].keyList : j);
	fprintf(pipe, "%s\t", rel->attrInfo[jpos].name);
    }
    fprintf(pipe, "\n");

    for (j=jfirst; j<m; j++)
    {
	jpos = (isKey ? rel->attrInfo[j].keyList : j);
	fprintf(pipe, "%d\t", rel->attrInfo[jpos].pgType);
    }
    fprintf(pipe, "\n");

    for (i=0; i<n; i++)
    {
	ipos = (isList ? posList[i]-1 : i);
	for (j=jfirst; j<m; j++)
	{
	    jpos = (isKey ? rel->attrInfo[j].keyList : j);
	    val = PQgetvalue(p,ipos,jpos);
	    if (val && rel->res.floatPrecision>=0 &&
		(rel->attrInfo[jpos].pgType==700 || 
		 rel->attrInfo[jpos].pgType==701))
		floatFormat(fieldBuf, val, rel->attrInfo[jpos].len, 
			    rel->res.floatPrecision);
	    else
		sprintf(fieldBuf, "%s", (val ? val : NULL_VAL));
	    fprintf(pipe, "%s\t", fieldBuf);
	}
	fprintf(pipe, "\n");
    }

    /* print totals */
    for (i=0; i<NUM_MATH_ACTIONS; i++)
	if (rel->printOptions.totalActions[i])
	    break;    /* find if at least one total action is on */
    if (i<NUM_MATH_ACTIONS)
	fprintf(pipe, "!TOTALS!\n");
    for (i=0; i<NUM_MATH_ACTIONS; i++)
    {
	if (! rel->printOptions.totalActions[i])
	    continue;     /* this action is off */
	fprintf(pipe, "%s\n", mathActionNames[i]);
	for (j=jfirst; j<m; j++)
	{
	    jpos = (isKey ? rel->attrInfo[j].keyList : j);
	    val = mathResultElem(totals, jpos, i);
	    if (val == NULL)
		fieldBuf[0] = '\0';
	    else if (rel->res.floatPrecision>=0 &&
		     (rel->attrInfo[jpos].pgType==700 || 
		      rel->attrInfo[jpos].pgType==701))
		floatFormat(fieldBuf, val, rel->attrInfo[jpos].len, 
			    rel->res.floatPrecision);
	    else
		strcpy(fieldBuf, val);
	    fprintf(pipe, "%s\t", fieldBuf);
	}
	fprintf(pipe, "\n");
    }
    
    if (isList)
	XtFree(posList);
    pclose(pipe);
    for (i=0; i<NUM_MATH_ACTIONS; i++)   /* free the totals matrix' vals */
	for (j=ATTR_1ST(rel); j<PQnfields(p,0); j++)
	    free(mathResultElem(totals, j, i));
    XtFree(totals);
    XtFree(mathCbs);
    status(rel, "Printing done.");
    setBusy(rel, NOBUSY);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void printOptions(rel)
  relInfo *rel;
{
    Widget sh, copBox, cancel, but, checkBox, frame, label;
    XmString compStr;
    
    setCursor(rel->top, XC_watch);
    sh = openClassOpsShell(rel->top, "printOptions");
    copBox = XtVaCreateManagedWidget("copBox",
				     xmFormWidgetClass, sh, NULL);
    XtAddCallback(copBox, XmNhelpCallback, helpView, "printing");
    label = XtVaCreateManagedWidget("totalActionsLabel", xmLabelGadgetClass,
				    copBox, NULL);
    frame = XtVaCreateManagedWidget("printOptionsFrame", xmFrameWidgetClass, 
				    copBox, NULL);
    checkBox = XmCreateSimpleCheckBox(frame, "printOptionsCheckBox", NULL, 0);
    but = XtVaCreateManagedWidget("mathSum", 
				  xmToggleButtonGadgetClass, checkBox,
				  XmNuserData, "Sum",
				  NULL);
    XmToggleButtonSetState(but, rel->printOptions.totalActions[SUM], False);
    XtAddCallback(but, XmNvalueChangedCallback, printTotalActionsCB, rel);
    but = XtVaCreateManagedWidget("mathProd", 
				  xmToggleButtonGadgetClass, checkBox,
				  XmNuserData, "Product",
				  NULL);
    XmToggleButtonSetState(but, rel->printOptions.totalActions[PRODUCT],False);
    XtAddCallback(but, XmNvalueChangedCallback, printTotalActionsCB, rel);
    but = XtVaCreateManagedWidget("mathCount", 
				  xmToggleButtonGadgetClass, checkBox,
				  XmNuserData, "Count",
				  NULL);
    XmToggleButtonSetState(but, rel->printOptions.totalActions[COUNT], False);
    XtAddCallback(but, XmNvalueChangedCallback, printTotalActionsCB, rel);
    but = XtVaCreateManagedWidget("mathAvg", 
				  xmToggleButtonGadgetClass, checkBox,
				  XmNuserData, "Average",
				  NULL);
    XmToggleButtonSetState(but, rel->printOptions.totalActions[AVERAGE],False);
    XtAddCallback(but, XmNvalueChangedCallback, printTotalActionsCB, rel);
    but = XtVaCreateManagedWidget("mathSd", 
				  xmToggleButtonGadgetClass, checkBox,
				  XmNuserData, "StdDev",
				  NULL);
    XmToggleButtonSetState(but, rel->printOptions.totalActions[STDDEV], False);
    XtAddCallback(but, XmNvalueChangedCallback, printTotalActionsCB, rel);
    but = XtVaCreateManagedWidget("mathMin", 
				  xmToggleButtonGadgetClass, checkBox,
				  XmNuserData, "Min",
				  NULL);
    XmToggleButtonSetState(but, rel->printOptions.totalActions[MMIN], False);
    XtAddCallback(but, XmNvalueChangedCallback, printTotalActionsCB, rel);
    but = XtVaCreateManagedWidget("mathMax", 
				  xmToggleButtonGadgetClass, checkBox,
				  XmNuserData, "Max",
				  NULL);
    XmToggleButtonSetState(but, rel->printOptions.totalActions[MMAX], False);
    XtAddCallback(but, XmNvalueChangedCallback, printTotalActionsCB, rel);
    XtManageChild(checkBox);
    cancel = XtVaCreateManagedWidget("copCancel", 
				     xmPushButtonWidgetClass, copBox,
				     NULL);
    XtAddCallback(cancel, XmNactivateCallback, printOptionsClose, sh);
    setFormColumn(copBox, -1);
    XtManageChild(copBox);
    XtPopup(sh, XtGrabNone);  
    setCursor(rel->top, None);
}





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





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void printTotalActionsCB(w, rel, cbs)
  Widget w;
  relInfo *rel;
  XmToggleButtonCallbackStruct *cbs;
{
    int action;
    String caller = NULL;
    
    if (!w)
	return;
    XtVaGetValues(w, XmNuserData, &caller, NULL);
    if (!strcmp(caller, "Sum"))             action = SUM;
    else if (!strcmp(caller, "Product"))    action = PRODUCT;
    else if (!strcmp(caller, "Count"))      action = COUNT;
    else if (!strcmp(caller, "Average"))    action = AVERAGE;
    else if (!strcmp(caller, "StdDev"))     action = STDDEV;
    else if (!strcmp(caller, "Min"))        action = MMIN;
    else if (!strcmp(caller, "Max"))        action = MMAX;

    if (caller != NULL)
	rel->printOptions.totalActions[action] = cbs->set;
}
