#include "precomp.h"

#define MAXPROFILELEN   60

// leading - non-zero looks a lot better
#define LEADING (max(ExtPrintLeading,yPrintChar/4))

// offset to start of body of card
#define BODYOFFSET (yPrintChar+LEADING+2*LINEWIDTH +10*LINEWIDTH)

// offset from left of card to print title or body of text
#define XTEXTOFFSET (xPrintChar/2)

// width of lines in pixels
#define LINEWIDTH 1

/************************************************************************/
/*                                                                      */
/*  Windows Cardfile - Written by Mark Cliggett                         */
/*  (c) Copyright Microsoft Corp. 1985, 1994 - All Rights Reserved      */
/*                                                                      */
/************************************************************************/

#if DBG
TCHAR dbuf[100];
VOID PrintLogFont( LOGFONT lf )
{
    wsprintf(dbuf,TEXT("lfHeight          %d\n"), lf.lfHeight        ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfWidth           %d\n"), lf.lfWidth         ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfEscapement      %d\n"), lf. lfEscapement   ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfOrientation     %d\n"), lf.lfOrientation   ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfWeight          %d\n"), lf.lfWeight        ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfItalic          %d\n"), lf.lfItalic        ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfUnderline       %d\n"), lf.lfUnderline     ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfStrikeOut       %d\n"), lf.lfStrikeOut     ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfCharSet         %d\n"), lf.lfCharSet       ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfOutPrecision    %d\n"), lf.lfOutPrecision  ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfClipPrecison    %d\n"), lf.lfClipPrecision ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfQuality         %d\n"), lf.lfQuality       ); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfPitchAndFamily  %d\n"), lf.lfPitchAndFamily); ODS(dbuf);
    wsprintf(dbuf,TEXT("lfFaceName        %s\n"), lf.lfFaceName      ); ODS(dbuf);
}
#endif

NOEXPORT void NEAR PrintHeaderFooter (HDC hDC, SHORT i);

NOEXPORT void GetDateTime(TCHAR *szTime, TCHAR *szDate);

TCHAR DefaultNullStr[] = TEXT("");

HWND hAbortDlgWnd;
INT fAbort;
INT bError;
INT iTabSize;

INT xPrintChar;         /* width of char on printer */
INT yPrintChar;         /* height of char on printer */
INT xPrintCard;         /* width of card on printer */
INT yPrintCard;         /* height of card on printer */
INT yCardSpace;         /* Space between card titles */

INT ExtPrintLeading;
INT xHeadFoot;
BOOL bCenter, bRight;
INT xPrintRes;
INT yPrintRes;
INT yPixelsPerInch;        /* pixels/inch */
INT xPixelsPerInch;        /* pixels/inch */


/* Flag if printer setup was done. */
BOOL bPrinterSetupDone=FALSE;
/*
 * all of these are in device units (for printer) and are calculated
 * by SetupPrinting()
 */

/* Had to use HEAD since HEADER already has another def.  */
#define HEAD   0
#define FOOTER 1

int dyTop;        /* width of top border */
int dyBottom;        /* width of bottom border */
int dxLeft;        /* width of left border */
int dxRight;        /* width of right border (this doesn't get used) */
int dyHeadFoot;        /* height from top/bottom of headers and footers */

int iPageNum;        /* global page number currently being printed */
int xLeftSpace, xRightSpace; /* Space of margins */
INT xCharPage;

FARPROC lpfnAbortProc;
FARPROC lpfnAbortDlgProc;
FARPROC lpfnPageDlgProc;

/* We'll dynamically allocate this */
HANDLE hHeadFoot=NULL;
LPTSTR  szHeadFoot;

void NEAR FreePrintHandles()
{
    if(PD.hDevMode)
        GlobalFree(PD.hDevMode);
    if(PD.hDevNames)
        GlobalFree(PD.hDevNames);
    PD.hDevMode = PD.hDevNames = NULL;
    bPrinterSetupDone = FALSE;
}

/* Get dafault printer data using the commdlg code for printer setup. */
BOOL NEAR GetDefaultPrinter()
{
    FreePrintHandles();

    PD.lStructSize     = sizeof(PRINTDLG);
    PD.Flags         = PD_PRINTSETUP|PD_RETURNDEFAULT;
    if (PrintDlg((LPPRINTDLG)&PD))
    {
        bPrinterSetupDone = TRUE;
        return TRUE;
    }
    else
    {
        FreePrintHandles();
        return FALSE;
    }
}

