/*********************************************************************/
/*  bibView: Administration of BibTeX-Databases                      */
/*           (Verwaltung von BibTeX-Literaturdatenbanken)            */
/*                                                                   */
/*  Module:  gui_list.c                                              */
/*                                                                   */
/*             GUI List Window                                       */
/*                                                                   */
/*  Author:  Holger Martin,  martinh@informatik.tu-muenchen.de       */
/*           Peter M. Urban, urban@informatik.tu-muenchen.de         */
/*                                                                   */
/*  History:                                                         */
/*    01.25.91  PMU  created                                         */
/*    05.26.92       Version 1.0 released                            */
/*                                                                   */
/*  Copyright 1992 TU MUENCHEN					     */
/*    See ./Copyright for complete rights and liability information. */
/*                                                                   */
/*********************************************************************/

#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/SmeLine.h>
#include "bibview.h"


/* imported global variables */
/* ------------------------- */
extern Widget topLevel;
extern Pixmap lstIconPixmap;


/* macros and definitions */
/* ---------------------- */

/* local function prototypes */
/* ------------------------- */
static Errcode MakeListStrings (LstWinPtr lw);


/* exported variables */
/* ------------------ */

listEntry list_layout;


/* local global variables */
/* ---------------------- */

static BibPtr gbp = NULL;

