/*********************************************************************/
/*  bibView: Administration of BibTeX-Databases                      */
/*           (Verwaltung von BibTeX-Literaturdatenbanken)            */
/*                                                                   */
/*  Module:  ctl_save.c                                              */
/*                                                                   */
/*             Close / Save Control                                  */
/*             - Menu function Save                                  */
/*             - Menu function Save as                               */
/*                                                                   */
/*  Author:  Holger Martin,  martinh@informatik.tu-muenchen.de       */
/*           Peter M. Urban, urban@informatik.tu-muenchen.de         */
/*                                                                   */
/*  History:                                                         */
/*    18.02.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/Shell.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/Box.h>
#include "FileNom.h"
#include "bibview.h"


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


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


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


/* local function prototypes */
/* ------------------------- */
static void confirmClose (BibPtr bp);
static void closeCmdOk (Widget w, XtPointer clientData, XtPointer callData);
static void cancelCloseCmd (Widget w, XtPointer clientData, XtPointer callData);
static void getFilename (BibPtr bp);
static void getFnameOk (Widget w, XtPointer clientData, XtPointer callData);
static void cancelGetFname (Widget w, XtPointer clientData, XtPointer callData);
static Errcode renameWindowTitles (BibPtr bp, String newName);


/* local global variables */
/* ---------------------- */
static BibPtr gbp = NULL;



/*********************************************************************/
/* csaQuitBibviewCmd:                                                */
/*    Callback function for command quit in main file menu           */
/*********************************************************************/
void
csaQuitBibviewCmd (Widget w, XtPointer clientData, XtPointer callData)
{
BibPtr bpold, bp;
CardPtr cp;
Boolean unsaved = FALSE;

   /* close bibs first (checks for unsaved changes) */
   bp = glbFirstBibListEl();
   while (bp != NULL) {
      /* check for unsaved changes to cards and macros */
      cp = glbFirstCardListEl(bp);
      while (cp != NULL) {
	 if (cp->changed || gucStdFldsChanged(cp)) {
	    unsaved = TRUE;
	    break;
	 }
	 cp = glbNextCardListEl(bp, cp);
      }
      if (bp->mw && bp->mw->changed)
	 unsaved = TRUE;
      if (bp->changed)
	 unsaved = TRUE;

      if (unsaved) {
         csaCloseBib(bp);
	 return;
      }  

      bpold = bp;
      bp = glbNextBibListEl(bp);
      glbDelBibListEl(bpold); 
   }
  
   exit(0);
}


/*********************************************************************/
/* csaCloseBibCmd:                                                   */
/*    Callback function for command close bib  in main menu          */
/*********************************************************************/
void
csaCloseBibCmd (Widget w, XtPointer clientData, XtPointer callData)
{
Errcode status;

   if ((status = guwSelectBib("closeHead", csaCloseBib)) != OK)
      guwWarning(status);
}


/*********************************************************************/
/* csaCloseCmd:                                                      */
/*    Callback function for command close/quit in bib win menu       */
/*********************************************************************/
void
csaCloseCmd (Widget w, XtPointer clientData, XtPointer callData)
{
BibPtr bp = (BibPtr)clientData;

   csaCloseBib(bp);
}


/*********************************************************************/
/* csaCloseBib:                                                      */
/*    Close bibliography file (ask if not saved)                     */
/*********************************************************************/
Errcode
csaCloseBib (BibPtr bp)
{
CardPtr cp;
Boolean unsaved = FALSE;
Errcode status;
   

   /* check for unsaved changes to cards and macros */
   cp = glbFirstCardListEl(bp);
   while (cp != NULL) {
      if (!cp->changed && !gucStdFldsChanged(cp)) {
	 gucCloseCardWin(cp);
	 cp = glbFirstCardListEl(bp);
      }
      else
	 unsaved = TRUE;
      cp = glbNextCardListEl(bp, cp);
   }
   if (bp->mw && bp->mw->changed)
      unsaved = TRUE;

   /* if opened and unsaved cards found, reorder them */
   if (unsaved)
      gucCascade(bp);

   /* confirm trashing unsaved cards or previous changes to bib */
   if (unsaved || bp->changed) {
      confirmClose(bp);
      return(OK);
   }

   /* delete database tree */
   if ((status = dbtDeleteTree(bp->treeIdx)) != DBT_OK) {
      guwError(status);
      return(status);
   }
   if ((status = gubCloseBibWin(bp)) != OK) {
      guwError(status);
      return(status);
   }

   return(OK);
}


/*********************************************************************/
/* csaSaveBibCmd:                                                    */
/*    Callback function for command save in file menu                */
/*********************************************************************/
void
csaSaveBibCmd (Widget w, XtPointer clientData, XtPointer callData)
{
Errcode status;

   if ((status = guwSelectBib("saveHead", csaSaveBib)) != OK)
      guwWarning(status);
}


