/*********************************************************************/
/*  bibView: Administration of BibTeX-Databases                      */
/*           (Verwaltung von BibTeX-Literaturdatenbanken)            */
/*                                                                   */
/*  Module:  ctl_card.c                                              */
/*                                                                   */
/*             Card Window Commands Control                          */
/*             - New      Open empty card window                     */
/*             - Change   Register changes done in card window       */
/*             - Copy     Copy card to other BibTeX file             */
/*                                                                   */
/*  Author:  Holger Martin,  martinh@informatik.tu-muenchen.de       */
/*           Peter M. Urban, urban@informatik.tu-muenchen.de         */
/*                                                                   */
/*  History:                                                         */
/*    01.25.92  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/Command.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/SmeLine.h>
#include <X11/Xaw/Text.h>
#include <X11/Xaw/AsciiText.h>
#include "bibview.h"


/* imported global variables */
/* ------------------------- */
extern Widget topLevel, mainMenu, desktop;
extern Pixmap questPixmap, annoteIconPixmap;


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


/* local function prototypes */
/* ------------------------- */
static void annoteChanged (Widget w, XtPointer clientData, XtPointer callData);
static void confirmCloseCard (CardPtr cp);
static void confirmCloseAnnote (CardPtr cp);
static void cancelQuitCmd (Widget w, XtPointer clientData, XtPointer callData);
static void cardQuitOkCmd (Widget w, XtPointer clientData, XtPointer callData);
static void annoteQuitOkCmd (Widget w, XtPointer clientData,
			     XtPointer callData);
static Errcode annoteSave (CardPtr cp); 
static Errcode annoteClose (CardPtr cp); 
static void annoteSaveCmd (Widget w, XtPointer clientData, XtPointer callData);
static void annoteCloseCmd (Widget w, XtPointer clientData, XtPointer callData);


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


/* local global variables */
/* ---------------------- */
CardPtr gcp;


/*********************************************************************/
/* ccdNewCardCmd:                                                    */
/*    Callback function for command "New" in bib window              */
/*********************************************************************/
void 
ccdNewCardCmd (Widget w, XtPointer clientData, XtPointer callData)
{
BibPtr bp = (BibPtr)clientData;
Errcode status;
CardType type;
CardDataPtr cd;
CardPtr cp;

   sscanf(XtName(w), "item%d", &type);
   type -= 1;

   /* create new internal data for a card window */
   if ((status = dbtMakeCard(&cd)) != DBT_OK) {
      guwError(status);
      return;
   }
   cd->cardtype = type;
   if ((cd->cardtypestr = glbNewString(glbTypeToName(type))) == NULL) {
      guwError(ERR_NOMALLOC);
      dbtDeleteCard(&cd);
      return;
   }
   if ((status = glbNewCardListEl(bp, &cp, cd)) != OK) {
      guwError(status);
      dbtDeleteCard(&cd);
      return;
   }

   /* open the window */
   if ((status = gucOpenCardWin(bp, cp, TRUE)) != OK)
      guwError(status);
}


