#include <stdio.h>
#include <common\ddemsg.hpp>

HGLOBAL DDEMessage::buildDDEDataHandle(HGLOBAL hGlobalData)
{
	DDEData *npDDEData;
	DWORD sizeData(::GlobalSize(hGlobalData));
	char *npLinkData;

	HGLOBAL hGlobalDDEData=::GlobalAlloc(GMEM_DDESHARE|GHND,sizeof(DDEData)+sizeData-1L);
	npDDEData=(DDEData FAR*)::GlobalLock(hGlobalDDEData);
	npLinkData=(char FAR*)::GlobalLock(hGlobalData);
	npDDEData->mustRespond(TRUE);
	npDDEData->mustRelease(FALSE);
	npDDEData->isResponseForRequest(TRUE);
	npDDEData->setFormat(TextFormat);
	npDDEData->setData(npLinkData,sizeData);
	::GlobalUnlock(hGlobalData);
	::GlobalFree(hGlobalData);
	::GlobalUnlock(hGlobalDDEData);
	return hGlobalDDEData;
}

HGLOBAL DDEMessage::copyDDEDataHandle(HGLOBAL hGlobalDDEData)
{
	int sizeData;
	HGLOBAL hGlobalData;
	DDEData FAR *npDDEData;
	char *pReturnData;
	
	if(!hGlobalDDEData)return (HGLOBAL)FALSE;
	npDDEData=(DDEData FAR*)::GlobalLock(hGlobalDDEData);
	if(!npDDEData)return (HGLOBAL)FALSE;
	sizeData=::GlobalSize(hGlobalDDEData)-(sizeof(DDEDATA)-1);
	if(sizeData<=0)return (HGLOBAL)FALSE;
	hGlobalData=::GlobalAlloc(GMEM_FIXED,sizeData);
	pReturnData=(char FAR*)::GlobalLock(hGlobalData);
	::memcpy(pReturnData,npDDEData->getData(),sizeData);
	::GlobalUnlock(hGlobalDDEData);
	::GlobalUnlock(hGlobalData);
	return hGlobalData;
}

WORD DDEMessage::sendInitiate(String applicationString,String topicString)
{
	LRESULT returnCode(FALSE);

	if(applicationString.isNull()||topicString.isNull())return returnCode;
	ATOM atomApplication(::GlobalAddAtom(applicationString));
	ATOM atomTopic(::GlobalAddAtom(topicString));
	mLastDDEMessage=WM_DDE_INITIATE;
	returnCode=::SendMessage(HWND_BROADCAST,WM_DDE_INITIATE,(WPARAM)mhClientWnd,MAKELPARAM(atomApplication,atomTopic));
	::GlobalDeleteAtom(atomApplication);
	::GlobalDeleteAtom(atomTopic);
	return returnCode;
}

WORD DDEMessage::acceptInitiate(String applicationString,String topicString)
{
	if(applicationString.isNull())return FALSE;
	if(topicString.isNull())return FALSE;
	ATOM atomApplication(::GlobalAddAtom(applicationString));
	ATOM atomTopic(::GlobalAddAtom(topicString));
	mLastDDEMessage=WM_DDE_ACK;
	return ::SendMessage(mhServerWnd,WM_DDE_ACK,(WPARAM)mhClientWnd,MAKELPARAM(atomApplication,atomTopic));
}

void DDEMessage::cleanup(void)
{
	if(!mhGlobalLastDDEData)return;
  ::GlobalUnlock(mhGlobalLastDDEData);
	::GlobalFree(mhGlobalLastDDEData);
  mhGlobalLastDDEData=0;
}

#if defined(__FLAT__)
WORD DDEMessage::postRequest(String requestString)
{
	if(requestString.isNull()||!isValid())return FALSE;
	ATOM atomDescription(::GlobalAddAtom(requestString));
	mLastDDEMessage=WM_DDE_REQUEST;
	return ::PostMessage(mhServerWnd,WM_DDE_REQUEST,(WPARAM)mhClientWnd,MAKELPARAM(TextFormat,atomDescription));
}

