// ActiveCtl.h : Declaration of the CActiveDoc class

#include "resource.h"       // main symbols
#include "OleDocument.h"
#include "Menu.h"
#include "ToolBar.h"
#include <RichEdit.h>

/////////////////////////////////////////////////////////////////////////////
// CActiveDoc
class CActiveDoc : 
	public CComObjectRoot,
	public CComCoClass<CActiveDoc, &CLSID_CActiveDoc>,
	public CComControl<CActiveDoc>,
	public IDispatchImpl<IActiveDoc, &IID_IActiveDoc, &LIBID_ACTIVEDOCLib>,
	public IProvideClassInfo2Impl<&CLSID_CActiveDoc, NULL, &LIBID_ACTIVEDOCLib>,
	public IPersistStreamInitImpl<CActiveDoc>,
	public IPersistStorageImpl<CActiveDoc>,
	public IQuickActivateImpl<CActiveDoc>,
	public IOleControlImpl<CActiveDoc>,
	public IOleObjectImpl<CActiveDoc>,
	public IOleInPlaceActiveObjectImpl<CActiveDoc>,
	public IViewObjectExImpl<CActiveDoc>,
	public IOleInPlaceObjectWindowlessImpl<CActiveDoc>,
	public IDataObjectImpl<CActiveDoc>,
	public ISupportErrorInfo,
	public IOleDocumentImpl<CActiveDoc>,
	public IOleDocumentViewImpl<CActiveDoc>,
	public CMenu<CActiveDoc>,
	public CToolbar<CActiveDoc>
{
public:
	CActiveDoc() : m_wndRTF(_T("RichEdit"), this, 1)
	{
		m_wndRTF.m_hWnd = NULL;
		m_bWindowOnly = TRUE;
	}

DECLARE_REGISTRY_RESOURCEID(IDR_ActiveDoc)

BEGIN_COM_MAP(CActiveDoc)
	COM_INTERFACE_ENTRY(IActiveDoc)
	COM_INTERFACE_ENTRY(IDispatch)
	COM_INTERFACE_ENTRY_IMPL(IViewObjectEx)
	COM_INTERFACE_ENTRY_IMPL_IID(IID_IViewObject2, IViewObjectEx)
	COM_INTERFACE_ENTRY_IMPL_IID(IID_IViewObject, IViewObjectEx)
	COM_INTERFACE_ENTRY_IMPL(IOleInPlaceObjectWindowless)
	COM_INTERFACE_ENTRY_IMPL_IID(IID_IOleInPlaceObject, IOleInPlaceObjectWindowless)
	COM_INTERFACE_ENTRY_IMPL_IID(IID_IOleWindow, IOleInPlaceObjectWindowless)
	COM_INTERFACE_ENTRY_IMPL(IOleInPlaceActiveObject)
	COM_INTERFACE_ENTRY_IMPL(IOleControl)
	COM_INTERFACE_ENTRY_IMPL(IOleObject)
	COM_INTERFACE_ENTRY_IMPL(IQuickActivate)
	COM_INTERFACE_ENTRY_IMPL(IPersistStorage)
	COM_INTERFACE_ENTRY_IMPL(IPersistStreamInit)
	COM_INTERFACE_ENTRY_IMPL(IDataObject)
	COM_INTERFACE_ENTRY_IMPL(IOleDocument)
	COM_INTERFACE_ENTRY_IMPL(IOleDocumentView)
	COM_INTERFACE_ENTRY(IProvideClassInfo)
	COM_INTERFACE_ENTRY(IProvideClassInfo2)
	COM_INTERFACE_ENTRY(ISupportErrorInfo)
END_COM_MAP()

BEGIN_PROPERTY_MAP(CActiveDoc)
	// PROP_ENTRY("Description", dispid, clsid)
END_PROPERTY_MAP()

BEGIN_MSG_MAP(CActiveDoc)
	MESSAGE_HANDLER(WM_PAINT, OnPaint)
	MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
	MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
	MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
	MESSAGE_HANDLER(WM_CREATE, OnCreate)
	MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
	MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackgnd)
	COMMAND_RANGE_HANDLER(ID_BLACK, ID_BLUE, OnColorChange)
	COMMAND_ID_HANDLER(ID_HELP_ABOUT, OnHelpAbout)
	NOTIFY_CODE_HANDLER(TTN_NEEDTEXT, OnToolbarNeedText)

	ALT_MSG_MAP(1)
