/***********************************************************************/
/*                                                                     */
/*                           Objective Caml                            */
/*                                                                     */
/*             Damien Doligez, projet Para, INRIA Rocquencourt         */
/*                                                                     */
/*  Copyright 1997 Institut National de Recherche en Informatique et   */
/*  en Automatique.  All rights reserved.  This file is distributed    */
/*  under the terms of the GNU Library General Public License, with    */
/*  the special exception on linking described in file ../LICENSE.     */
/*                                                                     */
/***********************************************************************/

/* $Id: files.c,v 1.5 2001/12/07 13:39:46 xleroy Exp $ */

#include "main.h"

static unsigned long nuntitled = 0;
static unsigned long count = 2;

/* XXX prvoir le cas o on peut crire le texte mais pas les ressources
   -> resrefnum peut tre -1 quand datarefnum est valide
*/

static void MakeUntitledTitle (Str255 result)
{
  char buffer [15];

  GetIndString (result, kMiscStrings, kUntitledIdx);
  if (nuntitled !=  0){
    if (result [0] > 240) result [0] = 240;
    sprintf (buffer, " %lu", count);   Assert (strlen (buffer) < 15);
    strcpy ((char *) result + result [0] + 1, buffer);
    result [0] += strlen (buffer);
    ++ count;
  }else{
    count = 2;
  }
  ++ nuntitled;
}

static void FreeUntitledTitle ()
{
  -- nuntitled;
}

/* Close the file associated with the window, saving it if needed. */
OSErr FileDoClose (WindowPtr w, ClosingOption close)
{
  WStatusH st;
  WEHandle we;
  Str255 savingprompt, filename;
  short item;
  OSErr err;

  Assert (WinGetKind (w) == kWinDocument);
  WinUpdateStatus (w);
  st = WinGetStatus (w);  Assert (st != NULL);
  we = WinGetWE (w);      Assert (we != NULL);
  GetWTitle (w, filename);
  if ((*st)->menuflags.save){
    GetIndString (savingprompt, kMiscStrings, kClosingIdx + close);
    ParamText (filename, savingprompt, NULL, NULL);
    InitCursor ();
    modalkeys = kKeysSaveDontCancel;
    item = Alert (kAlertSaveAsk, myModalFilterUPP);
    switch (item){
    case 1: /* Yes */
      err = FileDoSave (w, 0);
      if (err != noErr) return err;
      break;
    case 2: /* Cancel */
      return userCanceledErr;
    case 3: /* No */
      break;
    default: Assert (0);
    }
  }else{
    if ((*st)->resrefnum != -1){
      /* XXX sauver fenetre, selection, scrollbars */
    }
  }
  if ((*st)->datarefnum == -1){
    Assert ((*st)->resrefnum == -1);
    FreeUntitledTitle ();
  }else{
    FSClose ((*st)->datarefnum);
    if ((*st)->resrefnum != -1) CloseResFile ((*st)->resrefnum);
  }
  return noErr;
}

/* Open a new untitled window. */
void FileNew (void)
{
  Str255 titlebuf;
  WindowPtr w;
  OSErr err;
  WStatusH st;

  MakeUntitledTitle (titlebuf);
  w = WinOpenDocument ((StringPtr) titlebuf);
  if (w == NULL) {err = 0/*XXX*/; goto failed; }
  st = WinGetStatus (w);  Assert (st != NULL);
  (*st)->datarefnum = (*st)->resrefnum = -1;
  return;

  failed:
    if (w != NULL) WinDoClose (closingWindow, w);
    ErrorAlertGeneric (err);
}

/* Open the specified file in a new window. */
OSErr FileOpen (FSSpec *filespec)
 {
  WindowPtr w = NULL;
  WStatusH st;
  StringPtr title;
  Str255 titlebuf;
  short resrefnum = -1, datarefnum = -1;
  Size textsize;
  Handle texthandle = NULL;
  OSErr err;
  int template;
  SignedByte perm;
  FInfo fileinfo;

  err = FSpGetFInfo (filespec, &fileinfo);
  if (err != noErr) goto failed;
  if (fileinfo.fdFlags & kIsStationery){
    MakeUntitledTitle (titlebuf);
    title = (StringPtr) titlebuf;
    template = 1;
  }else{
    title = (StringPtr) filespec->name;
    template = 0;
  }
  perm = template ? fsRdPerm : fsRdWrPerm;

  err = FSpOpenDF (filespec, perm, &datarefnum);
  if (err != noErr){ datarefnum = -1; goto failed; }
  err = GetEOF (datarefnum, &textsize);
  if (err != noErr) goto failed;
  err = SetFPos (datarefnum, fsFromStart, 0L);
  if (err != noErr) goto failed;
  err = AllocHandle (textsize, &texthandle);
  if (err != noErr) goto failed;
  HLock (texthandle);
  err = FSRead (datarefnum, &textsize, *texthandle);
  HUnlock (texthandle);
  if (err != noErr) goto failed;

  /*XXX FSpCreateResFile (filespec, creator, type, 0); */
  resrefnum = FSpOpenResFile (filespec, perm);
  if (resrefnum != -1){
    /* XXX lire la position de la fentre, la slection, les scrollbars */
  }

  w = WinOpenDocument (title);
  if (w == NULL) { err = 0/*XXX*/; goto failed; }
  st = WinGetStatus (w);  Assert (st != NULL);

  WEUseText (texthandle, (*st)->we);
  WECalText ((*st)->we);
  WESetSelection (0, 0, (*st)->we);  /* XXX */
  AdjustScrollBars (w);
  WEResetModCount ((*st)->we);
  (*st)->basemodcount = 0;

  if (template){
    FSClose (datarefnum);
    if (resrefnum != -1) CloseResFile (resrefnum);
    (*st)->datarefnum = (*st)->resrefnum = -1;
  }else{
    (*st)->datarefnum = datarefnum;
    (*st)->resrefnum = resrefnum;
  }
  return noErr;

  failed:
    if (texthandle != NULL) DisposeHandle (texthandle);
    if (datarefnum != -1) FSClose (datarefnum);
    if (resrefnum != -1) CloseResFile (resrefnum);
    if (w != NULL) WinDoClose (closingWindow, w);
    return err;
}

