#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <string>
#include <iostream>
#include "MemoryMapping.h"


BEGIN_NAMESPACE


struct MemoryMappingData
{
	HANDLE  m_fileHandle;
	DWORD   m_fileSizeHigh;
	DWORD   m_fileSizeLow;
	HANDLE  m_mappingHandle;
	void*	m_mapping;
};


MemoryMappingData* MemoryMapping_Open(const char* filename)
{
	OFSTRUCT of;
	HANDLE hFile = (HANDLE)OpenFile(filename, &of, OF_READ);
	DWORD fileSizeLow = 0;
	DWORD fileSizeHigh = 0;
	if ((int)hFile == -1)
	{
		std::cerr << "Problem openning file " << filename << std::endl;
		return 0;
	}
	fileSizeLow = GetFileSize(hFile, &fileSizeHigh);
	HANDLE hMMFile = CreateFileMapping(hFile, 0, PAGE_READONLY, fileSizeHigh, fileSizeLow, 0);
	if (!hMMFile)
	{
		std::cerr << "Problem creating mapping to file " << filename << std::endl;
		CloseHandle(hFile);
		return 0;
	}
	MemoryMappingData* mapping = new MemoryMappingData;
	mapping->m_fileHandle = hFile;
	mapping->m_fileSizeHigh = fileSizeHigh;
	mapping->m_fileSizeLow = fileSizeLow;
	mapping->m_mappingHandle = hMMFile;
	mapping->m_mapping = MapViewOfFile(hMMFile, FILE_MAP_READ, 0, 0, 0);
	return mapping;
}


void* MemoryMapping_GetAddress(MemoryMappingData* mapping)
{
	if (!mapping)
		return 0;
	return mapping->m_mapping;
}


uint64_t MemoryMapping_GetSize(MemoryMappingData* mapping)
{
	if (!mapping)
		return 0;
	return (uint64_t(mapping->m_fileSizeHigh) << 32) | mapping->m_fileSizeLow;
}


void MemoryMapping_Close(MemoryMappingData* mapping)
{
	if (!mapping)
		return;
	UnmapViewOfFile(mapping->m_mapping);
	CloseHandle(mapping->m_mappingHandle);
	CloseHandle(mapping->m_fileHandle);
	delete mapping;
}


MemoryMapping::MemoryMapping(const char* a_filename)
{
	m_data = MemoryMapping_Open(a_filename);
}


MemoryMapping::~MemoryMapping()
{
	MemoryMapping_Close(m_data);
}


void* MemoryMapping::address()
{
	return MemoryMapping_GetAddress(m_data);
}


uint64_t MemoryMapping::size()
{
	return MemoryMapping_GetSize(m_data);
}


END_NAMESPACE