/*********************************************************************/
/* gulOpenListWin:                                                   */
/*    Create list window                                             */
/*********************************************************************/
Errcode
gulOpenListWin (BibPtr bp, CardDataList cl) 
{
LstWinPtr lw;
Errcode status;
String sp, help;
int i, lst_width;

   /* if opened already, just replace data and raise window */
   if (gulListWinExists(bp)) {
      if ((status = gulReplaceListData(bp, cl)) != OK)
	 return(status);
      if (XtIsRealized(bp->lw->lstShell)) {
	 XRaiseWindow(XtDisplay(bp->lw->lstShell),
		      XtWindow(bp->lw->lstShell));
      }
      return(OK);
   }

   if ((lw = (LstWinPtr)XtMalloc(sizeof(LstWin))) == NULL)
      return(ERR_NOMALLOC); 

   /* build label of new shell */
   if ((lw->shellName = (String)XtCalloc(strlen(PROGNAME) +
			               strlen(bp->filename)+10, 
			               sizeof(char))) == NULL) {
      return(ERR_NOMALLOC); 
   }
   sprintf(lw->shellName, "%s: List %s", PROGNAME, bp->filename);

   /* create argc and argv for list window */
   lw->cardLst = cl;
   if ((status = MakeListStrings(lw)) != OK) {
      XtFree((char *)lw->shellName);
      XtFree((char *)lw);
      return(status); 
   }

   /* register window in bib struct */
   bp->lw = lw;


   /* position window and icon */
   gulSetWindowCoords(bp, TRUE);
   if (cotIconizeOnDesktop())
      gulSetIconCoords(bp, TRUE);

   /* create popup shell for new file */
   lw->lstShell = XtVaCreatePopupShell("listShell",
	            topLevelShellWidgetClass, topLevel,
                    XtNx, lw->winX,
		    XtNy, lw->winY,  
                    XtNiconX, lw->iconX, 
		    XtNiconY, lw->iconY, 
                    XtNtitle, lw->shellName,
                    XtNiconPixmap, lstIconPixmap,
                    XtNiconName, bp->filename, NULL);
   /* create windows of popup shell */
   lw->lstWin = XtVaCreateManagedWidget("listWin",
	             panedWidgetClass, lw->lstShell, NULL);
   lw->cmdBox = XtVaCreateManagedWidget("commandBox", 
		     boxWidgetClass, lw->lstWin, NULL);
   lw->save = XtVaCreateManagedWidget("save", 
		    commandWidgetClass, lw->cmdBox, NULL);
   lw->sort = XtVaCreateManagedWidget("sort", 
		    menuButtonWidgetClass, lw->cmdBox, NULL);
   lw->copy = XtVaCreateManagedWidget("copy", 
		    commandWidgetClass, lw->cmdBox, NULL);
   lw->print = XtVaCreateManagedWidget("print", 
		    commandWidgetClass, lw->cmdBox, NULL);
   lw->quit = XtVaCreateManagedWidget("quit", 
		   commandWidgetClass, lw->cmdBox, NULL);
   lw->lstVp = XtVaCreateManagedWidget("listVport",
		   viewportWidgetClass, lw->lstWin, 
		   XtNallowVert, True, 
		   XtNallowHoriz, True, 
		   XtNuseBottom, TRUE, NULL);
   lw->vpWin = XtVaCreateManagedWidget("vportWin",
	             panedWidgetClass, lw->lstVp, NULL);

   lst_width = 0;
   for (i=0; i<list_layout.number; i++)
      lst_width += list_layout.width[i] + LST_WHITESPACE;

   if ((help = (String)XtCalloc(1, lst_width+1)) == NULL)
      return(ERR_NOMALLOC);
   
   if ((sp = (String)XtCalloc(1, lst_width+1)) == NULL)
      return(ERR_NOMALLOC);
      
   strcpy(sp, "");
   for (i=0; i<list_layout.number; i++){
      if (list_layout.field[i] == -1)
         sprintf(help, "%-*.*s",
              list_layout.width[i], list_layout.width[i], 
	      "MAINKEY");
      else if (list_layout.field[i] == -2)
         sprintf(help, "%-*.*s",
              list_layout.width[i], list_layout.width[i], 
	      "CARDTYPE");
      else
         sprintf(help, "%-*.*s",
              list_layout.width[i], list_layout.width[i], 
	      glbFldToName(list_layout.field[i]));
      sp = strcat(sp, help);
      sprintf(help, "%-*.*s",
 	    LST_WHITESPACE, LST_WHITESPACE, "");
      sp = strcat(sp, help);
      }

   lw->headBox = XtVaCreateManagedWidget("headBox", 
		     boxWidgetClass, lw->vpWin, 
		     XtNvSpace, 0, 
		     XtNborderWidth, 0, NULL);
                 XtVaCreateManagedWidget("head1", 
		      labelWidgetClass, lw->headBox, 
                      XtNlabel, sp,
                      XtNjustify, XtJustifyLeft,
		      XtNborderWidth, 0, NULL);
   XtFree((char *)help);
   XtFree((char *)sp);

   lw->list = XtVaCreateManagedWidget("mylist", 
		   listWidgetClass, lw->vpWin,  
		   XtNdefaultColumns, 1,
		   XtNforceColumns, True,
		   XtNlist, lw->listArgv, NULL);
   XtAddCallback(lw->quit, XtNcallback, gulCloseListWinCmd, (XtPointer)bp);
   XtAddCallback(lw->list, XtNcallback, csrDisplayCardCmd, (XtPointer)bp);
   XtAddCallback(lw->print, XtNcallback, cprPrintListCmd, (XtPointer)bp);
   XtAddCallback(lw->save, XtNcallback, cprSaveListCmd, (XtPointer)bp);
   XtAddCallback(lw->copy, XtNcallback, gulCopyListWinCmd, (XtPointer)bp);
   glbCreateFieldMenu("sortMenu", lw->sort, &lw->sortMenu, 
	      gulSortListWinCmd, (XtPointer) bp);

   XtPopup(lw->lstShell, XtGrabNone);
   return(OK);
}


/*********************************************************************/
/* gulListWinExists:                                                 */
/*    TRUE, if list window exists, else FALSE                        */
/*********************************************************************/
Boolean
gulListWinExists (BibPtr bp)
{
   return(bp->lw != NULL);
}