/* Call the commdlg code for printer setup. */
void PrinterSetupDlg(HWND hwnd)
{
    BOOL bTryAgain = (PD.hDevMode || PD.hDevNames);
    DWORD dwErr;

    LockData(0);
    PD.Flags = PD_PRINTSETUP;    /* invoke only the Setup dialog */

TryPrintSetupAgain:
    bPrinterSetupDone |= PrintDlg(&PD);

    /* set szPrinter and free hDevMode and hDevNames */
    /* PrintDlg error. */
    if(dwErr = CommDlgExtendedError()) /* Re-initialize the PD structure. */
    {
        PD.lStructSize    = sizeof(PRINTDLG);
        PD.hwndOwner      = hwnd;
        PD.hDC            = NULL;
        PD.nCopies        = 1;
        FreePrintHandles();
        if (bTryAgain)
        {
            bTryAgain = FALSE;
            goto TryPrintSetupAgain;
        }
        else if (dwErr != PDERR_NODEFAULTPRN)
        {
            TCHAR szError[256];

            LoadString(hIndexInstance, E_PRINT_SETUP_ERROR, szError, CharSizeOf(szError));
            MessageBox(hwnd, szError, szCardfile, MB_OK | MB_ICONHAND);
        }
    }
    UnlockData(0);
}

/*
 * convert floating point strings (like 2.75 1.5 2) into number of pixels
 * given the number of pixels per inch
 */
INT atopix(
    TCHAR *ptr,
    INT pix_per_in)
{
    TCHAR *dot_ptr;
    TCHAR sz[20];
    INT decimal;

    lstrcpy(sz, ptr);
    dot_ptr = _tcschr(sz, szDec[0]);
    if (dot_ptr)
    {
        *dot_ptr++ = 0;        /* terminate the inches */
        if (*(dot_ptr + 1) == (TCHAR) 0)
        {
            *(dot_ptr + 1) = TEXT('0');   /* convert decimal part to hundredths */
            *(dot_ptr + 2) = (TCHAR) 0;
        }
        decimal = ((int)MyAtol(dot_ptr) * pix_per_in) / 100;    /* first part */
    }
    else
        decimal = 0;        /* there is not fraction part */

    return ((INT)MyAtol(sz) * pix_per_in) + decimal;     /* second part */
}

HDC GetPrinterDC(
    void)
{
    LPDEVMODE lpDevMode;
    LPDEVNAMES lpDevNames;

    if (!bPrinterSetupDone) /* Retrieve default printer if none selected. */
    {
        if (!GetDefaultPrinter())
            return NULL;
    }

    lpDevNames  = (LPDEVNAMES)GlobalLock(PD.hDevNames);
    if (PD.hDevMode)
        lpDevMode = (LPDEVMODE)GlobalLock(PD.hDevMode);
    else
        lpDevMode = NULL;

    /* For pre 3.0 drivers lpDevMode will be null as these drivers don't
     * use this structure.
     */
    PD.hDC = CreateDC(((LPTSTR)lpDevNames)+lpDevNames->wDriverOffset,
                      ((LPTSTR)lpDevNames)+lpDevNames->wDeviceOffset,
                      ((LPTSTR)lpDevNames)+lpDevNames->wOutputOffset,
                      lpDevMode);
    GlobalUnlock(PD.hDevNames);
    if (PD.hDevMode)
        GlobalUnlock(PD.hDevMode);

    return PD.hDC;
}

HDC SetupPrintingFailed(
    HDC hPrintDC)
{
    if (hPrintDC)
        DeleteDC(hPrintDC);
    IndexOkError(ECANTPRINT);
    return NULL;
}

/*
 * setup the printer, return it's DC and create printing (abort)
 * dialog box.
 */
