#ifndef FILEBUFFER_H
#define FILEBUFFER_H

#define _LARGEFILE64_SOURCE

#include <except.h>
#include <fcntl.h>
#include <unistd.h>

#include <cstring> // memcpy

//#include <stdio.h>
#define __MODULE__ "File buffer"

class FileBuffer
{
    int _fd;
    uint8_t* _buffer;
    size_t _bufsize;
    size_t _intlimit;
    size_t _used;
public:
    FileBuffer(const char* fn, int mode=O_WRONLY | O_TRUNC | O_CREAT, 
	       int mask = 00644, size_t bufsize=131072)
    {
	if (bufsize < 0)
	    throw FATAL("Invalid argument");
	//printf("Opening %s\n", fn);
	_fd=open(fn, mode, mask);
	if (_fd < 0)
	    throw FATAL("Could not open file");
	_buffer=new uint8_t[bufsize];
	_bufsize=bufsize;
	_intlimit=bufsize-4;
	_used=0;
    }
    ~FileBuffer()
    {
	sync();
	close(_fd);
	delete _buffer;
    }
    void sync()
    {
	::write(_fd, _buffer, _used);
	_used = 0;
    }
    off_t lseek(off_t offset, int whence)
    {
//	return ::lseek(_fd, offset, whence);

	if(offset==0 && whence==SEEK_CUR)
	    return ::lseek(_fd, 0, SEEK_CUR)+_used;
	sync();
	return ::lseek(_fd, offset, whence);

    }
    ssize_t write(const void* buffer, size_t count)
    {
//	return ::write(_fd, buffer, count);
	ssize_t written=0;
	while (count)
	{
	    size_t size = (_bufsize-_used);
	    if (count < size)
		size = count;
	    memcpy((uint8_t*)_buffer+_used, buffer, size);
	    count-=size;
	    _used+=size;
	    written+=size;
	    buffer=(const uint8_t*)buffer+size;
	    if(_used==_bufsize)
		sync();
	    if((_used==0) && (count>_bufsize))
	    {
	        ::write(_fd, buffer, count);
	        written+=count;
	        break;
	    }	
	}
	return written;
    }
    void write_int(int value)
    {
//	::write(_fd, &value, 4);
	if (_used >= _intlimit)
	    sync();
	*(int*)(_buffer+_used)=value;
	_used+=4;
    }
};
#undef __MODULE__

#endif // FILEBUFFER_H