/* Get a file with the standard dialog and open it in a new window. */
void FileDoGetOpen (void)
{
  OSErr err;
  StandardFileReply sfreply;
  SFTypeList types = { 'TEXT' };

  StandardGetFile (NULL, 1, types, &sfreply);
  if (sfreply.sfGood){
    err = FileOpen (&sfreply.sfFile);
    if (err != noErr) ErrorAlertCantOpen (sfreply.sfFile.name, err);
  }
}

/* Revert w to the contents of its associated file. */
void FileRevert (WindowPtr w)
{
  WStatusH st;
  short err;
  Size textsize;
  Handle texthandle;

  /*XXX demander confirmation */

  st = WinGetStatus (w);
  Assert (st != NULL);
  Assert ((*st)->datarefnum != -1);
  Assert ((*st)->we != NULL);

  err = GetEOF ((*st)->datarefnum, &textsize);
  if (err != noErr) goto failed;
  err = SetFPos ((*st)->datarefnum, fsFromStart, 0L);
  if (err != noErr) goto failed;
  err = AllocHandle (textsize, &texthandle);
  if (err != noErr) goto failed;
  HLock (texthandle);
  err = FSRead ((*st)->datarefnum, &textsize, *texthandle);
  HUnlock (texthandle);
  if (err != noErr) goto failed;

  /* XXX lire la slection (pas la scrollbar ?) */

  SetPortWindowPort (w);
  WEUseText (texthandle, (*st)->we);
  WECalText ((*st)->we);
  WEUpdate (NULL, (*st)->we);
  WESetSelection (0, 0, (*st)->we);  /* XXX */
  AdjustScrollBars (w);
  WEResetModCount ((*st)->we);
  (*st)->basemodcount = 0;
  return;

  failed:
    if (texthandle != NULL) DisposeHandle (texthandle);
    ErrorAlertGeneric (err);
}

/* Save the text to datarefnum.
   If resrefnum != -1, save the window position and the current selection.
*/
static OSErr SaveText (WindowPtr w, short datarefnum, short resrefnum)
{
  WStatusH st = WinGetStatus (w);
  Handle text;
  Size textsize;
  OSErr err;

  Assert (st != NULL);
  Assert ((*st)->we != NULL);
  err = SetEOF (datarefnum, 0L);
  if (err != noErr) goto failed;
  text = WEGetText ((*st)->we);
  textsize = GetHandleSize (text);
  HLock (text);
  err = FSWrite (datarefnum, &textsize, *text);
  HUnlock (text);
  if (err != noErr) goto failed;
  (*st)->basemodcount = WEGetModCount ((*st)->we);

  if (resrefnum != -1){
    /* XXX crire la slection et la position des scrollbars
     attention: pas de fail. */
  }
  return noErr;

  failed:
    return err;
}

