/**
 * \file file.cpp Implementation of portable File class
 *
 *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

// File class
// ----------

File::File() {
#ifdef WIN32
	m_impl.reset(new FileImplWin());
#else
	m_impl.reset(new FileImplPosix());
#endif
}

File::File(const std::string &name) {
#ifdef WIN32
	m_impl.reset(new FileImplWin(name));
#else
	m_impl.reset(new FileImplPosix(name));
#endif
}

File::~File() {}

void File::open(const std::string &name) {
	m_impl->open(name);
}
void File::close() {
	m_impl->close();
}
void File::seek(uint64_t offset) {
	m_impl->seek(offset);
}
std::string File::read(uint64_t len) {
	return m_impl->read(len);
}
std::string File::read(uint64_t offset, uint64_t len) {
	return m_impl->read(offset, len);
}
void File::write(const std::string &data) {
	m_impl->write(data);
}
void File::write(uint64_t offset, const std::string &data) {
	m_impl->write(offset, data);
}

// FileImplBase class
// ------------------
FileImplBase::FileImplBase() {}
FileImplBase::FileImplBase(const std::string &name) {}
FileImplBase::~FileImplBase() {}

// FileImplWin class
// -----------------
FileImplWin::FileImplWin() : m_fd() {}
FileImplWin::FileImplWin(const std::string &name) : m_fd() {
	open(name);
}
FileImplWin::~FileImplWin() {
	if (m_fd) {
		close();
	}
}
void FileImplWin::open(const std::string &name, OpenFlags flags) {
	_open(name.c_str(), flags);
}
void FileImplWin::close() {
	if (m_fd) {
		_close(m_fd);
		m_fd = 0;
	}
}
void FileImplWin::seek(uint64_t offset) {
	_lseeki64(m_fd, offset, SEEK_SET);
}
std::string FileImplWin::read(uint64_t len) {
	CHECK_THROW(m_fd);

	boost::scoped_array<char> buf(new char[len]);
	int ret = _read(m_fd, buf.get(), len);
	CHECK_THROW(ret);
	return std::string(buf.get(), ret)
}
std::string FileImplWin::read(uint64_t offset, uint64_t len) {
	seek(offset);
	return read(len);
}
void FileImplWin::write(const std::string &data) {
	CHECK_THROW(m_fd);
	int ret = _write(m_fd, data.data(), data.size());
	CHECK_THROW(ret == data.size());
}
void FileImplWin::write(uint64_t offset, const std::string &data) {
	seek(offset);
	write(data);
}

// FileImplPosix class
// -------------------
FileImplPosix::FileImplPosix() : m_fd() {}
FileImplPosix::FileImplPosix(const std::string &name) : m_fd() {
	open(name);
}
FileImplPosix::~FileImplPosix() {
	if (m_fd) {
		close();
	}
}
void FileImplPosix::open(const std::string &name, OpenFlags flags) {
	::open(name.c_str(), flags);
}
void FileImplPosix::close() {
	if (m_fd) {
		::close(m_fd);
		m_fd = 0;
	}
}
void FileImplPosix::seek(uint64_t offset) {
	::lseek64(m_fd, offset, SEEK_SET);
}
std::string FileImplPosix::read(uint64_t len) {
	CHECK_THROW(m_fd);

	boost::scoped_array<char> buf(new char[len]);
	int ret = ::read(m_fd, buf.get(), len);
	CHECK_THROW(ret);
	return std::string(buf.get(), ret)
}
std::string FileImplPosix::read(uint64_t offset, uint64_t len) {
	seek(offset);
	return read(len);
}
void FileImplPosix::write(const std::string &data) {
	CHECK_THROW(m_fd);
	int ret = ::write(m_fd, data.data(), data.size());
	CHECK_THROW(ret == data.size());
}
void FileImplPosix::write(uint64_t offset, const std::string &data) {
	seek(offset);
	write(data);
}