<commit_before>#include "creader.h"
#include "../parser/cfiledecoder.h"
#include "../parser/ctextparser.h"
#include "settings/csettings.h"
#include "settings.h"
#include "assert/advanced_assert.h"

#include <math.h>

#include <algorithm>
#include <map>
#include <iterator>

CReader::CReader(ReaderInterface* interface) : _interface(interface)
{
	assert_r(_interface);

	_readingTimer.setSingleShot(true);
	QObject::connect(&_readingTimer, &QTimer::timeout, [this](){
		readNextFragment();
	});

	_speedWpm = CSettings().value(READER_READING_SPEED_SETTING, READER_READING_SPEED_DEFAULT).toUInt();
}

void CReader::load(const std::vector<TextFragment>& textFragments)
{
	resetAndStop();

	_textFragments.clear();
	std::transform(textFragments.cbegin(), textFragments.cend(), std::back_inserter(_textFragments), [this](const TextFragment& fragment) -> TextFragmentWithPause {
		return TextFragmentWithPause{fragment, 0};
	});

	updatePauseValues();
}

bool CReader::loadFromFile(const QString& filePath)
{
	CTextParser parser;
	parser.setAddEmptyFragmentAfterSentence(_clearScreenAfterSentenceEnd);
	load(parser.parse(CFileDecoder::readDataAndDecodeText(filePath)));

	if (!_textFragments.empty())
	{
		_filePath = filePath;
		return true;
	}
	else
		return false;
}

void CReader::setClearScreenAfterSentenceEnd(bool clear)
{
	_clearScreenAfterSentenceEnd = clear;
}

void CReader::setLongWordPauseScaling(unsigned lengthThreshold, float scaleFactor)
{
	if (lengthThreshold != _longWordThreshold || scaleFactor != _longWordDelayScaleFactor)
	{
		_longWordThreshold = lengthThreshold;
		_longWordDelayScaleFactor = scaleFactor;

		updatePauseValues();
	}
}

CReader::State CReader::state() const
{
	return _state;
}

QString CReader::filePath() const
{
	return _filePath;
}

size_t CReader::position() const
{
	return _position;
}

long double CReader::progress() const
{
	const size_t numWords = _textFragments.size();
	return numWords ? _position / (long double)numWords : 0.0;
}

size_t CReader::timeRemainingSeconds() const
{
	//const float basePausePerWordSeconds = 60.0f / _speedWpm;
	//const float theoreticalSeconds = (_textFragments.size() - _position) * basePausePerWordSeconds;
	const float actualSeconds = std::accumulate(_textFragments.cbegin() + _position, _textFragments.cend(), 0.0f, [](float acc, const TextFragmentWithPause& fragment) {
		return acc + fragment._pauseAfter / 1000.0f;
	});

	//const size_t actualWPM = (size_t)(60 * _textFragments.size() / actualSeconds);

	return (size_t)ceilf(actualSeconds);
}

void CReader::updateInterface() const
{
	_interface->stateChanged(_state);
	_interface->updateDisplay(_position);
}

size_t CReader::totalNumWords() const
{
	return _textFragments.size();
}

void CReader::resumeReading()
{
	_state = Reading;
	_interface->stateChanged(_state);
	readNextFragment();
}

void CReader::pauseReading()
{
	_readingTimer.stop();

	_state = Paused;
	_interface->stateChanged(_state);
}

void CReader::togglePause()
{
	if (_state == Reading)
		pauseReading();
	else
		resumeReading();
}

void CReader::resetAndStop()
{
	pauseReading();
	_position = 0;
	_interface->updateInfo();
}

