#include "mmap.h"
#include "m3derror.h"
#ifndef WIN32
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#endif
#include <unistd.h>
#include <string.h>
#include <iostream>
#include <errno.h>

#ifdef WIN32
#include <windows.h>
#include <sys/stat.h>
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *start, size_t length);
#define MAP_PRIVATE 1
#define MAP_FAILED 0
#define MAP_SHARED 1
#define PROT_READ 0
#define getpagesize() 65536
#endif

namespace M3D
{
	MMAP::MMAP ( const std::string &fname )
	{
		mmap ( fname.c_str() );
	}

	MMAP::MMAP ( const char* fname )
	{
		mmap ( fname );
	}
        MMAP::MMAP()
        {
            _mapped_file_ = 0;
            _file_size_ = 0;
        }

	MMAP::~ MMAP()
	{
		if(!_mapped_file_)return;
		if ( munmap ( _mapped_file_, _file_size_ ) <0 ) std::cerr<<"Failed to unmap file in M3D::MMAP. File size:"<<_file_size_<<std::endl;
	}
	void MMAP::mmap ( const char * fname )
	{
		_file_.open ( fname );
		//Получим размер файла
		struct stat file_stat;
		if ( fstat ( _file_, &file_stat ) <0 ) THROW ( strerror ( errno ) );
		_file_size_ = file_stat.st_size;

		//Отмапим файл
		_mapped_file_ = ( char* ) ::mmap ( 0, _file_size_, PROT_READ, MAP_SHARED, _file_, 0 );
		if ( _mapped_file_ == MAP_FAILED )
		{
			THROW ( strerror ( errno ) );
		}
	}

}
#ifdef WIN32
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) 
{ 
 HANDLE handle; 
 
 if (start != NULL || !(flags & MAP_PRIVATE))  return MAP_FAILED;
 
 if (offset % getpagesize() != 0) return MAP_FAILED;
 
 handle = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL, PAGE_WRITECOPY, 0, 0, NULL); 
 
 if (handle != NULL) 
 { 
  start = MapViewOfFile(handle, FILE_MAP_COPY, 0, offset, length); 
  CloseHandle(handle); 
 } 
 return start; 
} 
 
int munmap(void *start, size_t length) 
{ 
 UnmapViewOfFile(start); 
 return 0;
}
#endif