HDC SetupPrinting( BOOL bUseFont )
{
    TCHAR      buf[80];
    DWORD      nSpace;
    HDC        hPrintDC;
    TEXTMETRIC Metrics;
    DOCINFO    DocInfo;
    INT        iErr;
    HFONT      hPrintFont;       // font in print DC
    HFONT      hPrevFont;        // previous font in print DC

    /*
     * On second print job, this was getting used
     * before the dialog was created for the second time.
     */
    hAbortDlgWnd = (HWND)NULL;

    if (!(hPrintDC = GetPrinterDC()))
        return SetupPrintingFailed(hPrintDC);

    xPrintRes       = GetDeviceCaps(hPrintDC, HORZRES);
    yPrintRes       = GetDeviceCaps(hPrintDC, VERTRES);
    xPixelsPerInch  = GetDeviceCaps(hPrintDC, LOGPIXELSX);
    yPixelsPerInch  = GetDeviceCaps(hPrintDC, LOGPIXELSY);


    // if need be, use user defined font in printer


    if( bUseFont )
    {
        LOGFONT lf;            // temp version of FontStruct

        lf= FontStruct; 
        lf.lfHeight= - (iPointSize * yPixelsPerInch ) / (72*10);
        lf.lfWidth= 0;   // let font mapper figure it out
        lf.lfQuality= DEFAULT_QUALITY;
        hPrintFont = CreateFontIndirect(&lf);

        if( hPrintFont )
        {
            //PrintLogFont( lf );
            hPrevFont= SelectObject( hPrintDC, hPrintFont );
            DeleteObject( hPrevFont );
        }
        // if not successful, just use default font
    }

    GetTextMetrics(hPrintDC, &Metrics);
    yPrintChar = Metrics.tmHeight + Metrics.tmExternalLeading;
    ExtPrintLeading = Metrics.tmExternalLeading;
    xPrintChar = Metrics.tmAveCharWidth;    /* character width */
    iTabSize = xPrintChar*8;

    dyHeadFoot = yPixelsPerInch / 2;                  /* 1/2 an inch */
    dyTop      = atopix(chPageText[4], yPixelsPerInch);
    dyBottom   = atopix(chPageText[5], yPixelsPerInch);
    dxLeft     = atopix(chPageText[2], xPixelsPerInch);
    dxRight    = atopix(chPageText[3], xPixelsPerInch);

#if !defined(WIN32)
    nSpace = GetTextExtent(hPrintDC, TEXT(" "), 1 )
#else
    {
      SIZE  sz ;

      GetTextExtentPoint(hPrintDC , TEXT(" "), 1, &sz);

      nSpace = sz.cx;
    }
#endif
    xLeftSpace  = dxLeft / nSpace;
    xRightSpace = dxRight / nSpace;

    /* Number of characters between margins */
    xCharPage = (xPrintRes / xPrintChar) - xLeftSpace - xRightSpace;

    /* Allocate memory for the header.footer string.  Will allow any size
     * of paper and still have enough for the string.
     */
    hHeadFoot = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, ByteCountOf(xCharPage+2));

    if (!hHeadFoot)
        return SetupPrintingFailed (hPrintDC);

    SetAbortProc (hPrintDC, fnAbortProc);

    BuildCaption (buf, CharSizeOf(buf));

    /* Gotta disable the window before doing the start doc so that the user
     * can't quickly do multiple prints.
     */
    EnableWindow (hIndexWnd, FALSE);

    DocInfo.cbSize = sizeof (DOCINFO);
    DocInfo.lpszDocName  = buf;
    DocInfo.lpszOutput   = NULL;
    DocInfo.lpszDatatype = NULL;
    DocInfo.fwType       = 0;

    if ((iErr = StartDoc (hPrintDC, &DocInfo)) < 0)
    {
        DeleteDC (hPrintDC);
        EnableWindow (hIndexWnd, TRUE);
        if (iErr == SP_USERABORT)
            SendMessage (hIndexWnd, WM_SETFOCUS, 0, 0);
        else
            IndexOkError (ECANTPRINT);
        return NULL;
    }

    bError = FALSE;
    fAbort = FALSE;
    hAbortDlgWnd = CreateDialog(hIndexInstance, (LPTSTR) DTABORTDLG,
                                hIndexWnd, (DLGPROC)fnAbortDlgProc);
    if (!hAbortDlgWnd)
    {
        EnableWindow(hIndexWnd, TRUE);
        return SetupPrintingFailed(hPrintDC);
    }
    return hPrintDC;
}

void FinishPrinting (HDC hPrintDC)
{
    if (!fAbort)
    {
        if (!bError)
            EndDoc(hPrintDC);
        EnableWindow (hIndexWnd, TRUE);
        DestroyWindow (hAbortDlgWnd);
    }
    DeleteDC (hPrintDC);
    if (hHeadFoot)
        GlobalFree (hHeadFoot);
    hHeadFoot = NULL;
}


