// ODDE.cpp : Defines the class behaviors for the application.
//

#include "stdafx.h"
#include "ODDE.h"
#include "ODDEDlg.h"
#include <math.h> // for sin, cos
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CODDEApp

BEGIN_MESSAGE_MAP(CODDEApp, CWinApp)
	//{{AFX_MSG_MAP(CODDEApp)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG
	ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CODDEApp construction


CODDEApp::CODDEApp()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
	m_nTimerID = 0;
	m_nTimerRate = 1000;// 1 sec;
	m_bUseFloatDataType = FALSE; // use double
	m_bKeepColumnType = FALSE; // always turn to numeric columns
}

/////////////////////////////////////////////////////////////////////////////
// The one and only CODDEApp object

CODDEApp theApp;

const int DEMO_DDE_TIMER_ID = 666;
const int NUM_PTS_PER_ONE_TIME_TRANSFER = 2000;
const int NUM_PTS_PER_REAL_TIME_TRANSFER = 10;

const char		szcWksRealTime[] = "RealTime";
const char		szcWksOneTime[] =	"OneTime";

/////////////////////////////////////////////////////////////////////////////
// CODDEApp initialization

BOOL CODDEApp::InitInstance()
{
	// Standard initialization
	// If you are not using these features and wish to reduce the size
	//  of your final executable, you should remove from the following
	//  the specific initialization routines you do not need.

#ifdef _AFXDLL
	Enable3dControls();			// Call this when using MFC in a shared DLL
#else
	Enable3dControlsStatic();	// Call this when linking to MFC statically
#endif

	CODDEDlg dlg;
	m_pMainWnd = &dlg;
	int nResponse = dlg.DoModal();
	if (nResponse == IDOK)
	{
		// TODO: Place code here to handle when the dialog is
		//  dismissed with OK
	}
	else if (nResponse == IDCANCEL)
	{
		// TODO: Place code here to handle when the dialog is
		//  dismissed with Cancel
	}

	// Since the dialog has been closed, return FALSE so that we exit the
	//  application, rather than start the application's message pump.
	return FALSE;
}


///////////////////////////////////////////////////////
// DDEDEMO specific functions
///////////////////////////////////////////////////////
// return TRUE if message is processed, return FALSE for default handling
BOOL CODDEApp :: DoWindowProc(CWnd *pWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	if(WM_DDE_ACK == message)
	{
		TRACE("DDE message WM_DDE_ACK\n");
		m_OriginServer.On_WM_DDE_ACK(pWnd->m_hWnd, wParam, lParam);
		return TRUE;
	} else if(WM_DDE_TERMINATE == message)
	{
		TRACE("DDE message WM_DDE_TERMINATE\n");
		m_OriginServer.On_WM_DDE_TERMINATE(pWnd->m_hWnd);
		return TRUE;
	}
	return FALSE;
}

