// SAPrint.cpp - StandAlone Print - uses MFC

#include "stdafx.h"
#include "SAPrint.h"

#ifdef _DEBUG

#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;

#endif

SAPrint::SAPrint(const CString& sDocName, const CString& sFaceName, const UINT nLinesTot, const UINT nMaxLineSize)
{

CPrintDialog *pDlg = NULL;
TEXTMETRIC *pTM = NULL;
DOCINFO *pDI = NULL;
CFont *pOldFont = NULL;
LPCTSTR lpszFacename = NULL;
BOOL bRet;
CSize size;
UINT len;

m_bConstructed = FALSE;
m_bDelDoc = FALSE;
m_bPageStarted = FALSE;
m_bDocStarted = FALSE;

m_pDC = NULL;
m_pFont = NULL;

m_iPrintJobNo = 0;
m_nLinesPerPage = 0;
m_nMaxPageNo = 0;

m_nVMax = 0;
m_nHMax = 0;
m_nLinesTotal = 0;
m_nMaxLineSize = 0;
m_nPageNo = 0;
m_nLineNo = 0;
m_sDocName = sDocName;
m_sFaceName = "";

pDlg=new CPrintDialog(FALSE);
if (!pDlg) return;

if (!pDlg->DoModal()) goto Cleanup;

m_pDC = new CDC;
if (!m_pDC) goto Cleanup;

if (! m_pDC->Attach(pDlg->GetPrinterDC()) )
goto Cleanup;

delete pDlg;
pDlg = 0;

m_pFont = new CFont;
if (!m_pFont) goto Cleanup;

pTM = new TEXTMETRIC;
if (!pTM) goto Cleanup;

pDI = new DOCINFO;
if (!pDI) goto Cleanup;

::ZeroMemory(pDI, sizeof(DOCINFO));
if (sDocName != "")
    m_sDocName = sDocName;
UINT len = m_sDocName.GetLength();
pDI->lpszDocName=m_sDocName.GetBuffer(len+1);

LPCTSTR lpszFacename = NULL;
if (sFaceName != "")
{
    m_sFaceName = sFaceName;
    lpszFacename = m_sFaceName;
}

if (nLinesTot) m_nLinesTotal = nLinesTot;

if (nMaxLineSize)m_nMaxLineSize=nMaxLineSize;

// get basic printer info
m_iHeight=-((m_pDC->GetDeviceCaps(LOGPIXELSY) * 10) / PIXELS_PER_INCH );
if (! m_pFont->CreateFont ( m_iHeight, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH || FF_DONTCARE, lpszFacename ))
    goto Cleanup;

// this code checks to see what font was
// really used. Unfortunately, since
// FF_DONTCARE was specified, a name that
// does not quite match causes its name to be
// returned, but does not affect the font
// that is actually used, which is often the
// default font. If no name is given or
// NULL is passed into CreateFont, a null
// string will be returned by GetLogFont()
// function.

LOGFONT lf;
pOldFont = m_pDC->SelectObject(m_pFont);
if (m_pFont->GetLogFont(&lf))
    m_sFaceName = lf.lfFaceName;

m_pDC->GetTextMetrics (pTM);
m_cy = pTM->tmHeight +
pTM->tmExternalLeading;
delete pTM;
pTM = 0;

m_nVMax = m_pDC->GetDeviceCaps(VERTRES);
m_nHMax = m_pDC->GetDeviceCaps(HORZRES);
m_nLinesPerPage = (m_nVMax) / m_cy;
m_nMaxPageNo=(nLinesTot+(m_nLinesPerPage-1)) / m_nLinesPerPage;

// use "W", one of the widest letters
size = m_pDC->GetTextExtent("W", m_nMaxLineSize);
m_cxWidth = size.cx;
m_cxOffset = (m_cxWidth > m_nHMax ? 0 : m_nHMax - m_cxWidth) / 2;

m_iPrintJobNo = m_pDC->StartDoc(pDI);
if (m_iPrintJobNo > 0)
    m_bDocStarted = TRUE;
else
{
    CString s = "Unable to print ";
    s += m_sDocName;
    AfxMessageBox(s, MB_OK);
    goto Cleanup;
}
delete pDI;
pDI = 0;

m_pDC->SelectObject (pOldFont);
m_bConstructed = TRUE;

return;

Cleanup:

delete pDI;
delete pTM;
delete pDlg;
CleanUp(FALSE);

}

SAPrint::~SAPrint()
{
    CleanUp(TRUE);
}

void SAPrint::CleanUp(BOOL bEndDoc)
{

if (m_bDocStarted && m_bPageStarted)
    m_pDC->EndPage();
if (m_bDocStarted && !m_bDelDoc && bEndDoc)
    m_pDC->EndDoc();
else
    m_pDC->AbortDoc();

if (m_pDC)
    m_pDC->Detach();
if (m_pFont)
    m_pFont->DeleteObject();
delete m_pDC;
delete m_pFont;

}