/*********************************************************************/
/* gulReplaceListData:                                               */
/*    Replace cards to display in list                               */
/*********************************************************************/
Errcode
gulReplaceListData (BibPtr bp, CardDataList cl)
{
LstWinPtr lw = bp->lw;
Errcode status;

   if (lw == NULL) /* is list window open? */
      return(OK);

   /* XtFree old stuff */
   if (lw->listArgv)
      XtFree((char *)lw->listArgv);
   if (lw->strs)
      XtFree((char *)lw->strs);

   dbtCardListDelete(&lw->cardLst);  
   XtRemoveAllCallbacks(lw->print, XtNcallback); 

   /* create argc and argv for list window */
   lw->cardLst = cl;
   if ((status = MakeListStrings(lw)) != OK) {
      lw->listArgv = NULL;
      lw->strs = NULL;
      return(status); 
   }

   /* change list */
   XawPanedSetRefigureMode(lw->vpWin, False); 
   XawListChange(lw->list, lw->listArgv, lw->listArgc, 0, True);

   /* scroll to beginning of list */
   XawListHighlight(lw->list, 0);
   XawListUnhighlight(lw->list);
   XawPanedSetRefigureMode(lw->vpWin, True);

   /* set new client data for callbacks */
   XtAddCallback(lw->print, XtNcallback, cprPrintListCmd, (XtPointer)bp);

   return(OK);
}


/*********************************************************************/
/* gulSortListWinCmd:                                                */
/*    Callback function for list menu entry quit                     */
/*********************************************************************/
void
gulSortListWinCmd (Widget w, XtPointer clientData, XtPointer callData)
{
BibPtr bp = (BibPtr) clientData;
int type;
Errcode status;
  
   sscanf(XtName(w), "item%d", &type);
   if (type == 1)
      bp->sortedby = SORT_MAINKEY;
   else if (type == 2)
      bp->sortedby = SORT_TYPE;
   else  
      bp->sortedby = type-3;
   if ((status = gulSortListWin(bp)) != OK)
      guwError(status);
}


/*********************************************************************/
/* gulCloseListWinCmd:                                               */
/*    Callback function for list menu entry quit                     */
/*********************************************************************/
void
gulCloseListWinCmd (Widget w, XtPointer clientData, XtPointer callData)
{
BibPtr bp = (BibPtr) clientData;
Errcode status;

   if ((status = gulCloseListWin(bp)) != OK)
      guwError(status);
}


/*********************************************************************/
/* gulCopyListWin:                                                   */
/*    Callback function for list menu entry copy                     */
/*    Source is in gbp, destination in bp                            */
/*********************************************************************/
Errcode
gulCopyListWin(BibPtr bp)
{

CardListNode *clp, *cl = NULL;
CardListNode *dclp = NULL;
CardListNode *dcl = NULL;
CardData *hcard = NULL;
Errcode status;

   /* check bibs: can't be equal */
   if (bp->treeIdx == gbp->treeIdx) {
      guwError(ERR_COPY_SAME_LIST);
      return (ERR_COPY_SAME_LIST);
   }

   cl = gbp->lw->cardLst;
   
   if (gulListWinExists(bp))
      dclp = dcl = bp->lw->cardLst;

   /* add all cards from list to dest bib */
   for (clp = cl; clp != NULL; clp = clp->next) {
      CopyCard(&hcard, clp->data); 
      if ((status = dbtInsert(bp, hcard)) != DBT_OK) 
	 guwError(status);
      if (dclp != NULL){
         if ((status = dbtCardListInsert(&dcl, hcard, bp->sortedby)) != DBT_OK){ 
	    guwError(status);
            return(status);
            }
         }
   }
   dbtDeleteCard(&hcard); /* NEU */
   if (gulListWinExists(bp)) {
      bp->lw->cardLst = NULL;
      if  ((status = gulReplaceListData(bp, dcl)) != OK) {
	 guwError(status);
	 gulCloseListWin(bp);
      }
   }

   bp->changed = TRUE;
   return(OK);
}


/*********************************************************************/
/* gulCopyListWinCmd:                                                */
/*    Callback function for list menu entry copy                     */
/*********************************************************************/
void
gulCopyListWinCmd (Widget w, XtPointer clientData, XtPointer callData)
{
BibPtr bp = (BibPtr) clientData;
Errcode status;

   gbp = bp;
   if ((status = guwSelectBib("copyHead", gulCopyListWin)) != OK)
      guwError(status);
}