/*********************************************************************/
/* csaSaveCmd:                                                       */
/*    Callback function for command save in bib window menu          */
/*********************************************************************/
void
csaSaveCmd (Widget w, XtPointer clientData, XtPointer callData)
{
BibPtr bp = (BibPtr)clientData;
Errcode status;

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


/*********************************************************************/
/* csaSaveBib:                                                       */
/*    Save bibliography to disk                                      */
/*********************************************************************/
Errcode
csaSaveBib (BibPtr bp)
{
int status;

   /* check whether bib has a real name */
   if (strncmp(bp->filename, "noname", 6) == 0) {
      getFilename(bp);
      return(OK);
   }


   if (glbCheckPath(bp->filepath, bp->filename) != OK)
      return(BIF_EWRITE);

   /* make .bak file of original */
   if (cotBackupBeforeSave()) 
      glbMakeBackup(bp->filepath);

   /* write out file to disk */
   if ((status = bifFileWrite(bp)) != DBT_OK) {
      guwError(status);
      return(status);
   }
   bp->changed = FALSE;
   
   return(OK);
}


/*********************************************************************/
/* csaSaveAsBibCmd:                                                  */
/*    Callback function for command save as in file menu             */
/*********************************************************************/
void
csaSaveAsBibCmd (Widget w, XtPointer clientData, XtPointer callData)
{
Errcode status;

   if ((status = guwSelectBib("saveAsHead", csaSaveAsBib)) != OK)
      guwWarning(status);
}


/*********************************************************************/
/* csaSaveAsBib:                                                     */
/*    Save bibliography under new name to disk                       */
/*********************************************************************/
Errcode
csaSaveAsBib (BibPtr bp)
{
   getFilename(bp);
   return(OK);
}



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

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

   XtVaGetValues(bp->bw->bibdesk,
                 XtNx, &dx,
                 XtNy, &dy, NULL);
   XtTranslateCoords(desktop,
                     (Position)dx + SUBWIN_MARGIN,
                     (Position)dy + SUBWIN_MARGIN,
                     &x, &y);
   guwConfirmClose(x,y,cancelCloseCmd,closeCmdOk);
   gbp = bp;
}


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

   XtPopdown(shell);
   XtSetSensitive(mainMenu, TRUE);
   gubSetSensitive(NULL, TRUE);
   gbp = NULL;
}


/*********************************************************************/
/* closeCmdOk:                                                       */
/*    Callback function for OK button in confirm box                 */
/*********************************************************************/
static void
closeCmdOk (Widget w, XtPointer clientData, XtPointer callData)
{
Widget shell = (Widget) clientData;
char sysStr[2*MAX_FILEPATHLEN];
int status;

   XtPopdown(shell);
   /* remove file select box */
   XtSetSensitive(mainMenu, TRUE);
   gubSetSensitive(NULL, TRUE);

   if ((status = dbtDeleteTree(gbp->treeIdx)) != DBT_OK) {
      guwError(status);
   }
   if ((status = gubCloseBibWin(gbp)) != OK) {
      guwError(status);
   }
   if (gbp->macrofile != NULL)
      sprintf(sysStr, "rm -f %s %s", gbp->tempfile, 
		gbp->macrofile);
   else
      sprintf(sysStr, "rm -f %s", gbp->tempfile);
   system(sysStr);

   gbp = NULL;
}


/*********************************************************************/
/* getFilename:                                                      */
/*    Opens dialogbox for user to enter name of file                 */
/*********************************************************************/
static void
getFilename (BibPtr bp)
{
static Widget fsbShell, fsbBox, fsbDialog;
Position dx, dy, x, y;

   XtVaGetValues(desktop,
                 XtNx, &dx,
                 XtNy, &dy, NULL);
   XtTranslateCoords(desktop,
                     (Position)dx + SUBWIN_MARGIN,
                     (Position)dy + SUBWIN_MARGIN,
                     &x, &y);

   fsbShell  = XtVaCreatePopupShell("fileSelectBoxShell",
                 topLevelShellWidgetClass, desktop,
                 XtNx, x, XtNy, y, NULL);
   fsbBox    = XtVaCreateManagedWidget("fileSelectBox",
		 boxWidgetClass, fsbShell, NULL);
               XtVaCreateManagedWidget("fileRenameHead",
		 labelWidgetClass, fsbBox, 
		 XtNborderWidth, 0, NULL);
   fsbDialog = XtVaCreateManagedWidget("fileSelectBox",
                 fileNominatorWidgetClass, fsbBox, 
		 XtNborderWidth, 0, NULL);

   XtAddCallback(fsbDialog, XtNcancelCallback, cancelGetFname, fsbShell);
   XtAddCallback(fsbDialog, XtNselectCallback, getFnameOk, fsbDialog);

   XtSetSensitive(mainMenu, FALSE);
   gubSetSensitive(NULL, FALSE);
   gbp = bp;
   XtPopup(fsbShell, XtGrabNonexclusive);
}


/*********************************************************************/
/* cancelGetFname:                                                   */
/*    Callback function for CANCEL button in filename box            */
/*********************************************************************/
static void
cancelGetFname (Widget w, XtPointer clientData, XtPointer callData)
{
Widget shell = (Widget)clientData;

   XtSetSensitive(mainMenu, TRUE);
   gubSetSensitive(NULL, TRUE);
   XtPopdown(shell);
   gbp = NULL;
}