inline void SAPrint::DeleteDoc(void)
{ m_bDelDoc = TRUE; }

inline UINT SAPrint::GetLinesPerPg(void) const
{ return m_nLinesPerPage; }

inline UINT SAPrint::GetPageNo(void) const
{ return m_nPageNo; }

inline UINT SAPrint::GetMaxPageNo(void) const
{ return m_nMaxPageNo; }

inline UINT SAPrint::GetLineNo(void) const
{ return m_nLineNo; }

UINT SAPrint::GetLineNoNext(void) const
{ return (m_nLineNo % m_nLinesPerPage)+1; }

UINT SAPrint::GetPageNoNext(void) const
{
    if ((m_nLineNo % m_nLinesPerPage) == 0)
        return m_nPageNo + 1;
    return m_nPageNo;
}

UINT SAPrint::SetMaxPageNo(const UINT nMaxPageNo)
{
    UINT nOldMaxPageNo = m_nMaxPageNo;
    if (nMaxPageNo >= 0)
        m_nMaxPageNo = nMaxPageNo;
    return nOldMaxPageNo;
}

BOOL SAPrint::StartPage(void)
{
    if (!m_bConstructed) return FALSE;

    m_bPageStarted = FALSE;
    if (m_pDC->StartPage() > 0)
    {
        ++m_nPageNo;
        m_nLineNo = 0;
        m_bPageStarted = TRUE;
    }
    return m_bPageStarted;
}

BOOL SAPrint::PrintLine(const CString& sLine)
{
    BOOL bCont = FALSE;

    if (!m_bConstructed) return bCont;

    CString s;
    if (m_nLineNo == 0)
        if (!StartPage())
            return bCont;

CFont* pOldFont;
pOldFont = m_pDC->SelectObject (m_pFont);

UINT y = m_nLineNo * m_cy;
bCont = m_pDC->TextOut(m_cxOffset,y,sLine);
if (bCont)
    if (++m_nLineNo == m_nLinesPerPage)
    {
        bCont = EndPage();
        m_nLineNo = 0;
    }

m_pDC->SelectObject (pOldFont);
return bCont;

}

BOOL SAPrint::EndPage(void)
{
    if (!m_bConstructed) return FALSE;

BOOL bCont = FALSE;
if (m_bPageStarted)
{
    bCont = (m_pDC->EndPage() >= 0);
    if (bCont)
        m_bPageStarted = FALSE;
}

return bCont;

}

CString SAPrint::GetFaceName() const
{
    if (!m_bConstructed) return CString();

    CFont* pOldFont;
    pOldFont = m_pDC->SelectObject (m_pFont);

    LOGFONT lf;
    if (m_pFont->GetLogFont(&lf))
        CString sFaceName = lf.lfFaceName;
    m_pDC->SelectObject (pOldFont);

    return m_sFaceName;
}

BOOL SAPrint::SetFaceName(const CString& sFace)
{

if (!m_bConstructed) return FALSE;

LPCTSTR lpszFaceName = NULL;
if (sFace != "")
{
    m_sFaceName = sFace;
    lpszFaceName = m_sFaceName;
}

if (m_pFont)
    m_pFont->DeleteObject();

BOOL bRet = m_pFont->CreateFont( m_iHeight, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH || FF_DONTCARE, lpszFaceName );

if (!bRet) return bRet;

CFont* pOldFont = m_pDC->SelectObject (m_pFont);

LOGFONT lf;

if (m_pFont->GetLogFont(&lf))
    m_sFaceName = lf.lfFaceName;

m_pDC->SelectObject (pOldFont);

return bRet;

}

#ifdef _DEBUG

BOOL SAPrint::Test(const CString& sTestName, const UINT nLinesTotal)
{
    BOOL bCont = TRUE;
    CString sFmt = "%s Page %d line %d of %d/page of %d total in %s";
    UINT nMaxPage = max(1, (nLinesTotal + (GetLinesPerPg() - 1)) / GetLinesPerPg());
    SetMaxPageNo(nMaxPage);

    UINT n = 0;
    CString s;
    CString sFaceName = GetFaceName();

    if (sFaceName == "")
        sFaceName = "<Default Font>";

    for (UINT i=0; (i < nMaxPage) && bCont; ++i)
    {
        for (UINT j=0; bCont&&(j < m_nLinesPerPage); ++j)
        {
            s.Format(sFmt,sTestName, GetPageNoNext(), GetLineNoNext(), GetLinesPerPg(), nLinesTotal, sFaceName);
            bCont &= PrintLine(s);
            bCont &= (++n < nLinesTotal);
        }
    }
    return TRUE;

}

#endif