//************************************************************************
// Generic Win 3.1 fax printer driver support. 32-bit printer driver
// functions. Runs in the graphics engine context (CSRSS).
//
// History:
//    02-jan-95   nandurir   created.
//    01-feb-95   reedb      Clean-up, support printer install and bug fixes.
//    14-mar-95   reedb      Use GDI hooks to move most functionality to UI.
//    16-aug-95   reedb      Move to kernel mode. Debug output and validate
//                              functions moved from FAXCOMM.C.
//
//************************************************************************

#include "wowfaxdd.h"

//************************************************************************
// Globals
//************************************************************************

DRVFN  DrvFnTab[] = {
                      {INDEX_DrvEnablePDEV,      (PFN)DrvEnablePDEV  },
                      {INDEX_DrvDisablePDEV,     (PFN)DrvDisablePDEV  },
                      {INDEX_DrvCompletePDEV,    (PFN)DrvCompletePDEV  },
                      {INDEX_DrvEnableSurface,   (PFN)DrvEnableSurface  },
                      {INDEX_DrvDisableSurface,  (PFN)DrvDisableSurface  },
                      {INDEX_DrvStartDoc,        (PFN)DrvStartDoc  },
                      {INDEX_DrvStartPage,       (PFN)DrvStartPage  },
                      {INDEX_DrvSendPage,        (PFN)DrvSendPage  },
                      {INDEX_DrvEndDoc,          (PFN)DrvEndDoc  },
                      {INDEX_DrvDitherColor,     (PFN)DrvDitherColor },
                      {INDEX_DrvEscape,          (PFN)DrvEscape},
                   };

#define NO_DRVFN        (sizeof(DrvFnTab) / sizeof(DrvFnTab[0]))


#if DBG

//************************************************************************
// faxlogprintf - Driver version of the debug output function.
//
//************************************************************************

VOID faxlogprintf(PCHAR pszFmt, ...)
{
    va_list ap;
    char buffer[256];

    va_start(ap, pszFmt);

    EngDebugPrint("", pszFmt, ap);

    va_end(ap);
}

#endif

//************************************************************************
// ValidateFaxDev - Validates the FAXDEV structure by checking the DWORD
//      signature, which is a known fixed value.
//
//************************************************************************

BOOL ValidateFaxDev(LPFAXDEV lpFaxDev)
{
    if (lpFaxDev) {
        if (lpFaxDev->id == FAXDEV_ID) {
            return TRUE;
        }
        LOGDEBUG(("ValidateFaxDev failed, bad id, lpFaxDev: %X\n", lpFaxDev));
    }
    else {
        LOGDEBUG(("ValidateFaxDev failed, lpFaxDev: NULL\n"));
    }
    return FALSE;
}

//************************************************************************
// DllInitProc
//************************************************************************

BOOL DllInitProc(HMODULE hModule, DWORD Reason, PCONTEXT pContext)
{
    UNREFERENCED_PARAMETER(hModule);
    UNREFERENCED_PARAMETER(Reason);
    UNREFERENCED_PARAMETER(pContext);

    return TRUE;
}


//***************************************************************************
// DrvEnableDriver
//***************************************************************************

BOOL DrvEnableDriver(ULONG iEngineVersion, ULONG cb, DRVENABLEDATA  *pded)
{
    LOGDEBUG(("WOWFAX!DrvEnableDriver, iEngineVersion: %X, cb: %X, pded: %X\n", iEngineVersion, cb, pded));

    pded->iDriverVersion = DDI_DRIVER_VERSION;

    if (cb < sizeof(DRVENABLEDATA)) {
        LOGDEBUG(("WOWFAX!DrvEnableDriver, failed\n"));
        return FALSE;
    }

    pded->c = NO_DRVFN;
    pded->pdrvfn = DrvFnTab;

    return  TRUE;

}

//***************************************************************************
// DrvDisableDriver
//***************************************************************************

VOID DrvDisableDriver(VOID)
{
    LOGDEBUG(("WOWFAX!DrvDisableDriver\n"));
    return;
}

