/*
* saveas.c
* Copyright (C) 1998-2001 A.J. van Os; Released under GPL
*
* Description:
* Functions to save the results as a textfile or a drawfile
*/

#include <stdio.h>
#include <string.h>
#include "DeskLib:Menu.h"
#include "DeskLib:Save.h"
#include "DeskLib:Template.h"
#include "DeskLib:Window.h"
#include "drawfile.h"
#include "antiword.h"

/* The window handle of the save window */
static window_handle    tSaveWindow = 0;

/* Xfer_send box fields */
#define DRAG_SPRITE     3
#define OK_BUTTON       0
#define CANCEL_BUTTON   (-1)
#define FILENAME_ICON   2


/*
* saveas - a wrapper around Save_InitSaveWindowhandler
*/
static void
saveas(int iFileType, char *szOutfile, size_t tEstSize,
       save_filesaver save_function, void *pvReference)
{
       TRACE_MSG("saveas");

       if (tSaveWindow == 0) {
               tSaveWindow = Window_Create("xfer_send", template_TITLEMIN);
       }
       Icon_SetText(tSaveWindow, FILENAME_ICON, szOutfile);
       Window_Show(tSaveWindow, open_UNDERPOINTER);
       (void)Save_InitSaveWindowHandler(tSaveWindow, FALSE, TRUE, TRUE,
               DRAG_SPRITE, OK_BUTTON, CANCEL_BUTTON, FILENAME_ICON,
               save_function, NULL, NULL, tEstSize, iFileType, pvReference);
} /* end of saveas */

static BOOL
bWrite2File(void *pvBytes, size_t tSize, FILE *pFile, const char *szFilename)
{
       if (fwrite(pvBytes, sizeof(char), tSize, pFile) != tSize) {
               werr(0, "I can't write to '%s'", szFilename);
               return FALSE;
       }
       return TRUE;
} /* end of bWrite2File */

/*
* bText2File - Save the generated draw file to a Text file
*/
static BOOL
bText2File(char *szFilename, void *pvHandle)
{
       FILE    *pFile;
       diagram_type    *pDiag;
       drawfile_object *pObj;
       drawfile_text   *pText;
       const char      *pcTmp;
       int     iToGo, iX, iYtopPrev, iHeight, iLines;
       BOOL    bFirst, bIndent, bSuccess;

       TRACE_MSG("bText2File");

       fail(szFilename == NULL || szFilename[0] == '\0');
       fail(pvHandle == NULL);

       DBG_MSG(szFilename);

       pDiag = (diagram_type *)pvHandle;
       pFile = fopen(szFilename, "w");
       if (pFile == NULL) {
               werr(0, "I can't open '%s' for writing", szFilename);
               return FALSE;
       }
       bFirst = TRUE;
       iYtopPrev = 0;
       iHeight = (int)lWord2DrawUnits20(DEFAULT_FONT_SIZE);
       bSuccess = TRUE;
       fail(pDiag->tInfo.length < offsetof(drawfile_diagram, objects));
       iToGo = pDiag->tInfo.length - offsetof(drawfile_diagram, objects);
       DBG_DEC(iToGo);
       pcTmp = (const char *)pDiag->tInfo.data +
                               offsetof(drawfile_diagram, objects);
       while (iToGo > 0 && bSuccess) {
               pObj = (drawfile_object *)pcTmp;
               switch (pObj->type) {
               case drawfile_TYPE_TEXT:
                       pText = &pObj->data.text;
                       /* Compute the number of lines */
                       iLines = (iYtopPrev - pText->bbox.max.y +
                                       iHeight / 2) / iHeight;
                       DBG_DEC_C(iLines < 0, iYtopPrev);
                       DBG_DEC_C(iLines < 0, pText->bbox.max.y);
                       fail(iLines < 0);
                       bIndent = iLines > 0 || bFirst;
                       bFirst = FALSE;
                       /* Print the newlines */
                       while (iLines > 0 && bSuccess) {
                               bSuccess = bWrite2File("\n",
                                       1, pFile, szFilename);
                               iLines--;
                       }
                       /* Print the indentation */
                       if (bIndent && bSuccess) {
                               for (iX = Drawfile_ScreenToDraw(8);
                                    iX <= pText->bbox.min.x && bSuccess;
                                    iX += Drawfile_ScreenToDraw(16)) {
                                       bSuccess = bWrite2File(" ",
                                               1, pFile, szFilename);
                               }
                       }
                       if (!bSuccess) {
                               break;
                       }
                       /* Print the text object */
                       bSuccess = bWrite2File(pText->text,
                               strlen(pText->text), pFile, szFilename);
                       /* Setup for the next object */
                       iYtopPrev = pText->bbox.max.y;
                       iHeight = pText->bbox.max.y - pText->bbox.min.y;
                       break;
               case drawfile_TYPE_FONT_TABLE:
               case drawfile_TYPE_PATH:
               case drawfile_TYPE_SPRITE:
               case drawfile_TYPE_JPEG:
                       /* These are not relevant in a textfile */
                       break;
               default:
                       DBG_DEC(pObj->type);
                       bSuccess = FALSE;
                       break;
               }
               pcTmp += pObj->size;
               iToGo -= pObj->size;
       }
       DBG_DEC_C(iToGo != 0, iToGo);
       if (bSuccess) {
               bSuccess = bWrite2File("\n", 1, pFile, szFilename);
       }
       (void)fclose(pFile);
       if (bSuccess) {
               vSetFiletype(szFilename, FILETYPE_TEXT);
       } else {
               (void)remove(szFilename);
               werr(0, "Unable to save textfile '%s'", szFilename);
       }
       return bSuccess;
} /* end of bText2File */