/*********************************************************************/
/* gulSortListWin:                                                   */
/*    Sort list window                                               */
/*********************************************************************/
Errcode
gulSortListWin (BibPtr bp)
{
Errcode status;
CardDataList cl, clp, dcl=NULL;

   cl = bp->lw->cardLst;
   for (clp = cl; clp != NULL; clp = clp->next)
      if ((status = dbtCardListSortIns(&dcl, clp->data, bp->sortedby)) 
	   != DBT_OK) return(status);

/*   dbtCardListDelete(&bp->lw->cardLst);  */
   bp->lw->cardLst = NULL;
   if ((status = gulReplaceListData(bp, dcl)) != OK)
      return(status);
   return(OK);
}



/*********************************************************************/
/* gulCloseListWin:                                                  */
/*    Close list window                                              */
/*********************************************************************/
Errcode
gulCloseListWin (BibPtr bp)
{
   if (bp->lw != NULL) {
      if (bp->lw->listArgv)
         XtFree((char *)bp->lw->listArgv);
      if (bp->lw->strs)
         XtFree((char *)bp->lw->strs);
      XtDestroyWidget(bp->lw->lstShell);
      XtDestroyWidget(bp->lw->lstWin);
      XtDestroyWidget(bp->lw->cmdBox);
      XtDestroyWidget(bp->lw->save);
      XtDestroyWidget(bp->lw->sort);
      XtDestroyWidget(bp->lw->copy);
      XtDestroyWidget(bp->lw->print);
      XtDestroyWidget(bp->lw->quit);
      XtDestroyWidget(bp->lw->lstVp);
      XtDestroyWidget(bp->lw->vpWin);
      XtDestroyWidget(bp->lw->headBox);
      XtDestroyWidget(bp->lw->list);
      dbtCardListDelete(&bp->lw->cardLst);
      bp->lw->cardLst = NULL;
      XtFree((char *)bp->lw->shellName);
      XtFree((char *)bp->lw); 
      bp->lw = NULL;
   }
   return(OK);
}


/*********************************************************************/
/* gulCascade:                                                       */
/*    Reposition list window                                         */
/*********************************************************************/
Errcode
gulCascade (BibPtr bp)
{
   if (bp->lw == NULL) /* is list window open? */
      return(OK);

   gulSetWindowCoords(bp, FALSE);
   if (cotIconizeOnDesktop())
      gulSetIconCoords(bp, FALSE);
   return(OK);
}


/*********************************************************************/
/* gulSetWindowCoords:                                               */
/*    Set position of list window                                    */
/*********************************************************************/
Errcode
gulSetWindowCoords (BibPtr bp, Boolean calcOnly)
{
Position x, y;
LstWinPtr lw = bp->lw;

   if (lw == NULL) /* is list window open? */
      return(OK);

   x = SUBWIN_MARGIN;
   y = SUBWIN_MARGIN;
   XtTranslateCoords(bp->bw->bibdesk,
		     x, y,
		     &lw->winX, &lw->winY);

   /* set values */
   if (!calcOnly) {
      XtVaSetValues(lw->lstShell,
                    XtNx, lw->winX,
		    XtNy, lw->winY, NULL);
      if (XtIsRealized(lw->lstShell)) {
         XRaiseWindow(XtDisplay(lw->lstShell),
		      XtWindow(lw->lstShell));
      }
   }
   return(OK);
}