/*
 * print out the translated header/footer string in proper position.
 *
 * uses global stuff like xPrintChar, dyHeadFoot...
 */
NOEXPORT void NEAR PrintHeaderFooter (HDC hDC,SHORT nHF)
{
    TCHAR    buf[80];
    SHORT   len;

    lstrcpy (buf, chPageText[nHF]);

    szHeadFoot = GlobalLock (hHeadFoot);
    len = TranslateString (buf);

    if (*szHeadFoot)
    {
        if (nHF == HEAD)
        {
            TabbedTextOut (hDC, dxLeft, dyHeadFoot - yPrintChar, szHeadFoot,
                           len, 1, &iTabSize, dxLeft);
        }
        else
        {
            TabbedTextOut (hDC, dxLeft, yPrintRes-yPrintChar-dyHeadFoot,
                           szHeadFoot, len, 1, &iTabSize, dxLeft);
        }
    }
    GlobalUnlock (hHeadFoot);
}

void PrintList (void)
{
    HDC hPrintDC;
    INT curcard;
    INT i, y, Start, End;
    INT cCardsPerPage;
    LPCARDHEADER Cards;
    INT iError;


    hPrintDC = SetupPrinting( TRUE );
    if (!hPrintDC)
    {
        if (hHeadFoot)
        {
            GlobalFree (hHeadFoot);
            hHeadFoot = NULL;
        }
        return;
    }

    cCardsPerPage = max (1, (yPrintRes - dyTop - dyBottom) / yPrintChar);

    iPageNum = 1;

    Cards = (LPCARDHEADER) GlobalLock (hCards);

    y = dyTop - yPrintChar;

    for (curcard = 0; curcard < cCards; )
    {
        iError = StartPage(hPrintDC);
        if (iError < 0)
        {
            PrintError (iError);
            break;
        }

        PrintHeaderFooter (hPrintDC, HEAD);

        Start = curcard;
        End = curcard + cCardsPerPage;
        if (End > cCards)
            End = cCards;
        for (i = Start; i < End; ++i, curcard++)
        {
            TabbedTextOut (hPrintDC, dxLeft, y, Cards[i].line,
                           lstrlen(Cards[i].line), 1, &iTabSize, dxLeft);
            y += yPrintChar;
        }

        PrintHeaderFooter (hPrintDC, FOOTER);
        iPageNum++;

        /* Reset y so printing starts at top again. */
        y = dyTop - yPrintChar;

        iError = EndPage(hPrintDC);
        if (iError < 0)
        {
            PrintError (iError);
            break;
        }
        if (fAbort)
            break;
    }
    GlobalUnlock (hCards);
    FinishPrinting (hPrintDC);
}

