VOTableReader.cc 8.15 KB
/*
 * VOTableReader.cc
 *
 *  Created on: 7 août 2013
 *      Author: CS
 */

#include "VOTableData.hh"
#include "VOTableReader.hh"
#include "TimeTableCatalogUtil.hh"
#include "Catalog.hh"
#include <iostream>
#include <string.h>

#include <boost/algorithm/string.hpp>

namespace TimeTableCatalog {

const std::string VOTableReader::FORMAT = "VO";

VOTableReader::VOTableReader(const std::string& pPath) :
		XMLReader(pPath) {
	_tmpIntervalstartdate = -1;

	_readingVOTable     = false;
	_readingResource    = false;
	_readingTable       = false;
	_readingField       = false;
	_readingDescription = false;
	_readingTr          = false;
	_readingTd          = false;

	_tdCount    = 0;
	_fieldCount = 0;
}

VOTableReader::~VOTableReader() {
}

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

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

std::string VOTableReader::getFirstNode() {
	return VOTableData::VOTABLE_TAG;
}

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

/**
 *
 * @pTT : the timetable to load
 * @reader: the xmlReader
 *
 * Fills the given TimeTable with the xml file content
 */
void VOTableReader::processNode(TimeTable& pTT, xmlTextReaderPtr reader, int &crtIndex) {
	const xmlChar *name;

	// -- read tag
	name = xmlTextReaderConstName(reader);
	if (name == NULL)
		name = BAD_CAST "--";

	// get tag name to easily handle it
	std::string tagName = reinterpret_cast<const char*>(name);

	if (tagName == VOTableData::VOTABLE_TAG) {
		_readingVOTable = (xmlTextReaderNodeType(reader) == 1);
	}
	else if (tagName == VOTableData::RESOURCE_TAG) {
		_readingResource = (xmlTextReaderNodeType(reader) == 1);
	}
	else if (tagName == VOTableData::TABLE_TAG) {
		_readingTable = (xmlTextReaderNodeType(reader) == 1);
	}
	else if (tagName == VOTableData::DESCRIPTION_TAG) {
		_readingDescription = (xmlTextReaderNodeType(reader) == 1);
	}
	else if (tagName == VOTableData::FIELD_TAG) {
		_readingField = (xmlTextReaderNodeType(reader) == 1);
		if (_readingField) {
			readField (pTT, reader);
			++_fieldCount;
		}
	}
	else if (tagName == VOTableData::TR_TAG) {
		_readingTr = (xmlTextReaderNodeType(reader) == 1);
		if (!_readingTr) {
			_tdCount = 0;
		}
	}
	else if (tagName == VOTableData::TD_TAG) {
		_readingTd = (xmlTextReaderNodeType(reader) == 1);
	}
	else if ((tagName == "#text") && (xmlTextReaderNodeType(reader) == 3)) {
		if (_readingDescription) {
			readDescription (pTT, reader);
		}
		else if (_readingTr == true) {
			readInterval (pTT, reader, crtIndex);
			++crtIndex;
			_tdCount++;
		}
	}
}

void VOTableReader::readDescription(TimeTable& pTT, xmlTextReaderPtr reader) {
	// -- read tag text (may be NULL)
	const xmlChar *value = xmlTextReaderConstValue(reader);

	std::string tagValue = reinterpret_cast<const char*>(value);

	if (_readingVOTable && !_readingResource) {
		readMetadata(tagValue, pTT);
	} else if (_readingResource && !_readingField) {
		if (value != NULL)
			split(tagValue, '\n', pTT._description);
		else
			pTT._description.clear();
	} else if (_readingField && (_fieldCount > 2)) {
		// Two first fields are used for start time and stop time
		ParameterDescription *pd = pTT.getLastParameterDescritption();
		pd->setDescription(tagValue);
	}
}

void VOTableReader::readField(TimeTable& pTT, xmlTextReaderPtr reader) {
	const xmlChar *attrName;

	attrName = xmlTextReaderGetAttribute (reader, (const xmlChar*)VOTableData::FIELD_NAME_ATTRIB.c_str());

	// Jump startTime & stopTime tag
	if (_fieldCount >= 2){
		const xmlChar *attrId, *attrSize, *attrType, *attrUnit, *attrUcd, *attrUtype;

		attrId	 		= xmlTextReaderGetAttribute (reader, (const xmlChar*)VOTableData::FIELD_ID_ATTRIB.c_str());
		attrSize 		= xmlTextReaderGetAttribute (reader, (const xmlChar*)VOTableData::FIELD_ARRAYSIZE_ATTRIB.c_str());
		attrType 		= xmlTextReaderGetAttribute (reader, (const xmlChar*)VOTableData::FIELD_DATATYPE_ATTRIB.c_str());
		attrUnit		= xmlTextReaderGetAttribute (reader, (const xmlChar*)VOTableData::FIELD_UNIT_ATTRIB.c_str());
		attrUcd			= xmlTextReaderGetAttribute (reader, (const xmlChar*)VOTableData::FIELD_UCD_ATTRIB.c_str());
		attrUtype		= xmlTextReaderGetAttribute (reader, (const xmlChar*)VOTableData::FIELD_UTYPE_ATTRIB.c_str());

		std::string voType = std::string((const char *)attrType);
		ParameterDescription::ParameterType internalType = getTypeFromString(voType);

		std::string internalSize("1");
		if (((char *) attrSize) != NULL) {
			internalSize = std::string((const char *)attrSize);
		}
		if (internalSize.compare("*") == 0 || internalType == ParameterDescription::ParameterType::String) {
			internalSize = "1";
		}

		std::string attrIdStr = (attrId != NULL) ? std::string((const char *)attrId) : "";
		std::string attrNameStr = (attrName != NULL) ? std::string((const char *)attrName) : "";
		std::string attrUnitStr = (attrUnit != NULL) ? std::string((const char *)attrUnit) : "";
		std::string attrUcdStr = (attrUcd != NULL) ? std::string((const char *)attrUcd) : "";
		std::string attrUtypeStr = (attrUtype != NULL) ? std::string((const char *)attrUtype) : "";

		((Catalog *) &pTT)->addParameterDescription(ParameterDescription(
				attrIdStr,
				attrNameStr,
				internalSize,
				internalType,
				attrUnitStr,
				"",		// Read later
				attrUcdStr,
				attrUtypeStr));

	}
}

void VOTableReader::readInterval (TimeTable& pTT, xmlTextReaderPtr reader, int pcrtIndex) {
	// -- read tag text (may be NULL)
	const xmlChar *value = xmlTextReaderConstValue(reader);

	std::string tagValue = reinterpret_cast<const char*>(value);
	// first TD is startdate
	if (_tdCount == 0) {
		// read start date of interval
		_tmpIntervalstartdate = readISOTime(tagValue);

		// read time format, the first date of the first interval
		if (pTT._timeFormat == TimeTable::TIME_FORMAT::UNKNOWN) {
			int size = 0;
			pTT._timeFormat = getTimeFormat(tagValue, size);
		}
	} else if (_tdCount == 1) {
		// start date is set, that means we are waiting for stop date
		pTT.addInterval( TimeInterval(_tmpIntervalstartdate, readISOTime(tagValue), pcrtIndex));
	} else {
		TimeInterval * pLastInterval = pTT.getLastInterval();
		// If interval list is not empty, add parameter data to the last interval
		if (pLastInterval != NULL) {
			ParameterDescriptionList pdl = pTT.getParameterDescritptions();

			std::vector<std::string> paramList;
			split (tagValue, VOTableData::SEPARATOR.c_str()[0], paramList);

			int nbParamDataInterval = pLastInterval->getParameterDataCount();
			std::string paramKey = pdl [nbParamDataInterval].getId();
			pLastInterval->addParameterData(paramKey, paramList);
		}
	}
}

void VOTableReader::readMetadata(const std::string& pDescription,
		TimeTable& pTimeTable) {
	// try to find string like "Prop:xxxx" and set _prop attribute to "xxxx"
	std::vector<std::string> lines;
	split(pDescription, ';', lines);

	for (std::string line : lines) {

		// -- here try to find "Name:"
		if (contains(line, VOTableData::NAME_TAG)) {
			extractvalue(line, pTimeTable._name);
		}
		// -- here try to find "Historic:"
		else if (contains(line, VOTableData::HISTORIC_TAG)) {
			extractvalue(line, 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(line, VOTableData::CREATION_DATE_TAG)) {
			// convert creation date string to char*
			std::string creationDate;
			extractvalue(line, creationDate);
			// try to read date
			try {
				pTimeTable._creationDate = TimeTableCatalog::readISOTime(creationDate);
			} catch (...) {
				LOG4CXX_WARN(_logger,
						"Unable to parse creation date in " + getPath());
			}
		} else {
			// ignore lines
		}
	}
}

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

	if ((type.compare("boolean") == 0) || (type.compare("short") == 0) || (type.compare("int") == 0) || (type.compare("long") == 0)) {
		return ParameterDescription::ParameterType::Integer;
	}
	else if ((type.compare("float") == 0) || (type.compare("double") == 0)) {
		return ParameterDescription::ParameterType::Double;
	}
	return ParameterDescription::ParameterType::String;
}

} /* namespace TimeTableCatalog */