WORD DDEMessage::receiveRequest(CallbackData &someCallbackData,String &receiveString)
{
	WORD returnCode(FALSE);

  mLastCallbackData=someCallbackData;
	if(!someCallbackData.hiWord())receiveString=mStringUnset;
	else
	{
		receiveString.reserve(MaxLength);
		::GlobalGetAtomName(someCallbackData.hiWord(),receiveString,MaxLength-1);
		::GlobalDeleteAtom(someCallbackData.hiWord());
		returnCode=TRUE;
	}
	return returnCode;
}

WORD DDEMessage::postAcknowledge(void)
{
  String ackDescription(mStringUnset);
	DDEAck ddeAck;

	return postAcknowledge(ddeAck,ackDescription);
}

WORD DDEMessage::postAcknowledge(DDEAck someDDEAck,String ackDescription)
{
	if(ackDescription.isNull()||!isValid())return FALSE;
	ATOM atomDescription(::GlobalAddAtom(ackDescription));
	LONG packedParam(::PackDDElParam(WM_DDE_ACK,(WORD)someDDEAck,atomDescription));
	if(!packedParam){::GlobalDeleteAtom(atomDescription);return FALSE;}
	mLastDDEMessage=WM_DDE_ACK;
	return ::PostMessage(mhServerWnd,WM_DDE_ACK,(WPARAM)mhClientWnd,(LPARAM)packedParam);
}

WORD DDEMessage::receiveAcknowledge(CallbackData &someCallbackData)
{
	UINT packedParamLo(0);
	UINT packedParamHi(0);
	String stringOne;
  String stringTwo;

	mLastCallbackData=someCallbackData;
	if(WM_DDE_INITIATE==lastDDEMessage())
	{
		if(someCallbackData.loWord())::GlobalDeleteAtom(someCallbackData.loWord());
		if(someCallbackData.hiWord())::GlobalDeleteAtom(someCallbackData.hiWord());
    return TRUE;
	}
	else
	{
		stringOne.reserve(MaxLength);
		stringTwo.reserve(MaxLength);
		::UnpackDDElParam(WM_DDE_ACK,someCallbackData.lParam(),&packedParamLo,&packedParamHi);
		if(packedParamHi)
		{
			::GlobalGetAtomName(packedParamHi,stringTwo,MaxLength-1);
			if(!stringTwo.isNull())::GlobalDeleteAtom(packedParamHi);
		}
	  ::FreeDDElParam(WM_DDE_ACK,someCallbackData.lParam());
	}
	return TRUE;
}

WORD DDEMessage::postData(HGLOBAL hGlobalData,String stringDescription)
{
	if(!hGlobalData||!isValid())return FALSE;
	if(stringDescription.isNull())stringDescription=mStringUnset;
	cleanup();
	mhGlobalLastDDEData=buildDDEDataHandle(hGlobalData);
	if(!mhGlobalLastDDEData)return FALSE;
	ATOM atomDescription(::GlobalAddAtom(stringDescription));
	LPARAM packedParam(::PackDDElParam(WM_DDE_DATA,(UINT)mhGlobalLastDDEData,atomDescription));
	if(!packedParam){::GlobalDeleteAtom(atomDescription);return FALSE;}
	mLastDDEMessage=WM_DDE_DATA;
	return ::PostMessage(mhServerWnd,WM_DDE_DATA,(WPARAM)mhClientWnd,packedParam);
}

HGLOBAL DDEMessage::receiveData(CallbackData &someCallbackData)
{
	UINT packedParamLo;
	UINT packedParamHi;
	HGLOBAL hGlobalDDEData;

	mLastCallbackData=someCallbackData;
	::UnpackDDElParam(WM_DDE_DATA,someCallbackData.lParam(),&packedParamLo,&packedParamHi);
	if(packedParamHi)::GlobalDeleteAtom(packedParamHi);
	if(packedParamLo)hGlobalDDEData=(HGLOBAL)packedParamLo;
	else hGlobalDDEData=(HGLOBAL)FALSE;
	::FreeDDElParam(WM_DDE_DATA,someCallbackData.lParam());
	if(hGlobalDDEData)mhGlobalLastDDEData=copyDDEDataHandle(hGlobalDDEData);
	return mhGlobalLastDDEData;
}
#else
WORD DDEMessage::postRequest(String requestorString)
{
	if(requestorString.isNull()||!isValid())return FALSE;
	ATOM atomDescription(::GlobalAddAtom(requestorString));
	mLastDDEMessage=WM_DDE_REQUEST;
	return ::PostMessage(mhServerWnd,WM_DDE_REQUEST,(WPARAM)mhClientWnd,MAKELPARAM(TextFormat,atomDescription));
}