/*********************************************************************/
/* getFnameOk:                                                       */
/*    Callback function for OK button in filename box                */
/*********************************************************************/
static void
getFnameOk (Widget w, XtPointer clientData, XtPointer callData)
{
Widget dialog = (Widget) clientData;
String newName, newPath;
int status;

   /* get filename and rename windows */
   newName = (String)FileNominatorGetFileName(dialog);
   if (newName == NULL){
      XtPopdown(XtParent(XtParent(dialog)));
      XtSetSensitive(mainMenu, TRUE);
      gubSetSensitive(NULL, TRUE);
      guwError(NO_VALID_FILENAME);
      return;
      }
   strcpy(gbp->filename, newName);
   newPath = (String)FileNominatorGetFullFileName(dialog);
   if (newPath == NULL){
      XtPopdown(XtParent(XtParent(dialog)));
      XtSetSensitive(mainMenu, TRUE);
      gubSetSensitive(NULL, TRUE);
      guwError(NO_VALID_FILENAME);
      return;
      }
   strcpy(gbp->filepath, newPath);

   if (glbCheckPath(gbp->filepath, gbp->filename) != OK){
      XtPopdown(XtParent(XtParent(dialog)));
      XtSetSensitive(mainMenu, TRUE);
      gubSetSensitive(NULL, TRUE);
      guwError(BIF_EWRITE);
      return;
      }

   if ((status = renameWindowTitles(gbp, newName)) != OK)
      guwError(status);

   /* remove file select box */
   XtPopdown(XtParent(XtParent(dialog)));
   XtSetSensitive(mainMenu, TRUE);
   gubSetSensitive(NULL, TRUE);

   /* make .bak file of original */
   if (cotBackupBeforeSave())
      glbMakeBackup(gbp->filepath);

   /* write out file to disk */
   if ((status = bifFileWrite(gbp)) != DBT_OK) {
      guwError(status);
      return;
   }
   gbp->changed = FALSE;
   gbp = NULL;
}


/*********************************************************************/
/* renameWindowTitles:                                               */
/*    Rename titles of all open windows of a bib                     */
/*********************************************************************/
static Errcode
renameWindowTitles (BibPtr bp, String newName)
{
CardPtr cp;

   strcpy(bp->filename, newName);

   /* rename bib window */
   if (bp->bw->shellName)
      XtFree(bp->bw->shellName);
   if ((bp->bw->shellName =
          (String) XtCalloc(strlen(PROGNAME)+strlen(bp->filename)+4,
                          sizeof(char))) != NULL) {
      sprintf(bp->bw->shellName, "%s: %s", PROGNAME, bp->filename);
      XtVaSetValues(bp->bw->bibShell,
		    XtNtitle, bp->bw->shellName, 
		    XtNiconName, bp->filename, NULL);
   }
   else
      bp->bw->shellName = NULL;

   /* rename card windows */
   cp = glbFirstCardListEl(bp);
   while (cp != NULL) {
      if (cp->cw->shellName)
          XtFree(cp->cw->shellName);
      if ((cp->cw->shellName = (String)XtCalloc(strlen(bp->filename) +
					strlen(glbTypeToName(cp->cd->cardtype))+4,
					sizeof(char))) != NULL) {
         sprintf(cp->cw->shellName, "%s: %s", bp->filename, glbTypeToName(cp->cd->cardtype));
         XtVaSetValues(cp->cw->cardShell,
		       XtNtitle, cp->cw->shellName, NULL);
      } /* endif */
      else
	 cp->cw->shellName = NULL;
      cp = glbNextCardListEl(gbp, cp);
   } /* endwhile */

   /* rename list window */
   if (gulListWinExists(bp)) {
      if (bp->lw->shellName)
	    XtFree(bp->lw->shellName);
      if ((bp->lw->shellName = (String)XtCalloc(strlen(PROGNAME) +
                                              strlen(bp->filename)+10,
                                              sizeof(char))) != NULL) {
	 sprintf(bp->lw->shellName, "%s: List %s", PROGNAME, bp->filename);
         XtVaSetValues(bp->lw->lstShell,
		       XtNtitle, bp->lw->shellName, 
		       XtNiconName, bp->filename, NULL);
      } /* endif */
      else
	 bp->lw->shellName = NULL;
   } /* endif */

   /* rename macro window */
   if (gueMacroWinExists(bp)) {
      if (bp->mw->shellName)
	    XtFree(bp->mw->shellName);

      if ((bp->mw->shellName = (String)XtCalloc(strlen(PROGNAME) +
                                              strlen(bp->filename)+12,
                                              sizeof(char))) != NULL) {
	 sprintf(bp->mw->shellName, "%s: Macros %s", PROGNAME, bp->filename);
         XtVaSetValues(bp->mw->macShell,
		       XtNtitle, bp->mw->shellName, 
		       XtNiconName, bp->filename, NULL);
      } /* endif */
      else
	 bp->mw->shellName = NULL;
   } /* endif */

   return(OK);
}