/*
* bSaveTextfile - save the diagram as a text file
*/
BOOL
bSaveTextfile(event_pollblock *pEvent, void *pvReference)
{
       diagram_type    *pDiag;
       size_t  tRecLen, tNbrRecs, tEstSize;

       TRACE_MSG("bSaveTextfile");

       fail(pEvent == NULL);
       fail(pvReference == NULL);

       pDiag = (diagram_type *)pvReference;

       switch (pEvent->type) {
       case event_SEND:        /* From a menu */
               fail(pEvent->data.message.header.action != message_MENUWARN);
               if (menu_currentopen != pDiag->pSaveMenu ||
                   pEvent->data.message.data.menuwarn.selection[0] !=
                                                       SAVEMENU_SAVETEXT) {
                       return FALSE;
               }
               break;
       case event_KEY:         /* From a key short cut */
               if (pEvent->data.key.caret.window != pDiag->tMainWindow) {
                       return FALSE;
               }
               break;
       default:
               DBG_DEC(pEvent->type);
               return FALSE;
       }

       tRecLen = sizeof(drawfile_text) + DEFAULT_SCREEN_WIDTH * 2 / 3;
       tNbrRecs = pDiag->tInfo.length / tRecLen + 1;
       tEstSize = tNbrRecs * DEFAULT_SCREEN_WIDTH * 2 / 3;
       DBG_DEC(tEstSize);

       saveas(FILETYPE_TEXT, "WordText", tEstSize, bText2File, pDiag);
       return TRUE;
} /* end of bSaveTextfile */

