//
// This file is part of the aMule Project.
//
// Copyright (c) 2008-2011 aMule Team ( admin@amule.org / http://www.amule.org )
// Copyright (c) 2008-2011 Stu Redman ( sturedman@amule.org )
//
// Any parts of this program derived from the xMule, lMule or eMule project,
// or contributed by third-party developers are copyrighted by their
// respective authors.
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
//

#include "FileAutoClose.h"
#include "GetTickCount.h"	// for TheTime
#include "Logger.h"			// Needed for AddDebugLogLineN


static const uint32 ReleaseTime = 600;	// close file after 10 minutes of not being used

CFileAutoClose::CFileAutoClose()
	: m_mode(CFile::read),
	  m_autoClosed(false),
	  m_locked(0),
	  m_size(0),
	  m_lastAccess(TheTime)
{}

CFileAutoClose::CFileAutoClose(const CPath& path, CFile::OpenMode mode)
{
	Open(path, mode);
}

bool CFileAutoClose::Open(const CPath& path, CFile::OpenMode mode)
{
	m_mode = mode;
	m_autoClosed = false;
	m_locked = 0;
	m_size = 0;
	m_lastAccess = TheTime;
	return m_file.Open(path, mode);
}

bool CFileAutoClose::Create(const CPath& path, bool overwrite)
{
	m_mode = CFile::write;
	m_autoClosed = false;
	m_lastAccess = TheTime;
	return m_file.Create(path, overwrite);
}

bool CFileAutoClose::Close()
{
	bool state = m_autoClosed ? true : m_file.Close();
	m_autoClosed = false;
	return state;
}

uint64 CFileAutoClose::GetLength() const
{
	return m_autoClosed ? m_size : m_file.GetLength();
}

bool CFileAutoClose::SetLength(uint64 newLength)
{
	Reopen();
	return m_file.SetLength(newLength);
}

const CPath& CFileAutoClose::GetFilePath() const
{
	return m_file.GetFilePath();
}

bool CFileAutoClose::IsOpened() const
{
	return m_autoClosed || m_file.IsOpened();
}

void CFileAutoClose::ReadAt(void* buffer, uint64 offset, size_t count)
{
	Reopen();
	m_file.Seek(offset);
	m_file.Read(buffer, count);
}

void CFileAutoClose::WriteAt(const void* buffer, uint64 offset, size_t count)
{
	Reopen();
	m_file.Seek(offset);
	m_file.Write(buffer, count);
}

bool CFileAutoClose::Eof()
{
	Reopen();
	return m_file.Eof();
}

int CFileAutoClose::fd()
{
	Reopen();
	m_locked++;
	return m_file.fd();
}

void CFileAutoClose::Unlock()
{
	if (m_locked) {
		m_locked--;
	}
}

void CFileAutoClose::Reopen()
{
	if (m_autoClosed) {
		AddDebugLogLineN(logCFile, wxT("Reopen AutoClosed file ") + GetFilePath().GetPrintable());
		m_file.Reopen(m_mode); // throws on failure
		// On open error m_autoClosed stays true, so if the app tries again
		// it opens and throws again.
		// Otherwise it would assert on an operation on a closed file and probably die.
		m_autoClosed = false;
	}
	m_lastAccess = TheTime;
}

bool CFileAutoClose::Release(bool now)
{
	if (!m_autoClosed
			&& (now || TheTime - m_lastAccess >= ReleaseTime)
			&& !m_locked
			&& m_file.IsOpened()) {
		m_autoClosed = true;
		m_size = m_file.GetLength();
		m_file.Close();
		AddDebugLogLineN(logCFile, wxT("AutoClosed file ") + GetFilePath().GetPrintable()
			+ (now ? wxT("(immediately)") : wxT("(timed)")));
	}
	return m_autoClosed;
}

// File_checked_for_headers