void PrintCards (INT count)
{
    HDC          hPrintDC;
    INT          curcard;
    INT          i;
    INT          y;
    INT          cCardsPerPage;
    CARDHEADER   CardHead;
    LPCARDHEADER Cards;
    CARD         Card;
    HDC          hMemoryDC;
    HWND         hPrintWnd;
    HANDLE       hOldObject;
    INT          fPictureWarning;
    INT          iError;
    TEXTMETRIC   Metrics;

    hPrintWnd = CreateWindow(TEXT("Edit"), NULL,
        WS_CHILD | ES_MULTILINE,
        0, 0, (LINELENGTH * CharFixWidth) + 1, CARDLINES * CharFixHeight,
        hIndexWnd, NULL, hIndexInstance, NULL);

    /* Set fixed pitched font to this edit control, so that the text does
     * not get chopped off at the right when we print, because we use
     * fixed pitched font;
     * Fix for Bug #3760 --SANKAR-- 02-22-90
     */
    if (hPrintWnd)
        SendMessage(hPrintWnd, WM_SETFONT, (WPARAM) hFont, MAKELPARAM(TRUE, 0));

    if (!hPrintWnd)
    {
        IndexOkError(EINSMEMORY);
        if (hHeadFoot)
        {
            GlobalFree(hHeadFoot);
            hHeadFoot=NULL;
        }
        return;
    }

    if (!(hPrintDC = SetupPrinting( TRUE )))
    {
        if (hHeadFoot)
        {
            GlobalFree(hHeadFoot);
            hHeadFoot = NULL;
        }
        return;
    }

    //            length of text + offset on each end + line width
    xPrintCard = (LINELENGTH * xPrintChar) + XTEXTOFFSET*2 + 2*LINEWIDTH;

    //           start of body + size of body
    yPrintCard = BODYOFFSET + (CARDLINES * yPrintChar);
    yCardSpace = yPixelsPerInch/4;

    hOldObject = SelectObject(hPrintDC, GetStockObject(HOLLOW_BRUSH));

    hMemoryDC = CreateCompatibleDC(hPrintDC);
    fPictureWarning = FALSE;

    if (count == 1)
    {
        iPageNum = 1;
        if (!hMemoryDC && CurCard.lpObject)
            IndexOkError (ENOPICTURES);

        if ((iError = StartPage (hPrintDC)) < 0)
            PrintError (iError);

        PrintHeaderFooter (hPrintDC, HEAD);
        PrintCurCard (hPrintDC, hMemoryDC, dxLeft, dyTop, &CurCardHead, &CurCard, hEditWnd);
        PrintHeaderFooter (hPrintDC, FOOTER);

        if ((iError = EndPage (hPrintDC)) < 0)
            PrintError (iError);
    }
    else
    {
        iPageNum = 1;

        // extra yCardSpace in case it spills to next page during card spacing

        cCardsPerPage = max(1, (yPrintRes - dyTop - dyBottom + yCardSpace) / (yPrintCard + yCardSpace));

        for (curcard = 0; curcard < count; )
        {
            if ((iError = StartPage (hPrintDC)) < 0)
                PrintError (iError);

            PrintHeaderFooter (hPrintDC, HEAD);
            y = dyTop;
            for (i = 0; i < cCardsPerPage && curcard < count; ++i)
            {
                if (curcard != iFirstCard)
                {
                    Cards = (LPCARDHEADER) GlobalLock(hCards);
                    CardHead = Cards[curcard];
                    GlobalUnlock(hCards);
                    if (!ReadCurCardData(&CardHead, &Card, szText))
                        IndexOkError(ECANTPRINTPICT);
                }
                else
                {
                    CardHead = CurCardHead;
                    Card = CurCard;
                    GetWindowText(hEditWnd, szText, CARDTEXTSIZE);
                }
                SetWindowText(hPrintWnd, szText);
                if (!hMemoryDC && Card.lpObject && !fPictureWarning)
                {
                    fPictureWarning++;
                    IndexOkError(ENOPICTURES);
                }
                PrintCurCard(hPrintDC, hMemoryDC, dxLeft, y, &CardHead, &Card, hPrintWnd);

                if (curcard != iFirstCard && Card.lpObject)
                    PicDelete(&Card);

                y += yPrintCard + yCardSpace;
                curcard++;
            }

            PrintHeaderFooter(hPrintDC, FOOTER);

            iPageNum++;

            if ((iError = EndPage (hPrintDC)) < 0)
            {
                PrintError (iError);
                break;
            }
            if (fAbort)
                break;

        }
    }

    DestroyWindow (hPrintWnd);
    SelectObject (hPrintDC, hOldObject);
    FinishPrinting (hPrintDC);
    if (hMemoryDC)
        DeleteDC (hMemoryDC);
}