/*
* bDraw2File - Save the generated draw file to a Draw file
*
* Remark: This is not a simple copy action. The origin of the
* coordinates (0,0) must move from the top-left corner to the
* bottom-left corner.
*/
static BOOL
bDraw2File(char *szFilename, void *pvHandle)
{
       FILE            *pFile;
       diagram_type    *pDiagram;
       wimp_box        *pBbox;
       drawfile_object *pObj;
       drawfile_text   *pText;
       drawfile_path   *pPath;
       drawfile_sprite *pSprite;
       drawfile_jpeg   *pJpeg;
       int     *piPath;
       char    *pcTmp;
       int     iYadd, iToGo, iSize;
       BOOL    bSuccess;

       TRACE_MSG("bDraw2File");

       fail(szFilename == NULL || szFilename[0] == '\0');
       fail(pvHandle == NULL);

       NO_DBG_MSG(szFilename);

       pDiagram = (diagram_type *)pvHandle;
       pFile = fopen(szFilename, "wb");
       if (pFile == NULL) {
               werr(0, "I can't open '%s' for writing", szFilename);
               return FALSE;
       }
       iToGo = pDiagram->tInfo.length;
       DBG_DEC(iToGo);
       pcTmp = pDiagram->tInfo.data;
       bSuccess = bWrite2File(pcTmp,
                       offsetof(drawfile_diagram, bbox), pFile, szFilename);
       if (bSuccess) {
               pcTmp += offsetof(drawfile_diagram, bbox);
               iToGo -= offsetof(drawfile_diagram, bbox);
               pBbox = (wimp_box *)pcTmp;
               iYadd = -pBbox->min.y;
               pBbox->min.y += iYadd;
               pBbox->max.y += iYadd;
               bSuccess = bWrite2File(pcTmp,
                               sizeof(*pBbox), pFile, szFilename);
               iToGo -= sizeof(*pBbox);
               DBG_DEC(iToGo);
               pcTmp += sizeof(*pBbox);
       } else {
               iYadd = 0;
       }
       while (iToGo > 0 && bSuccess) {
               pObj = (drawfile_object *)pcTmp;
               iSize = pObj->size;
               switch (pObj->type) {
               case drawfile_TYPE_FONT_TABLE:
                       bSuccess = bWrite2File(pcTmp,
                                       iSize, pFile, szFilename);
                       pcTmp += iSize;
                       iToGo -= iSize;
                       break;
               case drawfile_TYPE_TEXT:
                       pText = &pObj->data.text;
                       /* First correct the coordinates */
                       pText->bbox.min.y += iYadd;
                       pText->bbox.max.y += iYadd;
                       pText->base.y += iYadd;
                       /* Now write the information to file */
                       bSuccess = bWrite2File(pcTmp,
                                       iSize, pFile, szFilename);
                       pcTmp += pObj->size;
                       iToGo -= pObj->size;
                       break;
               case drawfile_TYPE_PATH:
                       pPath = &pObj->data.path;
                       /* First correct the coordinates */
                       pPath->bbox.min.y += iYadd;
                       pPath->bbox.max.y += iYadd;
                       /* Now write the information to file */
                       bSuccess = bWrite2File(pPath,
                               sizeof(*pPath), pFile, szFilename);
                       pcTmp += sizeof(*pPath);
                       iSize = pObj->size - sizeof(*pPath);
                       fail(iSize < 14 * sizeof(int));
                       /* Second correct the path coordinates */
                       piPath = xmalloc(iSize);
                       memcpy(piPath, pcTmp, iSize);
                       piPath[ 2] += iYadd;
                       piPath[ 5] += iYadd;
                       piPath[ 8] += iYadd;
                       piPath[11] += iYadd;
                       if (bSuccess) {
                               bSuccess = bWrite2File(piPath,
                                       iSize, pFile, szFilename);
                               pcTmp += iSize;
                       }
                       piPath = xfree(piPath);
                       iToGo -= pObj->size;
                       break;
               case drawfile_TYPE_SPRITE:
                       pSprite = &pObj->data.sprite;
                       /* First correct the coordinates */
                       pSprite->bbox.min.y += iYadd;
                       pSprite->bbox.max.y += iYadd;
                       /* Now write the information to file */
                       bSuccess = bWrite2File(pcTmp,
                                       iSize, pFile, szFilename);
                       pcTmp += pObj->size;
                       iToGo -= pObj->size;
                       break;
               case drawfile_TYPE_JPEG:
                       pJpeg = &pObj->data.jpeg;
                       /* First correct the coordinates */
                       pJpeg->bbox.min.y += iYadd;
                       pJpeg->bbox.max.y += iYadd;
                       pJpeg->trfm.entries[2][1] += iYadd;
                       /* Now write the information to file */
                       bSuccess = bWrite2File(pcTmp,
                                       iSize, pFile, szFilename);
                       pcTmp += pObj->size;
                       iToGo -= pObj->size;
                       break;
               default:
                       DBG_DEC(pObj->type);
                       bSuccess = FALSE;
                       break;
               }
       }
       DBG_DEC_C(iToGo != 0, iToGo);
       (void)fclose(pFile);
       if (bSuccess) {
               vSetFiletype(szFilename, FILETYPE_DRAW);
       } else {
               (void)remove(szFilename);
               werr(0, "Unable to save drawfile '%s'", szFilename);
       }
       return bSuccess;
} /* end of bDraw2File */

/*
* bSaveDrawfile - save the diagram as a draw file
*/
BOOL
bSaveDrawfile(event_pollblock *pEvent, void *pvReference)
{
       diagram_type    *pDiag;
       size_t          tEstSize;

       TRACE_MSG("bSaveDrawfile");

       fail(pEvent == NULL);
       fail(pvReference == NULL);

       pDiag = (diagram_type *)pvReference;

       switch (pEvent->type) {
       case event_SEND:        /* From a menu */
               fail(pEvent->data.message.header.action != message_MENUWARN);
               if (menu_currentopen != pDiag->pSaveMenu ||
                   pEvent->data.message.data.menuwarn.selection[0] !=
                                                       SAVEMENU_SAVEDRAW) {
                       return FALSE;
               }
               break;
       case event_KEY:         /* From a key short cut */
               if (pEvent->data.key.caret.window != pDiag->tMainWindow) {
                       return FALSE;
               }
               break;
       default:
               DBG_DEC(pEvent->type);
               return FALSE;
       }

       tEstSize = pDiag->tInfo.length;
       DBG_DEC(tEstSize);

       saveas(FILETYPE_DRAW, "WordDraw", tEstSize, bDraw2File, pDiag);
       return TRUE;
} /* end of bSaveDrawfile */