void CReader::goToWord(size_t wordIndex)
{<commit_msg>Index validation added to CReader::goToWord<commit_after>#include "creader.h"
#include "../parser/cfiledecoder.h"
#include "../parser/ctextparser.h"
#include "settings/csettings.h"
#include "settings.h"
#include "assert/advanced_assert.h"

#include <math.h>

#include <algorithm>
#include <map>
#include <iterator>

DISABLE_COMPILER_WARNINGS
#include <QDebug>
#include <QTime>
RESTORE_COMPILER_WARNINGS

CReader::CReader(ReaderInterface* interface) : _interface(interface)
{
	assert_r(_interface);

	_readingTimer.setSingleShot(true);
	QObject::connect(&_readingTimer, &QTimer::timeout, [this](){
		readNextFragment();
	});

	_speedWpm = CSettings().value(READER_READING_SPEED_SETTING, READER_READING_SPEED_DEFAULT).toUInt();
}

void CReader::load(const std::vector<TextFragment>& textFragments)
{
	resetAndStop();

	_textFragments.clear();
	std::transform(textFragments.cbegin(), textFragments.cend(), std::back_inserter(_textFragments), [this](const TextFragment& fragment) -> TextFragmentWithPause {
		return TextFragmentWithPause{fragment, 0};
	});

	updatePauseValues();
}

bool CReader::loadFromFile(const QString& filePath)
{
	CTextParser parser;
	parser.setAddEmptyFragmentAfterSentence(_clearScreenAfterSentenceEnd);

	QTime timer;
	timer.start();
	load(parser.parse(CFileDecoder::readDataAndDecodeText(filePath)));
	qDebug() << "Parsing" << filePath << "took" << QString::number(timer.elapsed() / 1000.0f, 'f', 1) << "seconds";

	if (!_textFragments.empty())
	{
		_filePath = filePath;
		return true;
	}
	else
		return false;
}

void CReader::setClearScreenAfterSentenceEnd(bool clear)
{
	_clearScreenAfterSentenceEnd = clear;
}

void CReader::setLongWordPauseScaling(unsigned lengthThreshold, float scaleFactor)
{
	if (lengthThreshold != _longWordThreshold || scaleFactor != _longWordDelayScaleFactor)
	{
		_longWordThreshold = lengthThreshold;
		_longWordDelayScaleFactor = scaleFactor;

		updatePauseValues();
	}
}

CReader::State CReader::state() const
{
	return _state;
}

QString CReader::filePath() const
{
	return _filePath;
}

size_t CReader::position() const
{
	return _position;
}

long double CReader::progress() const
{
	const size_t numWords = _textFragments.size();
	return numWords ? _position / (long double)numWords : 0.0;
}

size_t CReader::timeRemainingSeconds() const
{
	//const float basePausePerWordSeconds = 60.0f / _speedWpm;
	//const float theoreticalSeconds = (_textFragments.size() - _position) * basePausePerWordSeconds;
	const float actualSeconds = std::accumulate(_textFragments.cbegin() + _position, _textFragments.cend(), 0.0f, [](float acc, const TextFragmentWithPause& fragment) {
		return acc + fragment._pauseAfter / 1000.0f;
	});

	//const size_t actualWPM = (size_t)(60 * _textFragments.size() / actualSeconds);

	return (size_t)ceilf(actualSeconds);
}

void CReader::updateInterface() const
{
	_interface->stateChanged(_state);
	_interface->updateDisplay(_position);
}

size_t CReader::totalNumWords() const
{
	return _textFragments.size();
}

void CReader::resumeReading()
{
	_state = Reading;
	_interface->stateChanged(_state);
	readNextFragment();
}

void CReader::pauseReading()
{
	_readingTimer.stop();

	_state = Paused;
	_interface->stateChanged(_state);
}

void CReader::togglePause()
{
	if (_state == Reading)
		pauseReading();
	else
		resumeReading();
}

void CReader::resetAndStop()
{
	pauseReading();
	_position = 0;
	_interface->updateInfo();
}

void CReader::goToWord(size_t wordIndex)
{
	if (_position >= _textFragments.size())
		return;

{'fraction_non_alphanumeric': 0.13463837417812313, 'fraction_numerical': 0.005678421996413628, 'mean_word_length': 6.640410958904109, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5864761', 'n_tokens_mistral': 2364, 'n_tokens_neox': 2273, 'n_words': 410}