/* Ask the user for a new file name, open both forks, and return
   the refnums.
*/
static OSErr PrepSaveAs (WindowPtr w, short *datarefnum, short *resrefnum,
                         StandardFileReply *reply)
{
  Str255 prompt, title;
  OSErr err;
  short auxrefnum = -1;

  *datarefnum = *resrefnum = -1;

  GetIndString (prompt, kMiscStrings, kSaveAsPromptIdx);
  GetWTitle (w, title);
  StandardPutFile (prompt, title, reply);

  if (reply->sfGood){
    if (reply->sfReplacing){
      err = FSpOpenDF (&reply->sfFile, fsRdWrPerm, datarefnum);
      if (err != noErr) *datarefnum = -1;
      if (err == opWrErr || err == fLckdErr || err == afpObjectLocked
          || err == permErr || err == afpAccessDenied || err == wrPermErr){
        ErrorAlert (kCannotWriteIdx, reply->sfFile.name, kCloseQuoteIdx, err);
      }
      if (err != noErr) goto failed;

      err = FSpOpenRF (&reply->sfFile, fsRdWrPerm, &auxrefnum);
      if (err != noErr) auxrefnum = -1;
      if (err == opWrErr || err == fLckdErr || err == afpObjectLocked
          || err == permErr || err == afpAccessDenied){
        ErrorAlert (kCannotWriteIdx, reply->sfFile.name, kCloseQuoteIdx, err);
      }
      if (err != noErr) goto failed;

      err = SetEOF (auxrefnum, 0L);
      if (err != noErr) goto failed;
      FSClose (auxrefnum); auxrefnum = -1;
      FSpCreateResFile (&reply->sfFile, kCreatorCaml,kTypeText,reply->sfScript);
      err = ResError (); if (err != noErr) goto failed;
      *resrefnum = FSpOpenResFile (&reply->sfFile, fsRdWrPerm);
      if (*resrefnum == -1){ err = ResError (); goto failed; } /*XXX ?? */

      err = SetEOF (*datarefnum, 0L);
      if (err != noErr) goto failed;

    }else{
      err = FSpCreate (&reply->sfFile, kCreatorCaml, kTypeText,reply->sfScript);
      if (err != noErr) goto failed;
      FSpCreateResFile (&reply->sfFile, kCreatorCaml,kTypeText,reply->sfScript);
      err = ResError (); if (err != noErr) goto failed;
      err = FSpOpenDF (&reply->sfFile, fsRdWrPerm, datarefnum);
      if (err != noErr){ *datarefnum = -1; goto failed; }
      *resrefnum = FSpOpenResFile (&reply->sfFile, fsRdWrPerm);
      if (*resrefnum == -1){ err = ResError (); goto failed; } /*XXX ?? */
    }
  }else{
    err = userCanceledErr;
    goto failed;
  }
  return noErr;

  failed:
    if (*datarefnum != -1) FSClose (*datarefnum);
    if (*resrefnum != -1) CloseResFile (*resrefnum);
    if (auxrefnum != -1) FSClose (auxrefnum);
    return err;
}

/* If saveasflag is true or there is no associated file,
   then ask for a new file name with the standard dialog
   and associate it with w.

   Save the contents of w to its associated file.
*/
static OSErr SaveDocument (WindowPtr w, int saveasflag)
{
  WStatusH st = WinGetStatus (w);
  OSErr err;
  int changetitle = 0;
  short datarefnum = -1, resrefnum = -1;

  Assert (st != NULL);
  if (saveasflag || (*st)->datarefnum == -1){
    StandardFileReply reply;

    err = PrepSaveAs (w, &datarefnum, &resrefnum, &reply);
    if (err != noErr) goto failed;

    if ((*st)->datarefnum == -1){
      Assert ((*st)->resrefnum == -1);
      FreeUntitledTitle ();
    }else{
      FSClose ((*st)->datarefnum);
      if ((*st)->resrefnum != -1) CloseResFile ((*st)->resrefnum);
      (*st)->datarefnum = (*st)->resrefnum = -1;
    }
    (*st)->datarefnum = datarefnum;
    (*st)->resrefnum = resrefnum;
    SetWTitle (w, reply.sfFile.name);
    datarefnum = resrefnum = -1;
  }
  err = SaveText (w, (*st)->datarefnum, (*st)->resrefnum);
  if (err != noErr) goto failed;
  return noErr;

  failed:
    if (datarefnum != -1) FSClose (datarefnum);
    if (resrefnum != -1) CloseResFile (resrefnum);
    return err;
}

/* Save the toplevel window to a new file.  Do not save the window
   position or the current selection.
*/
static OSErr SaveToplevel (void)
{
  WStatusH st;
  StandardFileReply reply;
  short datarefnum = -1, resrefnum = -1;
  OSErr err;

  Assert (winToplevel != NULL);
  st = WinGetStatus (winToplevel);
  Assert (st != NULL);

  err = PrepSaveAs (winToplevel, &datarefnum, &resrefnum, &reply);
  if (err != noErr) goto failed;
  err = SaveText (winToplevel, datarefnum, -1);
  if (err != noErr) goto failed;
  FSClose (datarefnum);
  if (resrefnum != -1) CloseResFile (resrefnum);
  return noErr;

  failed:
    if (datarefnum != -1) FSClose (datarefnum);
    if (resrefnum != -1) CloseResFile (resrefnum);
    return err;
}

static OSErr SaveGraphics (void)
{
  XXX ();
  return noErr;
}

OSErr FileDoSave (WindowPtr w, int saveasflag)
{
  if (w == winToplevel) return SaveToplevel ();
  else if (w == winGraphics) return SaveGraphics ();
  else return SaveDocument (w, saveasflag);
}
