// DataTransfer.cpp: implementation of the CDataTransfer class.
//
//////////////////////////////////////////////////////////////////////
 /*      
 *          Copyright (C) 2000 RasSimTech Ltd. 
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version. 
 *  This program 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 General Public License for more details. 
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 */

#include "DataTransfer.h"

#include <afxwin.h>         // MFC core and standard components

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#define BASE_FILE_PATH ""
#define BASE_FILE_NAME BASE_FILE_PATH"Shared"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CDataTransfer::CDataTransfer(int iDataSize, int iClassID)
{
	m_strFileName.Format(BASE_FILE_NAME"File%d",iClassID);
	m_strMapName.Format(BASE_FILE_NAME"Map%d",iClassID);
	m_strMutexName.Format(BASE_FILE_NAME"Mutex%d",iClassID);

	m_vdData.resize(iDataSize,0.0);
	m_iDataSizeBytes = iDataSize*sizeof(DATA_TYPE);

	// calculate the required file size in multiples of 4096
	ldiv_t div_result = ldiv(m_iDataSizeBytes,4096);
	m_iBufferSize = (div_result.rem==0)?(div_result.quot*4096):((div_result.quot+1)*4096);

	m_hFile = CreateMapFile(m_strFileName);

	if((m_hFile!=NULL)&&(m_hFile!=(void *)ERROR_USER_MAPPED_FILE))
	{
		m_hMapFile = CreateMap(m_hFile,m_strMapName);
		if(m_hMapFile!=NULL)
		{
			m_lpMapAddress = MapView(m_hMapFile);
		}
	}
	else if(m_hFile==(void *)ERROR_USER_MAPPED_FILE)
	{
		m_hMapFile = GetCurrentMap(m_strMapName);
		if(m_hMapFile!=NULL)
		{
			m_lpMapAddress = MapView(m_hMapFile);
		}
	}

}

CDataTransfer::~CDataTransfer()
{
	if (!UnmapViewOfFile(m_lpMapAddress)) 
	{ 
		ErrorHandler("Could not unmap view of file."); 
	} 
  	CloseHandle(m_hMapFile);
  	CloseHandle(m_hFile);
}


/************************************************************************** 
 * HANDLE CreateMapFile(char *MapFileName) 
 * 
 * Purpose: Create a Map file to map named share memory 
 * 
 * Inputs:  none 
 * 
 * Returns: MapFileHandle - a handle to the file 
 *                        or NULL if failure 
 * 
 * Calls:   CreateFile, ErrorOut 
 * 
\**************************************************************************/ 
HANDLE CDataTransfer::CreateMapFile(LPCTSTR lpstrMapFileName) 
{ 
   HANDLE hMapFileHandle; 
 
   hMapFileHandle= CreateFile(lpstrMapFileName, 
                             GENERIC_READ | GENERIC_WRITE, 
                             FILE_SHARE_READ | FILE_SHARE_WRITE, 
                             NULL, 
                             CREATE_ALWAYS, 
                             FILE_ATTRIBUTE_NORMAL, 
                             NULL); 
 

   if ((hMapFileHandle == INVALID_HANDLE_VALUE) && (GetLastError() != ERROR_USER_MAPPED_FILE))
   { 
      ErrorHandler("CreateFile"); 
      return(NULL); 
   } 
   else if((hMapFileHandle == INVALID_HANDLE_VALUE) && (GetLastError() == ERROR_USER_MAPPED_FILE))
   {
      return((void *)ERROR_USER_MAPPED_FILE); 
   }
   else
   {
      return(hMapFileHandle); 
   }
} 
 
/************************************************************************** 
 * HANDLE CreateMap(HANDLE FileToBeMapped, char *MapName ) 
 * 
 * Purpose: Create File Mapping object using the open file handle 
 * 
 * Inputs:  FileToBeMapped - handle to the file 
 * 
 * Returns: MapHandle - handle to the file mapping object 
 *                    or NULL if failure 
 * 
 * Calls:   CreateFileMapping, ErrorOut 
\**************************************************************************/ 
 
HANDLE CDataTransfer::CreateMap(HANDLE hFileToBeMapped, LPCTSTR lpstrMapName) 
{ 
   HANDLE hMapHandle; 
 
   hMapHandle= CreateFileMapping(hFileToBeMapped, 
                                NULL, 
                                PAGE_READWRITE, 
                                0, 
                                m_iBufferSize, 
                                lpstrMapName); 
 
   if (hMapHandle == NULL)
   { 
      ErrorHandler("CreateFileMapping"); 
      return(NULL); 
   } 
   else
   {
      return(hMapHandle); 
   }
} 
 
 
/************************************************************************** 
 * LPVOID MapView(HANDLE hMap) 
 * 
 * Purpose: Map the file mapping object into address space 
 * 
 * Inputs:  hMap - handle to the mapping object 
 * 
 * Returns: MappedPointer - pointer to the address space that the 
 *                        object is mapped into 
 *                        or NULL if failure 
 * 
 * Calls:   MapViewOfFile, ErrorOut 
 * 
\**************************************************************************/ 
 
LPVOID CDataTransfer::MapView(HANDLE hMap) 
{ 
   LPVOID lpvoidMappedPointer; 
 
   lpvoidMappedPointer= MapViewOfFile(hMap, 
                                FILE_MAP_WRITE | FILE_MAP_READ, 
                                0, 0, 4096); 
   if (lpvoidMappedPointer == NULL) 
   { 
      ErrorHandler("MapViewOfFile"); 
      return(NULL); 
   } 
   else 
      return(lpvoidMappedPointer); 
} 


HANDLE CDataTransfer::GetCurrentMap(LPCTSTR lpstrMapName)
{
   HANDLE hMapHandle; 
 
   hMapHandle= OpenFileMapping(FILE_MAP_WRITE,TRUE,lpstrMapName); 
 
   if (hMapHandle == NULL) 
   { 
      ErrorHandler("CreateFileMapping"); 
      return(NULL); 
   } 
   else 
      return(hMapHandle); 
}

void CDataTransfer::ErrorHandler(CString strErrorString)
{
	char  str[80]; 

	LPVOID lpMsgBuf;
	FormatMessage( 
		FORMAT_MESSAGE_ALLOCATE_BUFFER | 
		FORMAT_MESSAGE_FROM_SYSTEM | 
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		(LPTSTR) &lpMsgBuf,
		0,
		NULL 
	);
	wsprintf(str, "%s - %s", strErrorString, lpMsgBuf); 
	AfxMessageBox(str,(MB_OK|MB_ICONEXCLAMATION));
	fprintf(stderr,"%s",str);
	LocalFree( lpMsgBuf );
}

void CDataTransfer::WriteData()
{
	CMutex mutexTest(TRUE,m_strMutexName);
	memcpy((LPVOID)m_lpMapAddress,(LPVOID)&*(m_vdData.begin()),m_iDataSizeBytes);
	mutexTest.Unlock();
}

void CDataTransfer::ReadData()
{
	CMutex mutexTest(TRUE,m_strMutexName);
	memcpy((LPVOID)&*(m_vdData.begin()),(LPVOID)m_lpMapAddress,m_iDataSizeBytes);
	mutexTest.Unlock();
}