/*********************************************************************/
/* ccdSaveCardCmd:                                                   */
/*    Callback function for command "Save" in card window            */
/*********************************************************************/
void 
ccdSaveCardCmd (Widget w, XtPointer clientData, XtPointer callData)
{
CardPtr cp = (CardPtr)clientData;
BibPtr bp = (BibPtr)cp->bp;
CardWidgetsPtr cwp = &cp->cw->ct.cw;
CardDataList cl;
Errcode status;
XawTextBlock textblock;
CardData *hcard = NULL;
String str;

   if (cp->aw != NULL)
      annoteClose(cp);
   /* save data from text widgets to card */
   if ((status = gucSaveCardData(cp)) != OK) {
      guwError(status);
      gulCloseListWin(bp);
      return;
   }

   /* Check if data in card is OK */
   if (cotRequiredFields()) {
      if ((status = dbtTestCard(cp->cd)) != DBT_OK) {
         guwWarning(status);
	 }
   }

   /* insert new card in data tree, possibly new mainkey */
   CopyCard(&hcard, cp->cd);
   if ((status = dbtInsert(bp, hcard)) != DBT_OK) { 
      guwError(status);
      gulCloseListWin(bp);
      return;
   }
   
   if (strcmp(cp->cd->mainkey, hcard->mainkey) != 0){
      textblock.firstPos = 0;
      textblock.length = strlen(hcard->mainkey);
      textblock.ptr = hcard->mainkey;
      textblock.format = FMT8BIT;

      XawTextReplace(cwp->mainkey, (XawTextPosition) 0, 
             (XawTextPosition) strlen(cp->cd->mainkey),
             (XawTextBlock *) &textblock);
      XawTextSetInsertionPoint(cwp->mainkey, (XawTextPosition) 0);
      XtVaGetValues(cwp->mainkey, XtNstring, &str, NULL);
      XtFree(cp->cd->mainkey);
      cp->cd->mainkey = glbNewString(str);
      }

   cp->changed = FALSE;
   bp->changed = TRUE;

   /* insert card in list of cards for list window */
   if (gulListWinExists(bp)) {
      cl = bp->lw->cardLst;
      if ((status = dbtCardListInsert(&cl,hcard,bp->sortedby)) != DBT_OK) { 
         guwError(status);
         return;
         }
      bp->lw->cardLst = NULL;
      if ((status = gulReplaceListData(bp, cl)) != OK) {
         guwError(status);
         gulCloseListWin(bp);
         }
   }
   /* Change callback to change */
   dbtDeleteCard(&hcard);
   XtRemoveAllCallbacks(cp->cw->change, XtNcallback);
   XtAddCallback(cp->cw->change, XtNcallback, ccdChangeCardCmd, (XtPointer)cp);
}