BOOL CODDEApp :: SendData(int nRows, LPCTSTR lpcszWksName, WORD wOrginDDEFormat) // we will have several dataset prepared before hand
{
	int				nColumns = 4;// always send 4 columns in this example
static	INT			count = 0;
static	DWORD		init_time = 0;
		 
	// initialize the time only once
	if(init_time == 0)
		init_time = GetCurrentTime();
		
	// data area size, depends on rows and columns
	DWORD	length = nColumns * nRows * (m_bUseFloatDataType? sizeof(float) : sizeof(double));
				/* double is the best data type
				 * for Origin.
				 * Currently Origin only accept
				 * float and double.
				 */
				 
	HANDLE    hmem =
		GlobalAlloc(GHND | GMEM_DDESHARE, (LONG)sizeof(DDEPOKE) + 
					(DWORD)sizeof(DataWorkSheet) + length + 2);
        
	DDEPOKE		FAR * lpPokeData;
		lpPokeData = (DDEPOKE FAR *)GlobalLock(hmem);
		lpPokeData->fRelease = TRUE;
		lpPokeData->cfFormat = (short)m_OriginServer.GetOriginDDEClipboardFormat();

	DataWorkSheet	FAR * lpWorksheet; // move pointer to location in lpPokeData's memory at Value
		lpWorksheet = (DataWorkSheet FAR *)lpPokeData->Value;

		if(m_bUseFloatDataType)
			lpWorksheet->wFormat = DDE_DATA_FLOAT | wOrginDDEFormat;
		else
			lpWorksheet->wFormat = DDE_DATA_DOUBLE | wOrginDDEFormat;

		if(m_bKeepColumnType)
			lpWorksheet->wFormat |= DDE_DATA_KEEP_TYPE;

		lpWorksheet->nColumns = nColumns;
		lpWorksheet->nRows  = nRows;
		lpWorksheet->nColumnBegin = 0;
		/* the nRowBegin is ignored for appending */
	
		/* we are now ready to get some
		 * data 
		 */
	double	*lpData;
	lpData = (double *) lpWorksheet->data;
	float	*lpfData;
	lpfData = (float *) lpWorksheet->data;
/* the sample data consist of 4 columns
 * col(1)= count
 * col(2)= sin
 * col(3)= cos
 * col(4)= time
 */
 
#define	DATA_ARRAY(m,n)		lpData[(n) + (m) * nRows]
#define FDATA_ARRAY(m,n)	lpfData[(n) + (m) * nRows]
	/* data are stored column by column so that
	 * data in each column are continuous
	 */
	int		jj;
	double	findex, col2, col3, time;

	for(jj=0; jj < nRows; jj++)
	{
		col2 = sin((double)count/300.0) * ( 1.0 + (0.1*rand())/RAND_MAX);
		col3 = cos((double)count/300.0) * ( 1.0 + (0.1*rand())/RAND_MAX);
		time = (GetCurrentTime()-init_time)/1000.0;
		findex = count++;

		if(	m_bUseFloatDataType )
		{
			FDATA_ARRAY(0,jj) = findex;
			FDATA_ARRAY(1,jj) = col2;
			FDATA_ARRAY(2,jj) = col3;
			FDATA_ARRAY(3,jj) = time;
		}
		else
		{
			DATA_ARRAY(0,jj) = findex;
			DATA_ARRAY(1,jj) = col2;
			DATA_ARRAY(2,jj) = col3;
			DATA_ARRAY(3,jj) = time;
		}
	}

		/* now we are all done with the
		 * dde data block
		 */
	GlobalUnlock(hmem);

	if(!m_OriginServer.SendData(hmem, lpcszWksName, wOrginDDEFormat))
	{
        GlobalFree(hmem);
		return FALSE;
	}

	// eles the memory in hmem will be released by the server app
	return TRUE;
}

BOOL CODDEApp :: DoOneTimeDataTransfer()
{
	if(!IsServerRunning())
		return FALSE;

	return SendData(NUM_PTS_PER_ONE_TIME_TRANSFER, szcWksOneTime, 0); // send nextdataset into column 4
}


void CODDEApp :: StartRealTimeTransfer(CWnd *pWnd)
{
	ASSERT(m_nTimerID == 0);
	
	m_nTimerID = pWnd->SetTimer(DEMO_DDE_TIMER_ID, m_nTimerRate, NULL);
}


void CODDEApp :: StopRealTimeTransfer(CWnd *pWnd)
{
	ASSERT(m_nTimerID);
	pWnd->KillTimer(m_nTimerID);
	m_nTimerID = 0;
}

void CODDEApp :: ProcessRealTimeTransfer(int nEventID, CWnd *pWnd)
{
	if(nEventID != m_nTimerID)
		return;

	ASSERT(m_nTimerID);
	if(!IsServerRunning())
		return ;

	SendData(NUM_PTS_PER_REAL_TIME_TRANSFER, szcWksRealTime, DDE_DATA_APPEND);
}

BOOL CODDEApp :: DoOpenServer(CWnd *pWnd)
{
	if(!m_OriginServer.ConnectServer(pWnd->m_hWnd, m_strCmdLine))
		return FALSE;

	return TRUE;
}

//IV 04/07/99 t3291 FINISH_MOVE_DDEDEMO_32BIT
BOOL CODDEApp::OnCommandString(LPCTSTR lptsrCommand)
{
	return m_OriginServer.SendCommandString(lptsrCommand);
}
//end FINISH_MOVE_DDEDEMO_32BIT
