#include "my_global.h"
#ifdef UNIX
#include "osutil.h"
#include <errno.h>
#include <stddef.h>
//typedef int HANDLE;	done in os2def.h
#else /* WINDOWS */
//#include <windows.h>
#include "osutil.h"
#endif /* WINDOWS */
#include <stdlib.h>
#include <stdio.h>

#include "global.h"
#include "plgdbsem.h"
#include "maputil.h"

#ifdef WIN32
/***********************************************************************/
/*  In Insert mode, just open the file for append. Otherwise           */
/*  create the mapping file object. The map handle can be released     */
/*  immediately because they will not be used anymore.                 */
/*  If del is true in DELETE mode, then delete the whole file.         */
/*  Returns the file handle that can be used by caller.                */
/***********************************************************************/
HANDLE CreateFileMap(PGLOBAL g, LPCSTR filename,
										 MEMMAP *mm, MODE mode, bool del)
	{
  HANDLE hFile;
  HANDLE hFileMap;
  DWORD  access, share, disposition;

  memset(mm, 0, sizeof(MEMMAP));
	*g->Message = '\0';

  switch (mode) {
    case MODE_READ:
      access = GENERIC_READ;
      share = FILE_SHARE_READ;
      disposition = OPEN_EXISTING;
      break;
    case MODE_UPDATE:
    case MODE_DELETE:
	    access = GENERIC_READ | GENERIC_WRITE;
	    share = 0;
      disposition = (del) ? TRUNCATE_EXISTING : OPEN_EXISTING;
      break;
    case MODE_INSERT:
      access = GENERIC_WRITE;
      share = 0;
      disposition = OPEN_ALWAYS;
      break;
		default:
			sprintf(g->Message, MSG(BAD_FUNC_MODE), "CreateFileMap", mode);
			return INVALID_HANDLE_VALUE;
    } // endswitch

  hFile = CreateFile(filename, access, share, NULL,	disposition,
										 FILE_ATTRIBUTE_NORMAL, NULL);
  
  if (hFile != INVALID_HANDLE_VALUE)
		if (mode != MODE_INSERT) {
      /*****************************************************************/
      /*  Create the file-mapping object.                              */
      /*****************************************************************/
      access = (mode == MODE_READ) ? PAGE_READONLY : PAGE_READWRITE;
	    hFileMap = CreateFileMapping(hFile, NULL,	access, 0, 0, NULL);
		  
      if (!hFileMap) {
				DWORD ler = GetLastError();
		  
				if (ler && ler != 1006) {
					sprintf(g->Message, MSG(FILE_MAP_ERROR), filename, ler);
		      CloseHandle(hFile);
				  return INVALID_HANDLE_VALUE;
				} else {
					sprintf(g->Message, MSG(FILE_IS_EMPTY), filename);
				  return hFile;
				} // endif ler
		  
        } // endif hFileMap
		  
      access = (mode == MODE_READ) ? FILE_MAP_READ : FILE_MAP_WRITE;
      mm->memory = MapViewOfFile(hFileMap, access, 0, 0, 0);
			// lenH is the high-order word of the file size
			mm->lenL = GetFileSize(hFile, &mm->lenH);
      CloseHandle(hFileMap);                    // Not used anymore
		}	else // MODE_INSERT
	    /*****************************************************************/
	    /*  The starting point must be the end of file as for append.    */
			/*****************************************************************/
	    SetFilePointer(hFile, 0, NULL, FILE_END);

  return hFile;	
	}	// end of CreateFileMap

bool CloseMemMap(LPVOID memory, size_t dwSize) 
	{
	return (memory) ? !UnmapViewOfFile(memory) : false;
	} // end of CloseMemMap

#else	/* UNIX */
// Code to handle Linux and Solaris
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

/***********************************************************************/
/*  In Insert mode, just open the file for append. Otherwise           */
/*  create the mapping file object. The map handle can be released     */
/*  immediately because they will not be used anymore.                 */
/*  If del is true in DELETE mode, then delete the whole file.         */
/*  Returns the file handle that can be used by caller.                */
/***********************************************************************/
HANDLE CreateFileMap(PGLOBAL g, LPCSTR fileName, 
										     MEMMAP *mm, MODE mode, bool del) 
	{
	unsigned int openMode;
	HANDLE       fd;
	size_t       filesize;
  struct stat  st; 

  memset(mm, 0, sizeof(MEMMAP));
	*g->Message = '\0';

  switch (mode) {
    case MODE_READ:
			openMode = O_RDONLY;
      break;
    case MODE_UPDATE:
    case MODE_DELETE:
			openMode = (del) ? (O_RDWR | O_TRUNC) : O_RDWR;
      break;
    case MODE_INSERT:
			openMode = (O_WRONLY | O_CREAT | O_APPEND);
      break;
 		default:
			sprintf(g->Message, MSG(BAD_FUNC_MODE), "CreateFileMap", mode);
			return INVALID_HANDLE_VALUE;
   } // endswitch

  // Try to open the addressed file.
	fd = open(fileName, openMode);

	if (fd != INVALID_HANDLE_VALUE && mode != MODE_INSERT) {
    /* We must know about the size of the file. */
		if (fstat(fd, &st)) {
			sprintf(g->Message, MSG(FILE_MAP_ERROR), fileName, errno);
			close(fd);
			return INVALID_HANDLE_VALUE;
			}	// endif fstat
	  
		filesize = st.st_size;
		
    // Now we are ready to load the file.  If mmap() is available we try
    //   this first.  If not available or it failed we try to load it.
		mm->memory = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
		mm->lenL = (mm->memory != 0) ? filesize : 0;
		mm->lenH = 0;
		}	/* endif fd */
	
  // mmap() call was successful. ??????????
 	return fd;
	}	// end of CreateFileMap

bool CloseMemMap(void *memory, size_t dwSize) 
	{
	return (memory) ? ((munmap(memory, dwSize)) ? true : false) : false;
	}	// end of CloseMemMap

#endif   // UNIX