/*
	This file is part of Hikari, a library that allows developers
	to use Flash in their Ogre3D applications.

	Copyright (C) 2008 Adam J. Simmons

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef __FlashSite_H__
#define __FlashSite_H__

#import "PROGID:ShockwaveFlash.ShockwaveFlash" named_guids

#ifndef max
#define max(a,b)	(((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b)	(((a) < (b)) ? (a) : (b))
#endif

namespace Hikari {
namespace Impl {

class FlashSite : public IOleInPlaceSiteWindowless, public IOleClientSite	
{
public:
	int	refCount;
	FlashControl* owner;

public:
	FlashSite() : refCount(0), owner(0)
	{		
	}	

	virtual ~FlashSite()
	{
		if(owner)
			owner->comCount--;
	}

	void Init(FlashControl* owner)
	{
		this->owner = owner;
		owner->comCount++;
	}

	HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppv)
	{
		*ppv = 0;

		if(riid == IID_IUnknown)
		{
			*ppv = (IUnknown*)(IOleWindow*)this;
			AddRef();
			return S_OK;
		}
		else if (riid == IID_IOleWindow)
		{
			*ppv = (IOleWindow*)this;
			AddRef();
			return S_OK;
		}
		else if (riid == IID_IOleInPlaceSite)
		{
			*ppv = (IOleInPlaceSite*)this;
			AddRef();
			return S_OK;
		}
		else if (riid == IID_IOleInPlaceSiteEx)
		{
			*ppv = (IOleInPlaceSiteEx*)this;
			AddRef();
			return S_OK;
		}
		else if (riid == IID_IOleInPlaceSiteWindowless)
		{
			*ppv = (IOleInPlaceSiteWindowless*)this;
			AddRef();
			return S_OK;
		}
		else if (riid == IID_IOleClientSite)
		{
			*ppv = (IOleClientSite*)this;
			AddRef();
			return S_OK;
		}
		else
		{   
			return E_NOTIMPL;
		}
	}

	ULONG STDMETHODCALLTYPE AddRef()
	{  
		return ++refCount;
	}

	ULONG STDMETHODCALLTYPE Release()
	{  
		--refCount;

		if(!refCount)
			delete this;

		return refCount;
	}

	virtual HRESULT STDMETHODCALLTYPE SaveObject(void)
	{
		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk)
	{
		*ppmk = 0;
		return E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE GetContainer(IOleContainer ** theContainerP)
	{			
		return E_NOINTERFACE;
	}

	virtual HRESULT  STDMETHODCALLTYPE ShowObject(void)
	{
		return E_NOTIMPL;
	}

	virtual HRESULT  STDMETHODCALLTYPE OnShowWindow(BOOL)
	{
		return E_NOTIMPL;
	}

	virtual HRESULT  STDMETHODCALLTYPE RequestNewObjectLayout(void)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode)
	{
	    return S_OK;
	}

	HRESULT STDMETHODCALLTYPE GetWindow(HWND __RPC_FAR* theWnndow)
	{
		return E_FAIL;
	}

	HRESULT STDMETHODCALLTYPE CanInPlaceActivate(void)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE OnInPlaceActivate(void)
	{		
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE OnUIActivate(void)
	{		
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE GetWindowContext(IOleInPlaceFrame __RPC_FAR *__RPC_FAR *ppFrame, IOleInPlaceUIWindow __RPC_FAR *__RPC_FAR *ppDoc, 
		LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo)
	{
		RECT rect;
		rect.left = 0;
		rect.top = 0;
		rect.right = owner->width;
		rect.bottom = owner->height;

		*lprcPosRect = rect;
		*lprcClipRect = rect;
		
		*ppFrame = 0;
		QueryInterface(__uuidof(IOleInPlaceFrame), (void**)ppFrame);		
		*ppDoc = 0;

		lpFrameInfo->fMDIApp = FALSE;
		lpFrameInfo->hwndFrame = 0;
		lpFrameInfo->haccel = 0;
		lpFrameInfo->cAccelEntries = 0;
		
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE Scroll(SIZE scrollExtant)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE OnUIDeactivate(BOOL fUndoable)
	{		
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate(void)
	{	
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE DiscardUndoState(void)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE DeactivateAndUndo(void)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE OnPosRectChange(LPCRECT lprcPosRect)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE OnInPlaceActivateEx(BOOL __RPC_FAR *pfNoRedraw, DWORD dwFlags)
	{		
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE OnInPlaceDeactivateEx(BOOL fNoRedraw)
	{		
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE RequestUIActivate(void)
	{
		return S_FALSE;
	}

	HRESULT STDMETHODCALLTYPE CanWindowlessActivate(void)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE GetCapture(void)
	{
		return S_FALSE;
	}

	HRESULT STDMETHODCALLTYPE SetCapture(BOOL fCapture)
	{
		return S_FALSE;
	}

	HRESULT STDMETHODCALLTYPE GetFocus(void)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE SetFocus(BOOL fFocus)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE GetDC(LPCRECT pRect, DWORD grfFlags, HDC __RPC_FAR *phDC)
	{		
		return E_INVALIDARG;		
	}

	HRESULT STDMETHODCALLTYPE ReleaseDC(HDC hDC)
	{
		return E_INVALIDARG;
	}

	HRESULT STDMETHODCALLTYPE InvalidateRect(LPCRECT pRect, BOOL fErase)
	{	
		if(owner->isTotallyDirty)
			return S_OK;

		if(pRect)
		{
			if(owner->isClean)
			{
				owner->dirtyBounds.left = pRect->left;
				owner->dirtyBounds.right = pRect->right;
				owner->dirtyBounds.top = pRect->top;
				owner->dirtyBounds.bottom = pRect->bottom;
				owner->isClean = false;
			}
			else
			{
				owner->dirtyBounds.left = min(owner->dirtyBounds.left, pRect->left);
				owner->dirtyBounds.right = max(owner->dirtyBounds.right, pRect->right);
				owner->dirtyBounds.top = min(owner->dirtyBounds.top, pRect->top);
				owner->dirtyBounds.bottom = max(owner->dirtyBounds.bottom, pRect->bottom);
			}
		}

		if(owner->dirtyBounds.left < 0 || owner->dirtyBounds.top < 0 || 
			owner->dirtyBounds.right > owner->width || owner->dirtyBounds.bottom > owner->height || !pRect)
		{
			owner->invalidateTotally();
		}

		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE InvalidateRgn(HRGN hRGN, BOOL fErase)
	{	
		owner->invalidateTotally();

		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE ScrollRect(INT dx, INT dy, LPCRECT pRectScroll, LPCRECT pRectClip)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE AdjustRect(LPRECT prc)
	{
		if(!prc)
			return E_INVALIDARG;
		
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE OnDefWindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT __RPC_FAR *plResult)
	{
		return S_FALSE;
	}
};

}
}

#endif