void PrintCurCard(
    HDC hPrintDC,
    HDC hMemoryDC,
    INT xPos,                    // x offset of upper left
    INT yPos,                    // y offset of upper left
    PCARDHEADER pCardHead,
    PCARD   pCard,
    HWND    hWnd)
{
    INT y;
    HANDLE hOldObject;
    INT level;
    INT i;
    INT cLines;
    TCHAR buf[LINELENGTH];
    INT cch;

    // Draw the card outline

    Rectangle(hPrintDC,
              max( 0, xPos ),
              max( 0, yPos ),
              xPos + xPrintCard,
              yPos + yPrintCard);

    // draw a narrow (LINEWIDTH) box separating title from body of card

    Rectangle(hPrintDC,
              max( 0, xPos ),
              yPos + yPrintChar + LEADING,
              xPos + xPrintCard,
              yPos + BODYOFFSET - LINEWIDTH );

    // Draw the card title

    SetBkMode(hPrintDC, TRANSPARENT);
    TabbedTextOut(hPrintDC,
                  xPos + XTEXTOFFSET,
                  yPos + (LEADING/2),  // center top to bottom
                  pCardHead->line,
                  lstrlen(pCardHead->line),
                  1,
                  &iTabSize,
                  xPos+XTEXTOFFSET);

    // Print any object embedded in card! (wonder what AVI objects do?)

    if (pCard->lpObject && hMemoryDC)
    {
        HBITMAP hBitmap;
        BITMAP  bm;

        level = SaveDC(hPrintDC);

        IntersectClipRect(hPrintDC,
                          xPos + 1,
                          yPos + BODYOFFSET,
                          xPos + xPrintCard-1,
                          yPos + yPrintCard-1);

        /* Get a bitmap to print */
        if (GetObjectType( pCard->lpObject) != OBJ_BITMAP)
        {
            hBitmap = MakeObjectCopy(pCard, hPrintDC );
        }
        else
        {
            hBitmap = (HANDLE)pCard->lpObject ;
        }

        GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
        hOldObject = SelectObject(hMemoryDC, hBitmap);


        if (!StretchBlt(hPrintDC,
            xPos + (pCard->rcObject.left * xPrintChar) / CharFixWidth,
            yPos + BODYOFFSET + (pCard->rcObject.top * yPrintChar) / CharFixHeight,
            (bm.bmWidth * xPrintChar) / CharFixWidth,
            (bm.bmHeight * yPrintChar) / CharFixHeight,
            hMemoryDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY))
        {
            IndexOkError(ECANTPRINTPICT);
        }

        SelectObject(hMemoryDC, hOldObject);
        RestoreDC(hPrintDC, level);

        if (GetObjectType( pCard->lpObject) != OBJ_BITMAP)
             DeleteObject(hBitmap);
    }

    /* draw the text */
    /* we should really be using DrawText and EM_GETHANDLE */

    y = yPos + BODYOFFSET;
    cLines = SendMessage(hWnd, EM_GETLINECOUNT, 0, 0L);
    for (i = 0; i < cLines; ++i)
    {
        buf[0] = LINELENGTH;
        buf[1] = 0;
        cch = (INT)SendMessage(hWnd, EM_GETLINE, i, (LPARAM)buf);
        TabbedTextOut(hPrintDC, xPos + 1, y, buf, cch,
                1, (LPINT)&iTabSize, xPos + 1);
        y += yPrintChar;
    }
}

int fnAbortProc(
    HDC hPrintDC,       /* what is this useless parameter? */
    int iReserved)      /* and this one? Good question! */
{
    MSG msg;

    while (!fAbort && PeekMessage (&msg, NULL, 0, 0, TRUE))
    if (!hAbortDlgWnd || !IsDialogMessage (hAbortDlgWnd, (LPMSG)&msg))
    {
        TranslateMessage ((LPMSG)&msg);
        DispatchMessage ((LPMSG)&msg);
    }
    return(!fAbort);

    hPrintDC;
    iReserved;
}

HANDLE hSysMenu;

/*
 * dialog procedure for the print dialog
 *
 * this allows the user to cancel printing
 */
int fnAbortDlgProc(
    HWND hwnd,
    UINT msg,
    WPARAM wParam,
    LPARAM lParam)
{
    LPTSTR pchTmp;

    switch(msg)
    {
        case WM_COMMAND:
            fAbort = TRUE;
            EnableWindow(hIndexWnd, TRUE);
            DestroyWindow(hwnd);
            hAbortDlgWnd = NULL;
            return(TRUE);

        case WM_INITDIALOG:
            hSysMenu = GetSystemMenu(hwnd, FALSE);
            if (CurIFile[0])
                pchTmp = FileFromPath(CurIFile);
            else
                pchTmp = szUntitled;

            SetDlgItemText(hwnd, DTNAME, pchTmp);
            SetFocus(hwnd);
            return(TRUE);

        case WM_INITMENU:
            EnableMenuItem(hSysMenu, SC_CLOSE, MF_GRAYED);
            return(TRUE);
    }
    return(FALSE);

    wParam;
    lParam;
}