//	MESSAGE_HANDLER(WM_CHAR, OnChar)
//	END_MSG_MAP()
END_MSG_MAP()

BEGIN_TOOLBAR_MAP(CActiveDoc)
	TOOLBAR_BUTTON(ID_BLACK)
	TOOLBAR_BUTTON(ID_RED)
	TOOLBAR_BUTTON(ID_GREEN)
	TOOLBAR_BUTTON(ID_BLUE)
	TOOLBAR_SEPARATOR()
	TOOLBAR_BUTTON(ID_HELP_ABOUT)
END_TOOLBAR_MAP()
	
// ISupportsErrorInfo
	STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

// IActiveDoc
public:

// Implementation
	// Override IOleInPlaceActiveObjectImpl::OnDocWindowActivate
	STDMETHOD(OnDocWindowActivate)(BOOL fActivate)
	{
		ATLTRACE(_T("ActiveDoc::OnDocWindowActivate\n"));
		if (fActivate)
		{
			CreateToolbar(m_hWnd);
			InPlaceMenuCreate();
		}
		else
		{
			DestroyToolbar();
			InPlaceMenuDestroy();
		}
		return S_OK;
	}
	// Override IPersistStorageImpl::IsDirty
	STDMETHOD(IsDirty)()
	{
		ATLTRACE(_T("CActiveDoc::IsDirty\n"));
		if (m_wndRTF.m_hWnd != NULL)
		{
			return (m_wndRTF.SendMessage(EM_GETMODIFY, 0, 0)) ? S_OK : S_FALSE;
		}
		else
			return S_FALSE;
	}
	// Override IPersistStreamInitImp::Save
	STDMETHOD(Save)(LPSTREAM pStm, BOOL fClearDirty)
	{
		ATLTRACE(_T("CActiveDoc::Save\n"));
		// We can only save if we have an RTF control to save data from
		if (m_wndRTF.m_hWnd != NULL)
		{
			EDITSTREAM	es;
			es.dwCookie		= (DWORD)pStm;
			es.dwError		= 0;
			es.pfnCallback  = RTFSave;
			m_wndRTF.SendMessage(EM_STREAMOUT, SF_RTF, (LPARAM)&es);
			if (fClearDirty)
				SetRTFModified(FALSE); // We're no longer dirty
		}
		return S_OK;
	}
	// Override IPersistStreamInitImp::Load
	STDMETHOD(Load)(LPSTREAM pStm)
	{
		ATLTRACE(_T("CActiveDoc::Load\n"));
		// Ensure the RTF window has been created, so that we can load data into it.
		if (m_wndRTF.m_hWnd == NULL)
			CreateRTFWindow();

		EDITSTREAM	es;
		es.dwCookie		= (DWORD)pStm;
		es.dwError		= 0;
		es.pfnCallback  = RTFLoad;
		m_wndRTF.SendMessage(EM_STREAMIN, SF_RTF, (LPARAM)&es);
		SetRTFModified(FALSE); // We're not dirty
		return S_OK;
	}
	static DWORD CALLBACK RTFSave(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb)
	{
		HRESULT  hr;
		LPSTREAM pStm = (LPSTREAM)dwCookie;

		hr = pStm->Write(pbBuff, cb, (ULONG*)pcb);
		if (SUCCEEDED(hr))
			return 0;
		else
			return 1; // Failed so stop calling us.
	}
	static DWORD CALLBACK RTFLoad(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb)
	{
		HRESULT  hr;
		LPSTREAM pStm = (LPSTREAM)dwCookie;

		hr = pStm->Read(pbBuff, cb, (ULONG*)pcb);
		if (SUCCEEDED(hr))
			return 0;
		else
			return 1; // Failed so stop calling us.
	}

	HRESULT OnDraw(ATL_DRAWINFO& /* di */)
	{
		// Drawing handled by RTF control
		return 0;
	}
	LRESULT OnEraseBackgnd(UINT, WPARAM, LPARAM, BOOL&)
	{
		return 0;
	}
	LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&)
	{
		CreateToolbar(m_hWnd); // m_wndRTF.m_hWnd);

		// If we haven't created the RTF window then we need to create it. If not, is has already
		// been created by the Load procedure so we just make sure it is a parent of our window.
		if (m_wndRTF.m_hWnd == NULL)
			CreateRTFWindow();
		else
		{
			m_wndRTF.SetParent(m_hWnd);
			m_wndRTF.ModifyStyle(0, WS_CHILD | WS_VISIBLE);
		}
		return 0;
	}
	LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL&)
	{
		// Destroy the toolbar and the RTF window
		DestroyToolbar();
		m_wndRTF.DestroyWindow();
		FreeLibrary(m_hLibRTF);
		return 0;
	}
	LRESULT OnSetFocus(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		// When the control window get's the focus, set the focus to the
		// RTF control.
		CComControlBase::OnSetFocus(nMsg, wParam, lParam, bHandled);
		m_wndRTF.SetFocus();
		return 0;
	}
	void CreateRTFWindow()
	{
		DWORD dwStyle;
		RECT  rc;
		// If the control window has been created then we can use it's size otherwise default
		// to zero.
		if (m_hWnd == NULL)
		{
			// If the window isn't going to be a child at the moment, then don't set
			// WS_CHILD and don't make it visible yet
			dwStyle = 0;
			ZeroMemory(&rc, sizeof(RECT));
		}
		else
		{
			dwStyle = WS_CHILD | WS_VISIBLE;
			GetWindowRect(&rc);
			rc.right -= rc.left;
			rc.bottom -= rc.top;
			rc.top = rc.left = 0;
		}
		m_hLibRTF = LoadLibrary(_T("RICHED32.DLL"));
		m_wndRTF.Create(m_hWnd, rc, NULL, dwStyle | ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL, 0);
	}
	void SetRTFModified(BOOL bModified)
	{
		if (m_wndRTF.m_hWnd != NULL)
		{
			m_wndRTF.SendMessage(EM_SETMODIFY, (WPARAM)bModified, 0);
		}
	}
	STDMETHOD(SetObjectRects)(LPCRECT prcPos,LPCRECT prcClip)
	{
		// When our control window moves, move the toolbar and the RTF window.
		IOleInPlaceObjectWindowlessImpl<CActiveDoc>::SetObjectRects(prcPos, prcClip);
		if (m_wndRTF.m_hWnd != NULL)
		{
			RECT	rcToolbar;
			int		cx = 0;
			int		cy = 0;
			int		nToolbarHeight = 0;
			if (m_hwndToolbar != NULL)
			{
				::SendMessage(m_hwndToolbar, TB_AUTOSIZE, 0L, 0L);
				::GetWindowRect(m_hwndToolbar, &rcToolbar);
				nToolbarHeight = rcToolbar.bottom-rcToolbar.top-1;
				cx = prcPos->right - prcPos->left;
				cy = prcPos->bottom - prcPos->top;
			}
			m_wndRTF.SetWindowPos(NULL, 0, nToolbarHeight, cx, cy-nToolbarHeight, SWP_NOZORDER | SWP_NOACTIVATE);
		}
		return S_OK;
	}
	HRESULT OnColorChange(WORD, WORD nID, HWND, BOOL&)
	{
		COLORREF col[4] =
		{
			RGB(0, 0, 0),	// Black
			RGB(255, 0, 0),	// Red
			RGB(0, 255, 0),	// Green
			RGB(0, 0, 255)	// Blue
		};
		CHARFORMAT cf;
		int	nColor;
		nColor = nID - ID_BLACK;
		_ASSERTE(nColor >=0 && nColor <= sizeof(col)/sizeof(COLORREF));
		cf.cbSize = sizeof(CHARFORMAT);
		cf.dwMask = CFM_COLOR;
		cf.dwEffects = 0;
		cf.crTextColor = col[nColor];
		m_wndRTF.SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
		return 0;
	}

	class CAboutDlg : public CDialogImpl<CAboutDlg>
	{
	public:
		enum { IDD = IDD_ABOUT };
		BEGIN_MSG_MAP(CAboutDlg)
			COMMAND_ID_HANDLER(IDOK, OnOK)
		END_MSG_MAP()
		HRESULT OnOK(WORD, WORD, HWND, BOOL&)
		{
			EndDialog(0);
			return 0;
		}
	};
	HRESULT OnHelpAbout(WORD, WORD, HWND, BOOL&)
	{
		CAboutDlg dlg;
		dlg.DoModal();
		return 0;
	}

// Data
protected:
	CContainedWindow	m_wndRTF;
	HINSTANCE	m_hLibRTF;
};
