FileReaderASCII.cc 8.22 KB
/*
 * FileReaderASCII.cc
 *
 *  Created on: Nov 24, 2014
 *  Author: AKKA
 */

#include <boost/algorithm/string/trim_all.hpp>
#include <boost/algorithm/string.hpp>

#include "FileReaderASCII.hh"
#include "TimeUtil.hh"

namespace AMDA {
namespace LocalFileInterface {

// 32 KB is the maximum supported line size
int FileReaderASCII::MaxLineSize = 32 * 1024;

std::string FileReaderASCII::ClbKey = "CALIB_INFO";

FileReaderASCII::FileReaderASCII() : _asciiStream()
{
}

FileReaderASCII::~FileReaderASCII()
{
}

bool FileReaderASCII::open(std::string filePath)
{
	if (isOpened())
	{
		LOG4CXX_ERROR(gLogger, "FileReaderASCII::open - A file is already opened");
		return false;
	}
	// Open ascii stream
	_asciiStream.open (filePath, std::ios::in);

	return (_asciiStream.is_open());
}

bool FileReaderASCII::close(void)
{
	if (isOpened())
	{
		_asciiStream.close();
	}

	return (_asciiStream.is_open() == false);
}

bool FileReaderASCII::isOpened(void)
{
	return (_asciiStream.is_open());
}

std::string FileReaderASCII::getTimeParamId(void)
{
	LOG4CXX_DEBUG(gLogger, "FileReaderASCII::getTimeParamId");

	// Time parameter id is always at the first position in text files
	return std::string("0");
}

/*
 * @brief Split line
 */
bool FileReaderASCII::split (const char *line, std::vector<std::string> &lineFields)
{
	std::string sLine(line);

	// Remove all spaces in the given string (even multiple spaces between fields)
	boost::algorithm::trim_all(sLine);

	if ((sLine.find(" ") != std::string::npos) ||
	    (sLine.find("\t") != std::string::npos)) {

		boost::split(lineFields,sLine,boost::is_any_of(" \t"));

		return true;

	}

	return (false);
}

bool FileReaderASCII::getParamInfo(std::string& /*paramId*/, LocalParamType& /*paramType*/, int& /*dim1Size*/, int& /*dim2Size*/)
{
	LOG4CXX_DEBUG(gLogger, "FileReaderASCII::getParamInfo");

	// Parameter types and size can't be determined by the reader
	return true;
}

int FileReaderASCII::getRecordIndex(std::string& /*timeId*/, double time)
{
	LOG4CXX_DEBUG(gLogger, "FileReaderASCII::getRecordIndex");

	char line [MaxLineSize];
	int lineCount = 0;

	// Set current stream position at the beginning of the file
	_asciiStream.seekg (0, _asciiStream.beg);

	while(_asciiStream.eof() == false) {
		if (_asciiStream.getline (line, MaxLineSize)) {
			// Comments in the file are not considered
			if (line [0] != '#') {
				std::vector<std::string> lineFields;
				if (split (line, lineFields))
				{
					if (!lineFields.empty())
						if (getTime(lineFields[0]) >= time)
							return (lineCount);
				}
				lineCount++;
			}
		}
		else if (_asciiStream.rdstate() == std::ios_base::failbit) {
			LOG4CXX_ERROR(gLogger, "FileReaderASCII::getRecordIndex - Error reading line content, maxSize is " << MaxLineSize);
			return -1;
		}
	}

	LOG4CXX_ERROR(gLogger, "FileReaderASCII::FileReaderASCII - Cannot get record index");
	return -1;
}

FileReaderStatus FileReaderASCII::getParamPacketData(std::string& /*timeId*/, std::string& paramId,
		int recordIndex, double stopTime, LocalParamDataPacket *packet)
{
	LOG4CXX_DEBUG(gLogger, "FileReaderASCII::getParamPacketData - " << recordIndex);

	char line [MaxLineSize];
	int lineCount = 0;
	int colStart = std::stoi(paramId);
	int colStop = colStart + packet->getDimsSize();
	bool packetFull;
	double crtTime;

	float 	*dataFloat = NULL;
	double 	*dataDouble = NULL;
	short 	*dataShort = NULL;
	int		*dataInt = NULL;
	void 	*data;

	if ((packet->getType() != TYPE_FLOAT) &&
		(packet->getType() != TYPE_DOUBLE) &&
		(packet->getType() != TYPE_SHORT) &&
		(packet->getType() != TYPE_INT)	) {
		LOG4CXX_ERROR(gLogger, "FileReaderASCII::getParamPacketData - Not supported packet type");
		return FRS_ERROR;
	}

	if (packet->getType() == TYPE_FLOAT) {
		dataFloat = new float [packet->getDimsSize()];
		data = dataFloat;
	}
	else if (packet->getType() == TYPE_DOUBLE) {
		dataDouble = new double [packet->getDimsSize()];
		data = dataDouble;
	}
	else if (packet->getType() == TYPE_SHORT) {
		dataShort = new short [packet->getDimsSize()];
		data = dataShort;
	}
	else if (packet->getType() == TYPE_INT) {
		dataInt = new int [packet->getDimsSize()];
		data = dataInt;
	}

	// Set current stream position at the beginning of the file
	_asciiStream.seekg (0, _asciiStream.beg);

	while (_asciiStream.getline (line, MaxLineSize)) {
		// Comments in the file are not considered
		if (line [0] == '#')
			continue;

		lineCount++;

		// recordIndex reached ?
		if (lineCount <= recordIndex)
			continue;

		//split line
		std::vector<std::string> lineFields;
		if (split (line, lineFields) && !lineFields.empty())
		{
			crtTime = getTime(lineFields[0]);

			// stopTime overtaken ?
			if (crtTime > stopTime) {
				if (dataFloat != NULL)
					delete [] dataFloat;
				if (dataDouble != NULL)
					delete [] dataDouble;
				if (dataShort != NULL)
					delete [] dataShort;
				if (dataInt != NULL)
					delete [] dataInt;
				return FRS_FINISH;
			}

			// Extract values on the line depending on their type
			for (int col=colStart; col<colStop; col++) {
				if (col < (int)lineFields.size()) {
					if (packet->getType() == TYPE_FLOAT)
						dataFloat [col-colStart] = std::stof (lineFields[col]);
					else if (packet->getType() == TYPE_DOUBLE)
						dataDouble [col-colStart] = std::stod (lineFields[col]);
					else if (packet->getType() == TYPE_SHORT)
						dataShort [col-colStart] = (short) std::stof (lineFields[col]);
					else if (packet->getType() == TYPE_INT)
						dataInt [col-colStart] = std::stoi (lineFields[col]);
				} else {
					LOG4CXX_ERROR(gLogger, "FileReaderASCII::getParamPacketData - Error retrieving column " << col);
					if (dataFloat != NULL)
						delete [] dataFloat;
					if (dataDouble != NULL)
						delete [] dataDouble;
					if (dataShort != NULL)
						delete [] dataShort;
					if (dataInt != NULL)
						delete [] dataInt;
					return FRS_ERROR;
				}
			}

			//add data record in the packet
			if (!packet->addData(crtTime, data, packetFull))
			{
				if (dataFloat != NULL)
					delete [] dataFloat;
				if (dataDouble != NULL)
					delete [] dataDouble;
				if (dataShort != NULL)
					delete [] dataShort;
				if (dataInt != NULL)
					delete [] dataInt;
				if (packetFull)
					return FRS_MORE;
				LOG4CXX_ERROR(gLogger, "FileReaderASCII::getParamPacketData - Error to add data in packet");
				return FRS_ERROR;
			}
		} else {
			LOG4CXX_ERROR(gLogger, "FileReaderASCII::getParamPacketData - Error retrieving time on line " << lineCount);
			if (dataFloat != NULL)
				delete [] dataFloat;
			if (dataDouble != NULL)
				delete [] dataDouble;
			if (dataShort != NULL)
				delete [] dataShort;
			if (dataInt != NULL)
				delete [] dataInt;
			return  FRS_ERROR;
		}
	}

	if (dataFloat != NULL)
		delete [] dataFloat;
	if (dataDouble != NULL)
		delete [] dataDouble;
	if (dataShort != NULL)
		delete [] dataShort;
	if (dataInt != NULL)
		delete [] dataInt;
	return FRS_EOF;
}

/*
 * @brief Get an information
 */
bool FileReaderASCII::getInfo(const char* pInfoName, std::vector<double>& res)
{
	res.clear();

	// Set current stream position at the beginning of the file
	_asciiStream.seekg (0, _asciiStream.beg);

	char line [MaxLineSize];
	while (_asciiStream.getline (line, MaxLineSize)) {
		std::string lineStr = std::string(line);
		boost::algorithm::trim_all(lineStr);
		if (lineStr[0] != '#')
			continue;
		lineStr = lineStr.substr(1,lineStr.size()-1);
		boost::algorithm::trim_all(lineStr);
		if (!boost::starts_with(lineStr, FileReaderASCII::ClbKey))
			continue;
		lineStr = lineStr.substr(FileReaderASCII::ClbKey.size(),lineStr.size()-FileReaderASCII::ClbKey.size());
		std::vector<std::string> lineValues;
		boost::split(lineValues,lineStr,boost::is_any_of(","));
		if (lineValues.empty())
			continue;
		for (auto &value : lineValues)
			boost::algorithm::trim_all(value);
		if (lineValues[0].compare(pInfoName) != 0)
			continue;

		for (int i = 1; i < (int)lineValues.size(); ++i)
			res.push_back(std::stof(lineValues[i]));
		return true;
	}

	return false;
}

double FileReaderASCII::getTime(std::string& timeString) {
	switch (_timeFormat)
	{
		case LocalTimeFormat::DOUBLE :
			return std::stod(timeString);
		case LocalTimeFormat::ISO :
			return TimeUtil::readTimeInIso((char*)timeString.c_str());
		default:
			LOG4CXX_WARN(gLogger, "FileReaderASCII::getTime - Time format not implemented");
			return 0.;
	}
}

} /* LocalFileInterface */
} /* AMDA */