// Common, groups Files and WinWrap
// Copyright Alexander Liss

#ifndef __FILEWIN_H__
#define __FILEWIN_H__

#include "kernel.h"
#include "event.h"

// blocking operations
class File: public Kernel
{
File(const File&);
File& operator=(const File&);
public:

File(
	LPCTSTR lpFileName,
	DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE,
	DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE, // A DEVICE NEEDS EXCLUSIVE = 0
	DWORD dwCreationDisposition = OPEN_EXISTING,
	DWORD dwFlagsAndAttributes= FILE_FLAG_OVERLAPPED | FILE_FLAG_RANDOM_ACCESS, // OVERLAPPED - CANOT USE BLOCKING READ AND WRITE
	LPSECURITY_ATTRIBUTES lpSA = 0,
	HANDLE  hTemplateFile = 0
	);
~File(){}

BOOL get_type(DWORD& type);

BOOL get_size(DWORD& FileSize );
BOOL get_size(ULARGE_INTEGER& FileSize );

BOOL set_pointer(
	 LONG DistanceToMove,			  // bytes to move pointer
	 DWORD dwMoveMethod = FILE_BEGIN  // starting point
	);

BOOL set_pointer(
  LARGE_INTEGER DistanceToMove,	     // bytes to move pointer
  DWORD dwMoveMethod = FILE_BEGIN    // starting point           
);


BOOL set_file_end();

BOOL current_pointer(DWORD& place);
BOOL current_pointer(ULARGE_INTEGER& place);


// only if overlapped flag is not set
BOOL read(
		DWORD& bytesActual,
		LPVOID lpBuffer,
		DWORD dwBytesLimit		
	);

// only if overlapped flag is not set
BOOL write(
		DWORD& bytesActual,
		LPVOID lpBuffer,
		DWORD dwBytesSize		
	);

BOOL flush();

BOOL lock(
  DWORD dwFileOffsetLow,          
  DWORD dwFileOffsetHigh,         
  DWORD nNumberOfBytesToLockLow,  
  DWORD nNumberOfBytesToLockHigh  
);

BOOL unlock(
  DWORD dwFileOffsetLow,          
  DWORD dwFileOffsetHigh,         
  DWORD nNumberOfBytesToLockLow,  
  DWORD nNumberOfBytesToLockHigh  
);

// calling thread only
BOOL cancel();

};

		// can be used with file, pipe, device:

	// AsyncFileOperation

class AsyncFileOperation
{
AsyncFileOperation(const AsyncFileOperation&);
AsyncFileOperation& operator=(const AsyncFileOperation&);
public:

AsyncFileOperation(){clear();}
AsyncFileOperation(Kernel& z){clear();set(z);}
virtual ~AsyncFileOperation(){}

int set(Kernel& z){handle=z.get_handle();return 0;}

int put_pointer(DWORD offset,DWORD offset_high=0)
{overlapped.Offset=offset;overlapped.OffsetHigh=offset_high;return 0;}
int get_pointer(DWORD& offset,DWORD& offset_high)
{offset=overlapped.Offset;offset_high=overlapped.OffsetHigh;return 0;}

BOOL lock(
  DWORD nNumberOfBytesToLockLow,   
  DWORD nNumberOfBytesToLockHigh, 
  DWORD dwFlags                  // lock options
);

BOOL unlock(
  DWORD nNumberOfBytesToLockLow,   
  DWORD nNumberOfBytesToLockHigh
);

BOOL get_result(DWORD& dwTransfer,BOOL bWait=TRUE);

protected:
	HANDLE handle;
	OVERLAPPED overlapped;
	void clear();
};

	// AsyncReadWrite

class AsyncReadWrite: public AsyncFileOperation
{
AsyncReadWrite(const AsyncReadWrite&);
AsyncReadWrite& operator=(const AsyncReadWrite&);
public:

AsyncReadWrite(){}
AsyncReadWrite(Kernel& z):AsyncFileOperation(z){}
AsyncReadWrite(Kernel& f, Event& e):AsyncFileOperation(f){set(e);}

// manual reset event !
int set(Event& z){overlapped.hEvent=z.get_handle();return 0;}
 
// sets event to non-signaled state at operation's start
BOOL read(DWORD& BytesActual,LPVOID lpBuffer, DWORD dwBytesLimit);

// sets event to non-signaled state at operation's start
BOOL write(DWORD& BytesActual,LPVOID lpBuffer,DWORD dwBytes);

// blocking
BOOL read_loop(DWORD& BytesActual,LPVOID lpBuffer, DWORD dwBytesLimit, 
			   DWORD timeout_milliseconds, DWORD wait_slice_milliseconds);

// blocking
BOOL write_loop(DWORD& BytesActual,LPVOID lpBuffer,DWORD dwBytes, 
			   DWORD timeout_milliseconds, DWORD wait_slice_milliseconds);

};

	// AsyncReadWriteEx

class AsyncReadWriteEx: public AsyncFileOperation
{
AsyncReadWriteEx(const AsyncReadWriteEx&);
AsyncReadWriteEx& operator=(const AsyncReadWriteEx&);
public:

AsyncReadWriteEx():completion_routine(0){}
AsyncReadWriteEx(Kernel& z):AsyncFileOperation(z),completion_routine(0){}
AsyncReadWriteEx(Kernel& f, LPOVERLAPPED_COMPLETION_ROUTINE z):
	AsyncFileOperation(f){set(z);}

int set(LPOVERLAPPED_COMPLETION_ROUTINE z){completion_routine=z;return 0;} 

// one or the other, manual reset event 
int set_data(LPVOID z){overlapped.hEvent=(HANDLE)z;return 0;}
int set(Event& z){overlapped.hEvent=z.get_handle();return 0;}

BOOL read(LPVOID lpBuffer, DWORD dwBytesLimit);
BOOL write(LPVOID lpBuffer,DWORD dwBytes);

private:
	VOID (CALLBACK* completion_routine) (DWORD dwErrorCode,DWORD dwNumberOfBytesTransfered,LPOVERLAPPED lpOverlapped);
};


#endif