/*
 * QrfeRingFile.cpp
 *
 *  Created on: 06.06.2011
 *      Author: stefan.detter
 */

#include "QrfeRingFile.h"

#include <QFile>
#include <QDir>
#include <QMutexLocker>

QrfeRingFile::QrfeRingFile ( const QString & path, const QString & prefix, const QString & fileType, const uint & fileCount, const uint & maxSize, QObject * parent )
	: QIODevice(parent)
	, m_path(path)
	, m_prefix(prefix)
	, m_fileType(fileType)
	, m_fileCount( (fileCount>0)?fileCount:1 )
	, m_maxSize( (maxSize>0)?maxSize:1 )
{
	m_file = 0;
	m_currentFileNr = 1;
	m_append = true;
	m_risingNumber = false;

	m_file = new QFile( this );
}

QrfeRingFile::~QrfeRingFile()
{
	if(QIODevice::isOpen())
		close();

	if(m_file)
		delete m_file;
}


const QString& QrfeRingFile::path() const
{
	return m_path;
}

bool QrfeRingFile::setPath(const QString& path)
{
	if(m_path == path)
		return true;

	if(!QDir(path).exists())
	{
		return false;
	}

	if(isOpen())
	{
		close();
		m_path = path;
		return open(QIODevice::openMode());
	}
	m_path = path;
	return true;
}

const QString& QrfeRingFile::prefix() const
{
	return m_prefix;
}

bool QrfeRingFile::setPrefix(const QString& prefix)
{
	if(m_prefix == prefix)
		return true;

	if(isOpen())
	{
		close();
		m_prefix = prefix;
		return open(QIODevice::openMode());
	}

	m_prefix = prefix;
	return true;
}

const QString& QrfeRingFile::fileType() const
{
	return m_fileType;
}

bool QrfeRingFile::setFileType(const QString& fileType)
{
	if(fileType == m_fileType)
		return true;

	if(isOpen())
	{
		close();
		m_fileType = fileType;
		return open(QIODevice::openMode());
	}

	m_fileType = fileType;
	return true;
}

const uint& QrfeRingFile::fileCount() const
{
	return m_fileCount;
}

void QrfeRingFile::setFileCount(const uint& fileCount)
{
	m_fileCount = fileCount;
}

const uint& QrfeRingFile::maxSize() const
{
	return m_maxSize;
}

void QrfeRingFile::setMaxSize(const uint& maxSize)
{
	m_maxSize = maxSize;
}

const bool QrfeRingFile::append() const
{
	return m_append;
}

void QrfeRingFile::setAppend(const bool append)
{
	m_append = append;
}

const bool QrfeRingFile::risingNumber() const
{
	return m_risingNumber;
}

void QrfeRingFile::setRisingNumber(const bool risingNumber)
{
	m_risingNumber = risingNumber;
}


void QrfeRingFile::writeAsciiString ( const QString & str )
{
    write(str.toLatin1());
}


bool QrfeRingFile::open( OpenMode mode )
{
	QMutexLocker lock(&m_mutex);

	mode = ( mode & (~0x0F) ) | QIODevice::WriteOnly;
	if(m_append)
	{
		m_currentFileNr = getLastUsedFileNumber();
		mode |= QIODevice::Append;
	}
	else
	{
		m_currentFileNr = 1;
		mode |= QIODevice::Truncate;
	}

	m_file->setFileName(generateFilePathName(m_currentFileNr));

	if(m_file->open(mode))
	{
		QIODevice::open(mode);
		return true;
	}
	else
		return false;
}

void QrfeRingFile::close ()
{
	QMutexLocker lock(&m_mutex);

	m_file->close();
    QIODevice::close();
}

bool QrfeRingFile::flush()
{
    QMutexLocker lock(&m_mutex);
    return m_file->flush();
}

qint64 QrfeRingFile::writeData ( const char * data, qint64 len )
{
	QMutexLocker lock(&m_mutex);

	if (m_file->size() >= m_maxSize)
	{
		m_file->close();
		m_file->setFileName( getNextFileName() );

		OpenMode mode = QIODevice::openMode();
		mode = ( mode & (~0x0F) );
		mode |= QIODevice::WriteOnly;
		mode |= QIODevice::Truncate;
		m_file->open(mode);
	}
	return m_file->write(data, len);
}

qint64 QrfeRingFile::readData ( char * /*data*/, qint64 /*len*/ )
{
	return -1;
}


const QString QrfeRingFile::generateFileName ( uint fileNr ) const
{
	return QString("%1%2.%3").arg(m_prefix).arg(fileNr).arg(m_fileType);
}

const QString QrfeRingFile::generateFilePathName ( uint fileNr ) const
{
	return QString("%1%2%3").arg(m_path).arg(QDir::separator()).arg(generateFileName(fileNr));
}

const uint QrfeRingFile::getLastUsedFileNumber() const
{
	QDir dir(m_path);
	QStringList files = dir.entryList(QStringList() << QString("%1*.%2").arg(m_prefix).arg(m_fileType), QDir::NoFilter, QDir::Name);

	uint nextFileNr = 0;
	foreach(QString fileName, files)
	{
		QString nr = fileName.remove(m_prefix);
		nr = nr.remove("." + m_fileType);

		bool ok = false;
		uint id = nr.toUInt(&ok, 10);

		if(!ok){
			continue;
		}

		if(id > nextFileNr)
		{
			nextFileNr = id;
		}
	}

	if(nextFileNr == 0)
		return 1;
	else
		return nextFileNr;
}

const QString QrfeRingFile::getNextFileName ( )
{
	if(m_risingNumber)
	{
		++m_currentFileNr;
		QDir dir(m_path);
		dir.remove(generateFileName(m_currentFileNr - m_fileCount));
	}
	else
	{
		if (++m_currentFileNr > m_fileCount)
			m_currentFileNr = 1;
	}

	return generateFilePathName(m_currentFileNr);
}