/*********************************************************************/
/* ccdUserdataCmd:                                                   */
/*    Callback function for command "Userdata" in card window        */
/*********************************************************************/
void 
ccdUserdataCmd (Widget w, XtPointer clientData, XtPointer callData)
{
CardPtr cp = (CardPtr)clientData;
Errcode status;

   if (cp->extended)
      status = gucCloseUserFields(cp);
   else
      status = gucOpenUserFields(cp);

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

/*********************************************************************/
/* annoteSave:                                                       */
/*    Save "annote"  						     */
/*********************************************************************/
static Errcode 
annoteSave (CardPtr cp)
{
String str;
CardWidgetsPtr cwp = &cp->cw->ct.cw;
   
   XtFree(cp->cd->field[nannote]);
   XtVaGetValues(cwp->annote, XtNstring, &str, NULL);
   if ((cp->cd->field[nannote] = glbNewString(str)) == NULL)
      return(ERR_NOMALLOC);
   cp->cd->annoteChanged = TRUE;
   cp->aw->changed = FALSE;
   return(OK);
}

/*********************************************************************/
/* annoteSaveCmd:                                                    */
/*    Callback function for command "Save" in annote window          */
/*********************************************************************/
static void 
annoteSaveCmd (Widget w, XtPointer clientData, XtPointer callData)
{
Errcode status;
CardPtr cp = (CardPtr)clientData;
   if ((status=annoteSave(cp))!=OK)
      guwError(status);
   return;
}

/*********************************************************************/
/* annoteClose:                                                      */
/*    Close  annote window                                           */
/*********************************************************************/
static Errcode 
annoteClose(CardPtr cp)
{
  
   if (cp->aw != NULL) {
      XtPopdown(cp->aw->annoteShell);
      XtFree((char *)cp->aw->shellName);
      XtFree((char *)cp->aw);
      cp->aw = NULL;
   }
   return(OK);
}

/*********************************************************************/
/* annoteCloseCmd:                                                   */
/*    Callback function for command "Close" in annote window         */
/*********************************************************************/
static void 
annoteCloseCmd (Widget w, XtPointer clientData, XtPointer callData)
{
CardPtr cp = (CardPtr)clientData;

if (cp->aw->changed)
   confirmCloseAnnote(cp);
else
   annoteClose(cp);
}

/*********************************************************************/
/* ccdAnnoteCardCmd:                                                 */
/*    Callback function for command "Annote" in card window          */
/*********************************************************************/
void 
ccdAnnoteCardCmd (Widget w, XtPointer clientData, XtPointer callData)
{
CardPtr cp = (CardPtr)clientData;
CardWidgetsPtr cwp = &cp->cw->ct.cw;
AnnoteWinPtr aw;
String hlpstring;
  
   if (cp->aw != NULL) {
       if (XtIsRealized(cp->aw->annoteShell))
	  XRaiseWindow(XtDisplay(cp->aw->annoteShell),
	                XtWindow(cp->aw->annoteShell));
       return;
       }
   if ((aw = (AnnoteWinPtr) XtCalloc(1, sizeof(AnnoteWin))) == NULL) {
       guwError(ERR_NOMALLOC);
       return;
       }
   if (cp->cd->mainkey==NULL)
       aw->shellName = (String) XtCalloc(15,sizeof(char));
   else
       aw->shellName = (String) XtCalloc(strlen(cp->cd->mainkey)+10,
		sizeof(char));
   if (aw->shellName == NULL)
      {guwError(ERR_NOMALLOC);
       return;
       }
   if (cp->cd->mainkey==NULL)
      sprintf(aw->shellName, "Annote: NEW");
   else
      sprintf(aw->shellName, "Annote: %s", cp->cd->mainkey);
   aw->annoteShell = XtVaCreatePopupShell("AnnoteShell",
	       topLevelShellWidgetClass, topLevel,
	       XtNtitle, aw->shellName,
	       XtNiconName, cp->cd->mainkey,
	       XtNiconPixmap, annoteIconPixmap, NULL);
   if (cp->cd->field[nannote] != NULL)
      {hlpstring = (String)XtCalloc(strlen(cp->cd->field[nannote])+1, sizeof(char));
       strcpy(hlpstring, cp->cd->field[nannote]);
       }
   else 
      hlpstring = NULL;
   aw->annoteWin = XtVaCreateManagedWidget("annoteWin",
		    panedWidgetClass, aw->annoteShell, NULL);
   aw->cmdBox    = XtVaCreateManagedWidget("commandBox",
                    boxWidgetClass, aw->annoteWin, NULL);
   aw->save      = XtVaCreateManagedWidget("save",
                    commandWidgetClass, aw->cmdBox, NULL);
   aw->close     = XtVaCreateManagedWidget("close",
                    commandWidgetClass, aw->cmdBox, NULL);
   cwp->annote = XtVaCreateManagedWidget("AnnoteText",
		    asciiTextWidgetClass, aw->annoteWin,
		    XtNtype, XawAsciiString,
		    XtNeditType, XawtextEdit, 
		    XtNstring, hlpstring,
		    XtNscrollHorizontal, XawtextScrollWhenNeeded,
		    XtNscrollVertical, XawtextScrollWhenNeeded, NULL);
   cp->aw = aw;
   XtAddCallback(aw->close, XtNcallback, annoteCloseCmd, (XtPointer)cp);
   XtAddCallback(aw->save, XtNcallback, annoteSaveCmd, (XtPointer)cp);
   XtAddCallback(XawTextGetSource(cwp->annote), XtNcallback, annoteChanged,
		 (XtPointer) cp);
   XtPopup(cp->aw->annoteShell, XtGrabNone);
   return;
}


/*********************************************************************/
/* ccdDeleteCardCmd:                                                 */
/*    Callback function for command "Delete" in card window          */
/*********************************************************************/
void 
ccdDeleteCardCmd (Widget w, XtPointer clientData, XtPointer callData)
{
CardPtr cp = (CardPtr)clientData;
BibPtr bp = (BibPtr)cp->bp;
CardDataList cl, clp;
Errcode status;

   /* remove card from list of cards for list window */
   if (gulListWinExists(bp)){
    if (cp->cd->mainkey!=NULL){
      cl = clp = bp->lw->cardLst;
      if (strcmp(cp->cd->mainkey, clp->data->mainkey) == 0) {
	 bp->lw->cardLst = clp->next;
	 cl = clp->next;
	 dbtDeleteCard(&clp->data); 
      }
      else {
	 while (clp->next != NULL) {
	    if (strcmp(cp->cd->mainkey, clp->next->data->mainkey) == 0) {
               dbtDeleteCard(&clp->next->data); 
	       clp->next = clp->next->next;
	       break;
	    }
	    clp = clp->next;
	 } /* endwhile */
      }

      /* Update list window */
      if (cl != NULL) {
	 bp->lw->cardLst = NULL;
	 if ((status = gulReplaceListData(bp, cl)) != OK) {
	    guwError(status);
	    gulCloseListWin(bp);
	 }
      }
      else {
	 if ((status = gulCloseListWin(bp)) != OK)
	    guwError(status);
      }
    }
   }

   /* remove window */
   if ((status = gucCloseCardWin(cp)) != OK) 
      guwError(status);
   
   /* delete card from data tree */
   if ((status = dbtDelete(bp->treeIdx, cp->cd)) != DBT_OK) {
      guwError(status);
      return;
   }
   bp->changed = TRUE;
   

}


/*********************************************************************/
/* ccdChangeCardCmd:                                                 */
/*    Callback function for command "Change" in card window          */
/*********************************************************************/
void 
ccdChangeCardCmd (Widget w, XtPointer clientData, XtPointer callData)
{
CardPtr cp = (CardPtr)clientData;
BibPtr bp = (BibPtr)cp->bp;
CardWidgetsPtr cwp = &cp->cw->ct.cw;
CardDataList cl, clp;
Errcode status;
XawTextBlock textblock;
CardData *hcard = NULL;
String str;

   /* delete old card from data tree */
   if ((status = dbtDelete(bp->treeIdx, cp->cd)) != DBT_OK) {
      guwError(status);
      return;
   }

   if (cp->aw != NULL)
      annoteClose(cp);

   /* remove old card from list of cards for list window, keep node */
   if (gulListWinExists(bp)) {
      cl = clp = bp->lw->cardLst;
      if (strcmp(cp->cd->mainkey, clp->data->mainkey) == 0) {
	 dbtDeleteCard(&clp->data);
         cl = cl->next;
      }
      else {
	 while (clp->next != NULL) {
	    if (strcmp(cp->cd->mainkey, clp->next->data->mainkey) == 0) {
               dbtDeleteCard(&clp->next->data);
	   /*    clp = clp->next; */
	       clp->next = clp->next->next;
	       break;
	    }
	    clp = clp->next;
	 } /* endwhile */
      } /* endelse */
   } /* endif */

   /* save data from text widgets to card */
   if ((status = gucSaveCardData(cp)) != OK) {
      guwError(status);
      gulCloseListWin(bp);
      return;
   }

   /* insert new card in data tree, possibly new mainkey */
   CopyCard(&hcard, cp->cd);
   if ((status = dbtInsert(bp, hcard)) != DBT_OK) { 
      guwError(status);
      gulCloseListWin(bp);
      return;
   }
   
   if (strcmp(cp->cd->mainkey, hcard->mainkey) != 0){
      textblock.firstPos = 0;
      textblock.length = strlen(hcard->mainkey);
      textblock.ptr = hcard->mainkey;
      textblock.format = FMT8BIT;

      XawTextReplace(cwp->mainkey, (XawTextPosition) 0, 
             (XawTextPosition) strlen(cp->cd->mainkey),
             (XawTextBlock *) &textblock);
      XawTextSetInsertionPoint(cwp->mainkey, (XawTextPosition) 0);
      XtVaGetValues(cwp->mainkey, XtNstring, &str, NULL);
      XtFree(cp->cd->mainkey);
      cp->cd->mainkey = glbNewString(str);
      }

   cp->changed = FALSE;
   bp->changed = TRUE;

   /* update node in list window with new card */
   if (gulListWinExists(bp)) {
      if ((status = dbtCardListInsert(&cl,hcard,bp->sortedby)) != DBT_OK)  
	 guwError(status);
      /* replace "new" list with not existent old */
      bp->lw->cardLst = NULL;
      if ((status = gulReplaceListData(bp, cl)) != OK) {
	 guwError(status);
	 gulCloseListWin(bp);
      }
   } /* endif */

   /* Check if data in card is OK */
   if (cotRequiredFields()) {
      if ((status = dbtTestCard(cp->cd)) != DBT_OK) {
         guwWarning(status);
	 }
   }

   dbtDeleteCard(&hcard);


}

/*********************************************************************/
/* ccdDuplicateCardCmd:                                              */
/*    Callback function for command "Duplicate" in card window       */
/*********************************************************************/
void 
ccdDuplicateCardCmd (Widget w, XtPointer clientData, XtPointer callData)
{
CardPtr cp = (CardPtr)clientData;
BibPtr bp = (BibPtr)cp->bp;
Errcode status;
CardType type;
CardDataPtr cd = cp->cd;

   gcp = cp;

   sscanf(XtName(w), "item%d", &type);
   type -= 1;

   /* create new internal data for a card window */
   if ((status = glbDupCardListEl(bp, &cp, cd, type)) != OK) {
      guwError(status);
      return;
   }

   /* open the window */
   if ((status = gucOpenCardWin(bp, cp, TRUE)) != OK)
      guwError(status);
}


/*********************************************************************/
/* ccdCopyCardCmd:                                                   */
/*    Callback function for command "Copy" in card window            */
/*********************************************************************/
void 
ccdCopyCardCmd (Widget w, XtPointer clientData, XtPointer callData)
{
CardPtr cp = (CardPtr)clientData;
Errcode status;

   gcp = cp;
   if ((status = guwSelectBib("copyHead", ccdCopyCard1)) != OK)
      guwError(status);
}


/*********************************************************************/
/* ccdCopyCard1:                                                     */
/*    intermediate function for copy card                            */
/*********************************************************************/
Errcode
ccdCopyCard1 (BibPtr bp)
{
BibPtr p = gcp->bp;

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

   return(ccdCopyCard(bp, gcp));
}


/*********************************************************************/
/* ccdCopyCard:                                                      */
/*    copy card from one bib to another bib                          */
/*********************************************************************/
Errcode
ccdCopyCard (BibPtr bp, CardPtr cp)
{
Errcode status;
CardDataList cl;
CardData *hcard = NULL;
   
   /* Check if data in card is OK */
   if (cotRequiredFields()) {
      if ((status = dbtTestCard(cp->cd)) != DBT_OK) {
         guwWarning(status);
	 }
   }

   /* insert new card in data tree, possibly new mainkey */
   CopyCard(&hcard, cp->cd);
   if ((status = dbtInsert(bp, hcard)) != DBT_OK) { 
      guwError(status);
      return(status);
   }
   /* insert card in list of cards for list window */
   if (gulListWinExists(bp)) {
      cl = bp->lw->cardLst;
      if ((status = dbtCardListInsert(&cl,hcard,bp->sortedby)) != DBT_OK) { 
         guwError(status);
         return(status);
         }
      bp->lw->cardLst = NULL;
      if ((status = gulReplaceListData(bp, cl)) != OK) {
         guwError(status);
         gulCloseListWin(bp);
         }
   }
   bp->changed = TRUE;
   dbtDeleteCard(&hcard);

   return(OK);
}



/*********************************************************************/
/* ccdSetChangeFlag:                                                 */
/*    Set flag that card fields have changed                         */
/*********************************************************************/
void
ccdSetChangeFlag (Widget w, XtPointer clientData, XtPointer callData)
{
CardPtr cp = (CardPtr)clientData;

   cp->changed = TRUE;
}


/*********************************************************************/
/* ccdCloseCardCmd:                                                  */
/*    Callback for close card command in card window                 */
/*********************************************************************/
void
ccdCloseCardCmd (Widget w, XtPointer clientData, XtPointer callData)
{
CardPtr cp = (CardPtr)clientData;

   ccdCloseCard(cp->bp, cp);
}


/*********************************************************************/
/* ccdCloseCard:                                                     */
/*    close card window, check for changes                           */
/*********************************************************************/
Errcode
ccdCloseCard (BibPtr bp, CardPtr cp)
{
Errcode status;

   /* check for unsaved changes */
   if (cp->changed || gucStdFldsChanged(cp)) {
      cp->changed = TRUE;
      confirmCloseCard(cp);
      return(OK);
   }
   
   if (cp->aw != NULL)
      annoteClose(cp);

/* close card window */
   if ((status = gucCloseCardWin(cp)) != OK) {
      guwError(status);
      return(status);
   }

   return(OK);
}


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

static void
annoteChanged (Widget w, XtPointer clientData, XtPointer callData)
{
CardPtr cp = (CardPtr)clientData;

cp->aw->changed = TRUE;
}

/*********************************************************************/
/* confirmCloseCard:                                                 */
/*    Opens dialogbox for user to confirm closing without saving     */
/*********************************************************************/
static void
confirmCloseCard (CardPtr cp)
{
Position dx, dy, x, y;

   XtVaGetValues(desktop,
                 XtNx, &dx,
                 XtNy, &dy, NULL);
   XtTranslateCoords(cp->cw->cardDesk,
                     (Position)dx + SUBWIN_MARGIN,
                     (Position)dy + SUBWIN_MARGIN,
                     &x, &y);
   gcp = cp;
   guwConfirmClose(x,y,cancelQuitCmd,cardQuitOkCmd);
}



/*********************************************************************/
/* confirmCloseAnnote:                                                 */
/*    Opens dialogbox for user to confirm closing without saving     */
/*********************************************************************/
static void
confirmCloseAnnote (CardPtr cp)
{
Position dx, dy, x, y;

   XtVaGetValues(desktop,
                 XtNx, &dx,
                 XtNy, &dy, NULL);
   XtTranslateCoords(desktop,
                     (Position)dx + SUBWIN_MARGIN,
                     (Position)dy + SUBWIN_MARGIN,
                     &x, &y);
   gcp = cp;
   guwConfirmClose(x,y,cancelQuitCmd,annoteQuitOkCmd);
}

/*********************************************************************/
/* cancelQuitCmd:                                                    */
/*    Callback function for QUIT button in confirm box               */
/*********************************************************************/
static void
cancelQuitCmd (Widget w, XtPointer clientData, XtPointer callData)
{
Widget shell = (Widget)clientData;

   /* remove confirm shell */
   XtPopdown(shell);
   gcp = NULL;
   XtSetSensitive(mainMenu, TRUE);
   gubSetSensitive(NULL, TRUE);
}


/*********************************************************************/
/* CardQuitOkCmd:                                                    */
/*    Callback function for OK button in confirm box                 */
/*********************************************************************/
static void
cardQuitOkCmd (Widget w, XtPointer clientData, XtPointer callData)
{
Widget shell = (Widget)clientData;
Errcode status;

   /* remove confirm shell */
   XtPopdown(shell);

   /* close card window */
   if ((status = gucCloseCardWin(gcp)) != OK) {
      guwError(status);
      return;
   }
   gcp = NULL;

   /* enable menus */
   XtSetSensitive(mainMenu, TRUE);
   gubSetSensitive(NULL, TRUE);
}


/*********************************************************************/
/* annoteQuitOkCmd:                                                  */
/*    Callback function for OK button in confirm box                 */
/*********************************************************************/
static void
annoteQuitOkCmd (Widget w, XtPointer clientData, XtPointer callData)
{
Widget shell = (Widget)clientData;
Errcode status;

   /* remove confirm shell */
   XtPopdown(shell);

   /* close card window */
   if ((status = annoteClose(gcp)) != OK) {
      guwError(status);
      return;
   }
   
   gcp = NULL;

   /* enable menus */
   XtSetSensitive(mainMenu, TRUE);
   gubSetSensitive(NULL, TRUE);
}

