AsciiReader.cc 7.25 KB
/*
 * AsciiReader.cc
 *
 *  Created on: 5 août 2013
 *      Author: CS
 */

#include "Catalog.hh"
#include "AsciiData.hh"
#include "AsciiReader.hh"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp>
#include <fstream>
#include "TimeTableCatalogUtil.hh"
#include <algorithm>
#include <cctype>

namespace TimeTableCatalog {

const std::string AsciiReader::FORMAT = "ASCII";

AsciiReader::AsciiReader(const std::string& pPath) :
		AbstractReader(pPath), timeSize(0) {

}

AsciiReader::~AsciiReader() {

}

// ----------------- PUBLIC --------------------------

/**
 * Checks the TT format to know if the reader is the good one.
 */
bool AsciiReader::canRead(const std::string& pPath){
	std::string tmpPath(pPath);
	std::transform(tmpPath.begin(), tmpPath.end(), tmpPath.begin(), ::tolower);
	return boost::algorithm::ends_with(tmpPath, ".txt");
}

void AsciiReader::read(TimeTable& ptt) {
	std::ifstream ttfile(getLocalPath(), std::ios::in);

	// -- open file
	if (ttfile) {
		std::string line;
		// -- read line
		int crtIndex = 0;
		while (getline(ttfile, line)) {
			boost::algorithm::trim(line);
			if (boost::starts_with(line, "#")) {
				// -- it is a metadata
				readMetadata(line, ptt);
			} else {
				// -- add it to TimeTable
				if (line.empty()) {
					continue;
				}
				ptt.addInterval(*readInterval(line, ptt,crtIndex));
				++crtIndex;
			}
		}
		// -- close file
		ttfile.close();
	} else {
		LOG4CXX_INFO(_logger,
				"TimeTable file Not Found or unreadable (" + getPath() + ")");
	}
}

std::unique_ptr<AbstractReader> AsciiReader::createInstance(
		const std::string& pPath) {
	return std::unique_ptr < AbstractReader > (new AsciiReader(pPath));
}

// ----------------- PRIVATE --------------------------

std::unique_ptr<TimeInterval> AsciiReader::readInterval(
		const std::string& pline, TimeTable& pTT, int pcrtIndex) {
	// set date time format if not set (on first interval)
	if (pTT._timeFormat == TimeTable::TIME_FORMAT::UNKNOWN) {
		pTT._timeFormat = getTimeFormat(pline, this->timeSize);
		if (pTT._timeFormat == TimeTable::TIME_FORMAT::UNKNOWN) {
			std::unique_ptr <TimeInterval> ti (new TimeInterval(0, 0, pcrtIndex));
		}
	}

	std::string line = pline;
	boost::algorithm::trim(line);
	// read start time
	double startTime = readISOTime(line, pTT._timeFormat);
	line.erase(0, this->timeSize);
	boost::algorithm::trim(line);

	// read stop time
	double stopTime = readISOTime(line, pTT._timeFormat);
	line.erase(0, this->timeSize);
	boost::algorithm::trim(line);

	// -- create time interval
	std::unique_ptr <TimeInterval> ti (new TimeInterval(startTime, stopTime, pcrtIndex));

	std::vector<std::string> params;
	split(line, AsciiData::SEPARATOR.c_str()[0], params);

	// If parameters value found, set them for the interval
	if (!params.empty()) {
		// Starts setting parameter values with the third field of the
		// intervalFields vector (The first and second one are strat and stop dates)
		ParameterDescriptionList pdl = pTT.getParameterDescritptions();

		std::vector<std::string> paremeterValues;

		int paramPos = 0;
		for (auto parameterDesc : pdl) {
			paremeterValues.clear();
			for (int paramIdx=0; paramIdx< parameterDesc.getSizeAsInt(); paramIdx++) {
				if (paramPos < (int)params.size()) {
					paremeterValues.push_back(params[paramPos]);
					++paramPos;
				}
			}
			ti->addParameterData(parameterDesc.getId(), paremeterValues);
		}
	}

	return ti;
}

void AsciiReader::readMetadata(const std::string& pline,
		TimeTable& ptimeTable) {
	// try to find string like "Prop:xxxx" and set _prop attribute to "xxxx"

	// -- here try to find "Name:"
	if (contains(pline, AsciiData::NAME_KEYWORD, "#")) {
		extractvalue(pline, ptimeTable._name);
	}
	// -- here try to find "Historic:"
	else if (contains(pline, AsciiData::HISTORIC_KEYWORD, "#")) {
		extractvalue(pline, ptimeTable._history);
	}
	// -- here try to find "CreationDate:"
	// and try to set it as unix time
	// if impossible, add the line to the description
	else if (contains(pline, AsciiData::CREATION_DATE_KEYWORD, "#")) {
		// convert creation date string to char*
		std::string creationDate;
		extractvalue(pline, creationDate);
		// try to read date
		try {
			ptimeTable._creationDate = TimeTableCatalog::readISOTime(creationDate);
		} catch (...) {
			addDescription(pline, ptimeTable);
		}

	} // -- every other lines are added to description field*/
	// -- here try to find "Parameter NN :"
	else if (contains(pline, AsciiData::PARAMETER_KEYWORD, "#")) {
		addParameter(pline, ptimeTable);
	}
	// -- here try to find "CreationDate:"
	// and try to set it as unix time
	// if impossible, add the line to the description
	else {
		addDescription(pline, ptimeTable);
	}

}

void AsciiReader::addDescription(const std::string & pline, TimeTable& ptt) {
	// get value after "#"
	std::string value = pline.substr(1);
	// remove ; character at the end of the line
	boost::algorithm::replace_last(value, ";", "");
	ptt._description.push_back(value);
}

void AsciiReader::addParameter(const std::string & pline, TimeTable& ptt) {
	// get value after "Parameter NN:"
	size_t pos = pline.find(": ");
	if (pos!=std::string::npos) {
		// Extract parameter informations (after ": ")
		std::string paramLine = pline.substr(pos+2);

		// remove ; character at the end of the line
		boost::algorithm::replace_last(paramLine, ";", "");

		ParameterDescription pd;

		// Split line using coma separator
		std::stringstream ss(paramLine);
		std::string paramField;
		while (std::getline(ss, paramField, ';')) {

			boost::algorithm::trim(paramField);
			std::vector<std::string> fields;
			boost::split(fields,paramField,boost::is_any_of(":"));

			std::string value = "";
			if (fields.size() > 1) {
				std::vector<std::string> values(fields.begin()+1, fields.end());
				value = boost::algorithm::join(values, ":");
			}

			// Depending on the fiield [0] value, sets the corresponding parameter attribute
			if (fields [0] == AsciiData::ATTRIB_ID) {
				pd.setId(value);
			}
			if (fields [0] == AsciiData::ATTRIB_NAME) {
				pd.setName(value);
			}
			else if (fields [0] == AsciiData::ATTRIB_SIZE) {
				pd.setSize(value);
			}
			else if (fields [0] == AsciiData::ATTRIB_TYPE) {
				pd.setType(getTypeFromString(value));
			}
			else if (fields [0] == AsciiData::ATTRIB_UNIT) {
				pd.setUnit(value);
			}
			else if (fields [0] == AsciiData::ATTRIB_DESCRITION) {
				pd.setDescription(value);
			}
			else if (fields [0] == AsciiData::ATTRIB_UCD) {
				pd.setUcd(value);
			}
			else if (fields [0] == AsciiData::ATTRIB_UTYPE) {
				pd.setUtype(value);
			}
		}

		((Catalog *) &ptt)->addParameterDescription(pd);
	}
}

ParameterDescription::ParameterType AsciiReader::getTypeFromString(std::string type) {
	boost::algorithm::trim(type);
	boost::algorithm::to_lower(type);

	if ((type.compare("string") == 0) || (type.compare("char") == 0)) {
		return ParameterDescription::ParameterType::String;
	}
	else if ((type.compare("integer") == 0) || (type.compare("int") == 0)) {
		return ParameterDescription::ParameterType::Integer;
	}
	else if ((type.compare("float") == 0) || (type.compare("double") == 0)) {
		return ParameterDescription::ParameterType::Double;
	}
	else if (type.compare("date") == 0) {
		return ParameterDescription::ParameterType::Date;
	}
	return ParameterDescription::ParameterType::String;
}

} /* namespace TimeTableCatalog */