void PrintError (int iError)
{
    bError = TRUE;
    if (iError & SP_NOTREPORTED)
    {
        switch(iError)
        {
            case -5:
                IndexOkError(EMEMPRINT);
                break;
            case -4:
                IndexOkError(EDISKPRINT);
                break;
            case -3:
            case -2:
                break;
            default:
                IndexOkError(ECANTPRINT);
                break;
        }
    }
}

/***************************************************************************
 * short TranslateString(char *src)
 *
 * purpose:
 *    translate a header/footer strings
 *
 *     supports the following:
 *
 *    &&    insert a & char
 *    &f    current file name or (untitiled)
 *    &d    date in Day Month Year
 *    &t    time
 *    &p    page number
 *    &p+num    set first page number to num
 *
 * params:
 *    IN/OUT    src    this is the string to translate, gets filled with
 *            translate string.  limited by len chars
 *    IN    len    # chars src pts to
 *
 * used by:
 *    Header Footer stuff
 *
 * uses:
 *    lots of c lib stuff
 *
 * restrictions:
 *     this function uses the following global data
 *
 *    iPageNum
 *    text from main window caption
 * NOTE : Resides in _TEXT segment so that it can call C runtimes
 * most of the print code is in _PRINT segment
 *
 ***************************************************************************/

short TranslateString(
    TCHAR *src)
{
    extern int iPageNum;
    extern INT xCharPage;
    extern LPTSTR  szHeadFoot;

    TCHAR         letters[15];
    TCHAR         chBuff[3][80], buf[80];
    TCHAR         *ptr, *dst=buf, *save_src=src;
    int          page;
    short        nAlign=1, foo, nx,
                 nIndex[3];

    nIndex[0]=0;
    nIndex[1]=0;
    nIndex[2]=0;

    LoadString(hIndexInstance, IDS_LETTERS, letters, CharSizeOf(letters));

    while (*src)   /* look at all of source */
    {
        while (*src && *src != TEXT('&'))
        {
            if( IsDBCSLeadByte(*src))
            {
                chBuff[nAlign][nIndex[nAlign]]=*src++;
                nIndex[nAlign] += 1;
            }
            chBuff[nAlign][nIndex[nAlign]]=*src++;
            nIndex[nAlign] += 1;
        }

        if (*src == TEXT('&'))   /* is it the escape char? */
        {
            src++;

            if (*src == letters[0] || *src == letters[1])
            {                      /* &f file name (no path) */

                /* a bit of sleaze... get the caption from
                 * the main window.  search for the '-' and
                 * look two chars beyond, there is the
                 * file name or (untitled) (cute huh?)
                 */

                GetWindowText(hIndexWnd, buf, 80);
                ptr=_tcschr(buf, TEXT('-')) + 2;

                /* Copy to the currently aligned string. */
                lstrcpy((chBuff[nAlign]+nIndex[nAlign]), ptr);

                /* Update insertion position. */
                nIndex[nAlign] += lstrlen(ptr);
            }
            else if (*src == letters[2] || *src == letters[3])
            {                      /* &P or &P+num page */
                src++;
                page = 0;
                if (*src == TEXT('+'))       /* &p+num case */
                {
                    src++;
                    while (_istdigit(*src))
                        {
                        /* Convert to int on-the-fly*/
                        page = (10*page)+(TCHAR)(*src)-48;
                        src++;
                        }
                }

                wsprintf(buf, TEXT("%d"), iPageNum+page);
                lstrcpy((chBuff[nAlign]+nIndex[nAlign]), buf);
                nIndex[nAlign] += lstrlen(buf);
                src--;
            }
            else if (*src == letters[4] || *src == letters[5])
            {                      /* &t time */

                GetDateTime(buf, NULL);

                /* extract time */
                _tcsncpy(chBuff[nAlign]+nIndex[nAlign], buf, lstrlen(buf));
                nIndex[nAlign] += lstrlen(buf);
            }
            else if (*src == letters[6] || *src == letters[7])
            {                      /* &d date */
                GetDateTime(NULL, buf);
                /* extract day month day */
                _tcsncpy(chBuff[nAlign]+nIndex[nAlign], buf, lstrlen(buf));
                nIndex[nAlign] += lstrlen(buf);
            }
            else if (*src == TEXT('&'))
            {               /* quote a single & */
                chBuff[nAlign][nIndex[nAlign]]=TEXT('&');
                nIndex[nAlign] += 1;
            }
            /* Set the alignment for whichever has last occured. */
            else if (*src == letters[8] || *src == letters[9])
                nAlign=1;                    /* &c center */
            else if (*src == letters[10] || *src == letters[11])
                nAlign=2;                    /* &r right */
            else if (*src == letters[12] || *src == letters[13])
                nAlign=0;                   /* &d date */
            src++;
        }
    }
    /* Make sure all strings are null-terminated. */
    for (nAlign=0; nAlign<3; nAlign++)
        chBuff[nAlign][nIndex[nAlign]]=0;

    /* Initialize Header/Footer string */
    for (nx=0; nx<xCharPage; nx++)
        *(szHeadFoot+nx)=32;

    /* Copy Left aligned text. */
    for (nx=0; nx < nIndex[0]; nx++)
        *(szHeadFoot+nx)=chBuff[0][nx];

    /* Calculate where the centered text should go. */
    foo=(xCharPage-nIndex[1])/2;
    for (nx=0; nx<nIndex[1]; nx++)
        *(szHeadFoot+foo+nx)=(TCHAR)chBuff[1][nx];

    /* Calculate where the right aligned text should go. */
    foo=xCharPage-nIndex[2];
    for (nx=0; nx<nIndex[2]; nx++)
        *(szHeadFoot+foo+nx)=(TCHAR)chBuff[2][nx];


    return lstrlen(szHeadFoot);
}