//***************************************************************************
// DrvEnablePDEV
//***************************************************************************
DHPDEV DrvEnablePDEV(DEVMODEW *pdevmode,        // Driver data, Client FAXDEV
                     PWSTR     pwstrPrtName,    // Printer's name in CreateDC()
                     ULONG     cPatterns,       // Count of standard patterns
                     HSURF    *phsurfPatterns,  // Buffer for standard patterns
                     ULONG     cjGdiInfo,       // Size of buffer for GdiInfo
                     ULONG    *pulGdiInfo,      // Buffer for GDIINFO
                     ULONG     cjDevInfo,       // Number of bytes in devinfo
                     DEVINFO  *pdevinfo,        // Device info
                     HDEV      hdev,
                     PWSTR     pwstrDeviceName, // Device Name - "LaserJet II"
                     HANDLE    hDriver          // Printer handle for spooler access
)
{
    LPFAXDEV   lpCliFaxDev, lpSrvFaxDev = NULL;

    LOGDEBUG(("WOWFAX!DrvEnablePDEV, pdevmode: %X, pwstrPrtName: %S\n", pdevmode, pwstrPrtName));

    if (pdevmode) {
        // Point to the end of the DEVMODE where the FAXDEV is located.
        lpCliFaxDev = (LPFAXDEV) ((PBYTE)pdevmode + pdevmode->dmSize);

        // Allocate a server side FAXDEV to be passed back to GDI. Copy the
        // client side FAXDEV to the server side FAXDEV. Note all pointers in
        // the client FAXDEV reference client side memory and cannot be
        // dereferenced on the server side.
        lpSrvFaxDev = (LPFAXDEV)EngAllocMem(0, sizeof(FAXDEV), FAXDEV_ID);
        LOGDEBUG(("WOWFAX!DrvEnablePDEV, allocated lpSrvFaxDev: %X\n", lpSrvFaxDev));

        if (InitPDEV(lpCliFaxDev, lpSrvFaxDev,
                     cPatterns, phsurfPatterns,
                     cjGdiInfo, pulGdiInfo,
                     cjDevInfo, pdevinfo)) {

            lpSrvFaxDev->hDriver = hDriver;
            return (DHPDEV)lpSrvFaxDev;
        }
        else {
            LOGDEBUG(("WOWFAX!DrvEnablePDEV, failed\n"));
            if (lpSrvFaxDev) {
                EngFreeMem(lpSrvFaxDev);
                lpSrvFaxDev = NULL;
            }
        }
    }
    return (DHPDEV)lpSrvFaxDev;
}

//***************************************************************************
// InitPDEV - Called by DrvEnablePDEV and DrvRestartPDEV to initialize the
//      server side PDEV/FAXDEV.
//***************************************************************************


BOOL InitPDEV(
    LPFAXDEV  lpCliFaxDev,           // Pointer to the client side FAXDEV
    LPFAXDEV  lpSrvFaxDev,           // Pointer to the server side FAXDEV
    ULONG     cPatterns,            // Count of standard patterns
    HSURF    *phsurfPatterns,       // Buffer for standard patterns
    ULONG     cjGdiInfo,            // Size of buffer for GdiInfo
    ULONG    *pulGdiInfo,           // Buffer for GDIINFO
    ULONG     cjDevInfo,            // Number of bytes in devinfo
    DEVINFO  *pdevinfo              // Device info
)
{
    PGDIINFO pgdiinfo = (PGDIINFO)pulGdiInfo;
    ULONG    uColors[2];

    if (!ValidateFaxDev(lpCliFaxDev)) {
        return FALSE;
    }

    // lpSrvFaxDev hasn't been initialized yet, so just check pointer.
    if (lpSrvFaxDev == NULL) {
        LOGDEBUG(("WOWFAX!InitPDEV, failed, NULL lpSrvFaxDev parameter\n"));
        return FALSE;
    }

    // Copy client FAXDEV to server.
    RtlCopyMemory(lpSrvFaxDev, lpCliFaxDev, sizeof(FAXDEV));

    // Copy GDIINFO from client FAXDEV to the GDI buffer for GDIINFO.
    RtlCopyMemory(pgdiinfo, &(lpCliFaxDev->gdiinfo), sizeof(GDIINFO));

    // Initialize the DEVINFO structure.
    uColors[0] = RGB(0x00, 0x00, 0x00);
    uColors[1] = RGB(0xff, 0xff, 0xff);

    pdevinfo->hpalDefault = EngCreatePalette(PAL_INDEXED, 2, uColors, 0, 0, 0);
    pdevinfo->iDitherFormat = BMF_1BPP;

    // Make sure we don't journal.
    pdevinfo->flGraphicsCaps |= GCAPS_DONTJOURNAL;

    // Make sure we do dither.
    pdevinfo->flGraphicsCaps |= GCAPS_HALFTONE | GCAPS_MONO_DITHER |
                                    GCAPS_COLOR_DITHER;

    // Copy the DEVINFO data to the server side FAXDEV.
    RtlCopyMemory(&(lpSrvFaxDev->devinfo), pdevinfo, sizeof(DEVINFO));

    return TRUE;
}