WORD DDEMessage::receiveRequest(CallbackData &someCallbackData,String &receiveString)
{
	WORD returnCode(FALSE);

	mLastCallbackData=someCallbackData;
	if(!someCallbackData.hiWord())receiveString=mStringUnset;
	else
	{
		receiveString.reserve(MaxLength);
		::GlobalGetAtomName(someCallbackData.hiWord(),receiveString,MaxLength-1);
		::GlobalDeleteAtom(someCallbackData.hiWord());
		returnCode=TRUE;
	}
	return returnCode;
}

WORD DDEMessage::postAcknowledge(void)
{
  String ackDescription(mStringUnset);
	DDEAck ddeAck;

  return postAcknowledge(ddeAck,ackDescription);
}

WORD DDEMessage::postAcknowledge(DDEAck someDDEAck,String ackDescription)
{
	if(ackDescription.isNull())ackDescription=mStringUnset;
	ATOM ackAtom(::GlobalAddAtom(ackDescription));
	mLastDDEMessage=WM_DDE_ACK;
	return ::PostMessage(mhServerWnd,WM_DDE_ACK,(WPARAM)mhClientWnd,MAKELPARAM((WORD)someDDEAck,ackAtom));
}

WORD DDEMessage::receiveAcknowledge(CallbackData &someCallbackData)
{
	String stringOne;
  String stringTwo;
	UINT packedParamLo;
	UINT packedParamHi;

	if(!isValid())return FALSE;
  mLastCallbackData=someCallbackData;
	if(WM_DDE_INITIATE==lastDDEMessage())
	{
		if(someCallbackData.loWord())::GlobalDeleteAtom(someCallbackData.loWord());
		if(someCallbackData.hiWord())::GlobalDeleteAtom(someCallbackData.hiWord());
    return TRUE;
	}
	stringOne.reserve(MaxLength);
	stringTwo.reserve(MaxLength);
	if(someCallbackData.loWord())
	{
		::GlobalGetAtomName(someCallbackData.loWord(),stringOne,MaxLength-1);
		if(!stringOne.isNull())::GlobalDeleteAtom(someCallbackData.loWord());
	}
	if(someCallbackData.hiWord())
	{
		::GlobalGetAtomName(someCallbackData.hiWord(),stringTwo,MaxLength-1);
		if(!stringTwo.isNull())::GlobalDeleteAtom(someCallbackData.hiWord());
	}
	return TRUE;
}

WORD DDEMessage::postData(HGLOBAL hGlobalData,String stringDescription)
{
	cleanup();
	if(!hGlobalData||!isValid())return FALSE;
	if(stringDescription.isNull())stringDescription=mStringUnset;
  cleanup();
	mhGlobalLastDDEData=buildDDEDataHandle(hGlobalData);
	if(!mhGlobalLastDDEData)return FALSE;
	ATOM atomDescription(::GlobalAddAtom(stringDescription));
	mLastDDEMessage=WM_DDE_DATA;
	return ::PostMessage(mhServerWnd,WM_DDE_DATA,(WPARAM)mhClientWnd,MAKELPARAM(mhGlobalLastDDEData,atomDescription));
}

HGLOBAL DDEMessage::receiveData(CallbackData &someCallbackData)
{
	HGLOBAL hGlobalDDEData;

	cleanup();
	mLastCallbackData=someCallbackData;
	if(someCallbackData.hiWord())::GlobalDeleteAtom(someCallbackData.hiWord());
	if(someCallbackData.loWord())hGlobalDDEData=(HGLOBAL)someCallbackData.loWord();
	else hGlobalDDEData=(HGLOBAL)FALSE;
	if(!hGlobalDDEData)return hGlobalDDEData;
	return copyDDEDataHandle(hGlobalDDEData);
}
#endif