TIME Time;
DATE Date;

/* ** Get current date and time from dos, and build string showing same.
      String must be formatted according to country info obtained from
      win.ini. */
static void GetDateTime(TCHAR *szTime, TCHAR *szDate)
{
  register int i = 0, j = 0;
  int          isAM = TRUE;
  BOOL         bLead;
  TCHAR        cSep;
  SYSTEMTIME   st;


    GetLocalTime (&st);

    if (!szTime)
       goto GetDate;

    if (Time.iTime)
       wsprintf (szTime, Time.iTLZero ? TEXT("%02d%c%02d") : TEXT("%d%c%02d"),
                 st.wHour, Time.szSep[0], st.wMinute);
    else
    {
       if (st.wHour > 12)
       {
          st.wHour -= 12;
          isAM = FALSE;
       }
       wsprintf (szTime, Time.iTLZero ? TEXT("%02d%c%02d%s") : TEXT("%d%c%02d%s"),
                 st.wHour, Time.szSep[0], st.wMinute, isAM ? Time.sz1159 : Time.sz2359);
    }

GetDate:
    if (!szDate)
       return;

    while (Date.szFormat[i] && (j < MAX_FORMAT - 1))
    {
        bLead = FALSE;
        switch (cSep = Date.szFormat[i++])
        {
            case TEXT('d'):
                if (Date.szFormat[i] == TEXT('d'))
                {
                    bLead = TRUE;
                    i++;
                }
                if (bLead || (st.wDay / 10))
                    szDate[j++] = TEXT('0') + st.wDay / 10;
                szDate[j++] = TEXT('0') + st.wDay % 10;
                break;

            case TEXT('M'):
                if (Date.szFormat[i] == TEXT('M'))
                {
                    bLead = TRUE;
                    i++;
                }
                if (bLead || (st.wMonth / 10))
                    szDate[j++] = TEXT('0') + st.wMonth / 10;
                szDate[j++] = TEXT('0') + st.wMonth % 10;
                break;

            case TEXT('y'):
                i++;
                if (Date.szFormat[i] == TEXT('y'))
                {
                    bLead = TRUE;
                    i+=2;
                }
                if (bLead)
                {
                    szDate[j++] = (st.wYear < 2000 ? TEXT('1') : TEXT('2'));
                    szDate[j++] = (st.wYear < 2000 ? TEXT('9') : TEXT('0'));
                }
                szDate[j++] = TEXT('0') + (st.wYear % 100) / 10;
                szDate[j++] = TEXT('0') + (st.wYear % 100) % 10;
                break;

            default:
                /* copy the current character into the formatted string - it
                 * is a separator. BUT: don't copy a separator into the
                 * very first position (could happen if the year comes first,
                 * but we're not using the year)
                 */
                if (j)
                    szDate[j++] = cSep;
                break;
        }
    }
    while ((szDate[j-1] < TEXT('0')) || (szDate[j-1] > TEXT('9')))
        j--;
    szDate[j] = TEXT('\0');
}