//***************************************************************************
// DrvCompletePDEV
//***************************************************************************

VOID DrvCompletePDEV(DHPDEV dhpdev, HDEV hdev)
{
    LPFAXDEV lpSrvFaxDev = (LPFAXDEV) dhpdev;

    LOGDEBUG(("WOWFAX!DrvCompletePDEV, dhpdev %X\n", dhpdev));

    if (ValidateFaxDev(lpSrvFaxDev)) {
        // Store the gdi handle.
        lpSrvFaxDev->hdev = hdev;
    }
    else {
         LOGDEBUG(("WOWFAX!DrvCompletePDEV, failed\n"));
    }

    return;
}

//***************************************************************************
// DrvDisablePDEV
//***************************************************************************

VOID DrvDisablePDEV(DHPDEV  dhpdev)
{
    LPFAXDEV lpSrvFaxDev = (LPFAXDEV) dhpdev;

    LOGDEBUG(("WOWFAX!DrvDisablePDEV, dhpdev %X\n", dhpdev));

    if (ValidateFaxDev(lpSrvFaxDev)) {
        if (lpSrvFaxDev->devinfo.hpalDefault) {
            EngDeletePalette(lpSrvFaxDev->devinfo.hpalDefault);
        }
        EngFreeMem(lpSrvFaxDev);
        LOGDEBUG(("WOWFAX!DrvDisablePDEV, deallocated lpSrvFaxDev: %X\n", lpSrvFaxDev));
    }
    else {
        LOGDEBUG(("WOWFAX!DrvDisablePDEV, failed\n"));
    }
    return;
}


//***************************************************************************
// DrvEnableSurface
//***************************************************************************

HSURF DrvEnableSurface(DHPDEV  dhpdev)
{

    LPFAXDEV  lpFaxDev = (LPFAXDEV)dhpdev;
    HBITMAP   hbm = 0;

    LOGDEBUG(("WOWFAX!DrvEnableSurface, lpFaxDev: %X\n", lpFaxDev));

    if (ValidateFaxDev(lpFaxDev)) {
        // GDI will allocate space for the bitmap bits. We'll use a DrvEscape
        // to copy them to the client side.
        hbm = EngCreateBitmap(lpFaxDev->gdiinfo.szlPhysSize,
                              lpFaxDev->bmWidthBytes,
                              lpFaxDev->bmFormat, BMF_TOPDOWN, NULL);
        if (hbm) {
            lpFaxDev->hbm = hbm;
            EngAssociateSurface((HSURF)hbm, lpFaxDev->hdev, 0);
            return  (HSURF)hbm;
        }
        LOGDEBUG(("WOWFAX!DrvEnableSurface, EngCreateBitmap failed\n"));
    }

    return  (HSURF)hbm;
}

//***************************************************************************
// DrvDisableSurface
//***************************************************************************

VOID DrvDisableSurface(
    DHPDEV dhpdev
)
{
    LPFAXDEV  lpFaxDev = (LPFAXDEV)dhpdev;

    LOGDEBUG(("WOWFAX!DrvDisableSurface, lpFaxDev: %X\n", lpFaxDev));

    if (ValidateFaxDev(lpFaxDev)) {
        if (lpFaxDev->hbm) {
            EngDeleteSurface((HSURF)lpFaxDev->hbm);
            lpFaxDev->hbm = 0;
            return;
        }
    }
    return;
}

