// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and Microsoft
// WinHelp documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.


#include "stdafx.h"
#include "padview.h"
#include "paddoc.h"
#include "paditem.h"
#include <limits.h>

IMPLEMENT_DYNAMIC(CEmbeddedItem, COleServerItem)

CEmbeddedItem::CEmbeddedItem(CPadDoc* pContainerDoc)
	: COleServerItem(pContainerDoc, TRUE)
{
	m_nBeg = 0;
	m_nEnd = UINT_MAX;

	// support CF_TEXT format
	GetDataSource()->DelayRenderFileData(CF_TEXT);
}

BOOL CEmbeddedItem::OnRenderFileData(LPFORMATETC lpFormatEtc, CFile* pFile)
{
	ASSERT(lpFormatEtc != NULL);
	if (lpFormatEtc->cfFormat != CF_TEXT)
		return COleServerItem::OnRenderFileData(lpFormatEtc, pFile);

	BOOL bResult = FALSE;
	TRY
	{
		// save contents of this item to the file
		SaveToFile(pFile);

		// CF_TEXT has NUL termination
		char chZero = '\0';
		pFile->Write(&chZero, sizeof(char));

		bResult = TRUE; // success
	}
	END_TRY

	return bResult;
}

CPadView* CEmbeddedItem::GetView() const
{
	CDocument* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	POSITION pos = pDoc->GetFirstViewPosition();
	ASSERT(pos != NULL);
	CPadView* pView = (CPadView*)pDoc->GetNextView(pos);
	ASSERT_VALID(pView);
	ASSERT(pView->IsKindOf(RUNTIME_CLASS(CPadView)));
	return pView;
}

void CEmbeddedItem::SaveToFile(CFile* pFile)
{
	CPadView* pView = GetView();
	LPCSTR lpszText = NULL;

	TRY
	{
		// get access to the edit buffer
		lpszText = pView->LockBuffer();

		// get range (make sure inside of text length)
		UINT nEnd = pView->GetWindowTextLength();
		UINT nBeg = min(m_nBeg, nEnd);
		nEnd = min(m_nEnd, nEnd);

		// write it out to the file
		pFile->Write(lpszText+nBeg, (nEnd-nBeg) * sizeof(char));
	}
	END_TRY

	// release access to edit buffer
	if (lpszText != NULL)
		pView->UnlockBuffer();
}

void CEmbeddedItem::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// save just the portion this item refers to
		ar.Flush();
		CFile* pFile = ar.GetFile();
		SaveToFile(pFile);
	}
	else
	{
		// otherwise, read in the entire file
		GetDocument()->Serialize(ar);
	}
}

BOOL CEmbeddedItem::OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize)
{
	if (dwDrawAspect != DVASPECT_CONTENT)
		return COleServerItem::OnGetExtent(dwDrawAspect, rSize);

	// no drawing will happen if cliprect is NULL
	CClientDC dc(NULL);
	dc.IntersectClipRect(0, 0, 0, 0);
	return OnDraw(&dc, rSize);
}

BOOL CEmbeddedItem::OnDraw(CDC* pDC, CSize& rSize)
{
	// get view attached to the item
	CPadView* pView = GetView();

	// edit controls have a border around them
	CRect rectEdit;
	pView->GetEditCtrl().GetRect(&rectEdit);
	rectEdit.InflateRect(1, 1);
	CRect rectClient;
	pView->GetClientRect(&rectClient);
	CRect margin(rectEdit.top - rectClient.top, rectEdit.left - rectClient.left,
		rectClient.right - rectEdit.right, rectEdit.top - rectClient.top);
	++margin.top;

	// get the font from the CEditView
	CFont* pFont = pView->GetFont();
	CFont* pOldFont = NULL;
	if (pFont != NULL)
		pOldFont = pDC->SelectObject(pFont);
	TEXTMETRIC tm;
	pDC->GetTextMetrics(&tm);

	// get formatting rectangle
	CSize sizeT = m_sizeExtent;
	pDC->HIMETRICtoDP(&sizeT);
	CRect rect(0, 0, sizeT.cx, sizeT.cy);
	if (rect.IsRectEmpty())
		rect.right = rectEdit.Width() + margin.right + margin.left;
	// adjust for borders
	rect.left += margin.left;
	rect.top += margin.top;
	rect.right -= margin.right;
	rect.bottom = INT_MAX;  // bottomless for layout

	// first just determine the correct extents of the text
	pDC->SetBkMode(TRANSPARENT);
	pDC->SaveDC();
	pDC->IntersectClipRect(0, 0, 0, 0); // no drawing with NULL clipping
	if (pView->PrintInsideRect(pDC, rect, m_nBeg, m_nEnd) == 0)
		rect.bottom = rect.top + tm.tmHeight;
	pDC->RestoreDC(-1);

	// then, really output the text
	pDC->SetWindowOrg(0, 0);
	pDC->SetWindowExt(rect.Width() + margin.right + margin.left,
		rect.Height() + margin.top + margin.bottom);
	pView->PrintInsideRect(pDC, rect, m_nBeg, m_nEnd);

	// adjust for border (rect.left is already adjusted)
	rect.left -= margin.left;
	rect.top -= margin.top;
	rect.right += margin.right;
	rect.bottom += margin.bottom;
	if (pView->GetStyle() & WS_HSCROLL)
		++rect.bottom;  // account for border on scroll bar!

	// select previous font
	if (pOldFont != NULL)
		pDC->SelectObject(pOldFont);

	// return HIMETRIC size
	rSize = rect.Size();
	pDC->DPtoHIMETRIC(&rSize);
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