/*********************************************************************/
/* gulSetIconCoords:                                                 */
/*    Set position of list window icon                               */
/*********************************************************************/
Errcode
gulSetIconCoords (BibPtr bp, Boolean calcOnly)
{
Dimension dwidth, dheight;
Position x, y;
LstWinPtr lw = bp->lw;

   if (lw == NULL) /* is list window open? */
      return(OK);

   /* calculate position of icon */
   XtVaGetValues(bp->bw->bibdesk,
		 XtNwidth, &dwidth,
		 XtNheight, &dheight, NULL);
   x = dwidth - LST_ICON_WIDTH - LST_ICON_MARGIN;
   y = LST_ICON_MARGIN;
   XtTranslateCoords(bp->bw->bibdesk,
	             x, y, 
		     &lw->iconX, &lw->iconY);

   /* set values */
   if (!calcOnly) {
      XtVaSetValues(lw->lstShell,
		    XtNiconX, lw->iconX,
		    XtNiconY, lw->iconY, NULL);
   }
   return(OK);
}


/*********************************************************************/
/* gulUnsetIconCoords:                                               */
/*    Delete position of list window icon                            */
/*********************************************************************/
Errcode
gulUnsetIconCoords (BibPtr bp, Boolean calcOnly)
{
LstWinPtr lw = bp->lw;

   if (lw == NULL) /* is list window open? */
      return(OK);

   lw->iconX = lw->iconY = -1;
   if (!calcOnly) {
      XtVaSetValues(lw->lstShell,
		    XtNiconX, lw->iconX,
		    XtNiconY, lw->iconY, NULL);
   }
   return(OK);
}



/*********************************************************************/
/* LOCAL FUNCTIONS                                                   */
/*********************************************************************/

/*********************************************************************/
/* MakeListStrings:                                                  */
/*    Build entries for list from argv of cards                      */
/*********************************************************************/
static Errcode
MakeListStrings (LstWinPtr lw)
{
CardDataList cl;
String p, *sp, help, spp;
int i, noOfCards = 0; 
int lst_width;

   /* find out how many cards there are */
   for (cl=lw->cardLst; cl != NULL; cl=cl->next, noOfCards++)  ;
   lw->listArgc = noOfCards;  

   if (noOfCards == 0) {
      lw->listArgv = NULL;
      lw->strs = NULL;
      return(OK);
   }

   lst_width = 0;
   for (i=0; i<list_layout.number; i++)
      lst_width += list_layout.width[i] + LST_WHITESPACE;


   /* alloc new argv for Strings */
   if ((help = (String)XtCalloc(1,lst_width+1)) == NULL)
      return(ERR_NOMALLOC);
   if ((lw->listArgv=(String *)XtCalloc(noOfCards+1, sizeof(String))) == NULL)
      return(ERR_NOMALLOC);
   if ((lw->strs = (String)XtCalloc(noOfCards,(size_t)(lst_width+1))) == NULL)
      return(ERR_NOMALLOC); 
   for (i=0, p=lw->strs; i < noOfCards; i++) {
      (lw->listArgv)[i] = p;
      p += lst_width+1; 
   }
   lw->listArgv[noOfCards] = NULL; /* NULL terminated list */
   i=0; 

   for (cl=lw->cardLst, sp=lw->listArgv; cl != NULL; cl=cl->next, sp++) {
      strcpy(*sp, "");
      for (i=0; i<list_layout.number; i++){
         if (list_layout.field[i] == -1)
            sprintf(help, "%-*.*s",
              list_layout.width[i], list_layout.width[i], 
	      cl->data->mainkey);
         else if (list_layout.field[i] == -2)
            sprintf(help, "%-*.*s",
              list_layout.width[i], list_layout.width[i], 
	      cl->data->cardtypestr);
         else if (!glbIsStringEmpty(cl->data->field[list_layout.field[i]]))
           sprintf(help, "%-*.*s",
              list_layout.width[i], list_layout.width[i], 
	      cl->data->field[list_layout.field[i]]);
         else
           sprintf(help, "%-*.*s",
              list_layout.width[i], list_layout.width[i], "-----");
         *sp = strcat(*sp, help);
         sprintf(help, "%-*.*s",
 	    LST_WHITESPACE, LST_WHITESPACE, "");
         *sp = strcat(*sp, help);
	 }
     
       for (spp=*sp;*spp!='\0';spp++)
       if ((*spp=='\t')||(*spp=='\n'))
	 *spp=' ';
   }
   XtFree((char *)help);
   return(OK);
}