//***************************************************************************
// DrvStartDoc
//***************************************************************************

BOOL DrvStartDoc(
    SURFOBJ *pso,
    PWSTR pwszDocName,
    DWORD dwJobId
)
{
    LOGDEBUG(("WOWFAX!DrvStartDoc, pso: %X, pwszDocName: %S, dwJobId: %X\n", pso, pwszDocName, dwJobId));
    return  TRUE;
}

//***************************************************************************
// DrvStartPage
//***************************************************************************

BOOL DrvStartPage(
    SURFOBJ *pso
)
{
    LPFAXDEV  lpFaxDev = (LPFAXDEV)pso->dhpdev;
    BITMAP bm;
    RECTL rc;

    LOGDEBUG(("WOWFAX!DrvStartPage, pso: %X\n", pso));

    // Calculate the size of the rectangle based on the input data
    // in 'pso' - this will  ensure that the entire bitmap is erased.

    if (ValidateFaxDev(lpFaxDev)) {
        rc.left   = 0;
        rc.top    = 0;
        rc.right  = pso->lDelta * lpFaxDev->cPixPerByte;
        rc.bottom = pso->cjBits / pso->lDelta;

        EngEraseSurface(pso, &rc, COLOR_INDEX_WHITE);
        return  TRUE;
    }
    return  FALSE;
}       


//***************************************************************************
// DrvSendPage
//***************************************************************************

BOOL DrvSendPage(SURFOBJ *pso)
{
    LOGDEBUG(("WOWFAX!DrvSendPage, pso %X\n", pso));
    return  TRUE;
}


//***************************************************************************
// DrvEndDoc
//***************************************************************************

BOOL DrvEndDoc(SURFOBJ *pso, FLONG fl)
{
    LOGDEBUG(("WOWFAX!DrvEndDoc, pso %X\n", pso));
    return  TRUE;
}

ULONG
DrvDitherColor(
    DHPDEV  dhpdev,
    ULONG   iMode,
    ULONG   rgbColor,
    ULONG  *pulDither
    )

{
    return DCR_HALFTONE;
}

//***************************************************************************
// DrvEscape - Allows client side to get server side data.
//***************************************************************************

ULONG DrvEscape(
    SURFOBJ *pso,
    ULONG   iEsc,
    ULONG   cjIn,
    PVOID   *pvIn,
    ULONG   cjOut,
    PVOID   *pvOut
)
{
    LPFAXDEV lpSrvFaxDev;
    ULONG    ulRet = 0;

    LOGDEBUG(("WOWFAX!DrvEscape, pso %X, iEsc: %X\n", pso, iEsc));
    if (pso) {
        lpSrvFaxDev = (LPFAXDEV)pso->dhpdev;
        if (ValidateFaxDev(lpSrvFaxDev)) {
            LOGDEBUG(("WOWFAX!DrvEscape, lpSrvFaxDev: %X\n", lpSrvFaxDev));
            switch (iEsc) {
                case DRV_ESC_GET_DEVMODE_PTR:
                    return (ULONG) lpSrvFaxDev->pdevmode;

                case DRV_ESC_GET_FAXDEV_PTR:
                    return (ULONG) lpSrvFaxDev->lpClient;

                case DRV_ESC_GET_SURF_INFO:
                    if (pvOut) {
                        if (cjOut == sizeof(LONG)) {
                            (LONG) *pvOut = pso->lDelta;
                            return (ULONG) pso->cjBits;
                        }
                    }
                    break;

                case DRV_ESC_GET_BITMAP_BITS:
                    // Validate the buffer pointer and copy the bits.
                    if (pvOut) {
                        if (cjOut == pso->cjBits) {
                            RtlCopyMemory(pvOut, pso->pvBits, cjOut);
                            return cjOut;
                        }
                        LOGDEBUG(("WOWFAX!DrvEscape, bitmap size mismatch cjIn: %X, pso->cjBits: %X\n", cjIn, pso->cjBits));
                    }
                    break;

//                default:
                    LOGDEBUG(("WOWFAX!DrvEscape, unknown escape: %X\n", iEsc));
            } //switch
        }
    }
    LOGDEBUG(("WOWFAX!DrvEscape, failed\n"));

    return ulRet;
}


