#include <common/clipbrd.hpp>
#include <common/string.hpp>

Clipboard::Clipboard(GUIWindow &parentWindow)
: mParentWindow(parentWindow), mhNextViewerWnd(0)
{
	if(!parentWindow.isValid())return;
  mChangeCBChainHandler.setCallback(this,&Clipboard::changeCBChainHandler);
	mDrawClipboardHandler.setCallback(this,&Clipboard::drawClipboardHandler);
	mDestroyHandler.setCallback(this,&Clipboard::destroyHandler);
	mParentWindow.insertHandler(VectorHandler::ChangeCBChainHandler,&mChangeCBChainHandler);
	mParentWindow.insertHandler(VectorHandler::DrawClipboardHandler,&mDrawClipboardHandler);
	mParentWindow.insertHandler(VectorHandler::DestroyHandler,&mDestroyHandler);
	mhNextViewerWnd=::SetClipboardViewer(mParentWindow);
}

Clipboard::~Clipboard()
{
  removeCBChain();
	mParentWindow.removeHandler(VectorHandler::DrawClipboardHandler,&mDrawClipboardHandler);
	mParentWindow.removeHandler(VectorHandler::ChangeCBChainHandler,&mChangeCBChainHandler);
	mParentWindow.removeHandler(VectorHandler::DestroyHandler,&mDestroyHandler);
}

void Clipboard::setDrawDataHandler(PureCallback *pCallback)
{
  mDrawDataHandler=CallbackPointer(pCallback);
}

bool Clipboard::isOkay(void)const
{
  return mParentWindow.isValid();
}

CallbackData::ReturnType Clipboard::destroyHandler(CallbackData &someCallbackData)
{
  removeCBChain();
  return (CallbackData::ReturnType)false;
}

CallbackData::ReturnType Clipboard::changeCBChainHandler(CallbackData &someCallbackData)
{
  if(!isOkay())return (CallbackData::ReturnType)false;
	if((HWND)someCallbackData.wParam()==mhNextViewerWnd)mhNextViewerWnd=(HWND)someCallbackData.loWord();
	else ::SendMessage(mhNextViewerWnd,WM_CHANGECBCHAIN,someCallbackData.wParam(),someCallbackData.lParam());
  return (CallbackData::ReturnType)false;
}

CallbackData::ReturnType Clipboard::drawClipboardHandler(CallbackData &someCallbackData)
{
  if(!isOkay())return (CallbackData::ReturnType)false;
	::SendMessage(mhNextViewerWnd,WM_DRAWCLIPBOARD,someCallbackData.wParam(),someCallbackData.lParam());
	if(::OpenClipboard(mParentWindow)){drawClipboard();::CloseClipboard();}
	return (CallbackData::ReturnType)false;
}

void Clipboard::removeCBChain(void)
{
  if(!isOkay())return;
	::ChangeClipboardChain(mParentWindow,mhNextViewerWnd);
}

bool Clipboard::setClipboard(Format format,HANDLE hData)
{
  bool returnCode(false);

  if(!isOkay()||!hData)return returnCode;
	if(!::OpenClipboard(mParentWindow))return returnCode;
	emptyClipboard();
	returnCode=(hData==::SetClipboardData(format,hData));
	::CloseClipboard();
	return returnCode;
}

bool Clipboard::setClipboard(const String &strText)
{
  bool returnCode(false);

  if(!isOkay()||strText.isNull()||!::OpenClipboard(mParentWindow))return returnCode;
	emptyClipboard();
	int strLen(strText.length());
	char *ptrData=(char*)::GlobalAlloc(GMEM_FIXED,strLen+1);
	if(!ptrData){::CloseClipboard();return returnCode;}
	::memset(ptrData,0,strLen+1);
	::memcpy(ptrData,(char*)(String&)strText,strLen);
	returnCode=ptrData==::SetClipboardData(CF_TEXT,(HANDLE)ptrData);
	::CloseClipboard();
	return true;
}

bool Clipboard::setClipboard(UINT format,const String &strText)
{
  bool returnCode(false);

  if(!isOkay()||strText.isNull()||!::OpenClipboard(mParentWindow))return returnCode;
	emptyClipboard();
	int strLen(strText.length());
	char *ptrData=(char*)::GlobalAlloc(GMEM_FIXED,strLen+1);
	if(!ptrData){::CloseClipboard();return returnCode;}
	::memset(ptrData,0,strLen+1);
	::memcpy(ptrData,(char*)(String&)strText,strLen);
	returnCode=ptrData==::SetClipboardData(format,(HANDLE)ptrData);
	::CloseClipboard();
	return true;
}

bool Clipboard::getClipboard(String &strText)const
{
  bool returnCode(false);
	HANDLE handle=0;

  if(!isOkay()||!::OpenClipboard(mParentWindow))return returnCode;
	if(0==(handle=::GetClipboardData(CF_TEXT))){::CloseClipboard();return false;}
	strText=(LPSTR)::GlobalLock(handle);
	::GlobalUnlock(handle);
  ::CloseClipboard();
	return true;
}

bool Clipboard::getClipboard(UINT format,String &strText)const
{
  bool returnCode(false);
	HANDLE handle=0;

  if(!isOkay()||!::OpenClipboard(mParentWindow))return returnCode;
	if(0==(handle=::GetClipboardData(format))){::CloseClipboard();return false;}
	strText=(LPSTR)::GlobalLock(handle);
	::GlobalUnlock(handle);
  ::CloseClipboard();
	return true;
}

UINT Clipboard::registerClipboardFormat(const String &strFormatName)
{
  return ::RegisterClipboardFormat(strFormatName.str());
}

bool Clipboard::hasData(Format format)
{
	return ::IsClipboardFormatAvailable(format);
}

bool Clipboard::hasData(UINT format)
{
	return ::IsClipboardFormatAvailable(format);
}

// virtuals

void Clipboard::drawClipboard(void)
{
  mDrawDataHandler.callback(CallbackData());
}

// (ie) HANDLE hData=::GetClipboardData(CF_DIB);

