Files
qt5-legatus-legacy/Lts/Services/InfrastructureManagement/ImportBuildings/ism_import_buildings.cpp
T
2026-08-13 18:33:10 +02:00

1027 lines
37 KiB
C++
Executable File

/**
* @RDE_HEADER@
* ISM Test Import XML
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2016-11-28
*/
#include "ism_import_buildings.h"
#include <InfrastructureManagement/parse_building_xml.h>
#include <nglapplication/nglcoreapplication.h>
#include <LtsCommandLineParser/LtsCommandLineParser.h>
#include <QFile>
#include <QTextStream>
#include <QTimer>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QtWebSockets/QWebSocket>
#include <QUrl>
#include <QThread>
#include <InfrastructureManagement/ism_ftc.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <iostream>
using namespace InfrastructureManagement;
// ------------------------------------------------------------------------------
IsmImportBuildings::IsmImportBuildings(QObject *parent)
: QObject(parent)
, m_logger(getLogger("ImportXml"))
{
qRegisterMetaType<Core::FunctionReply>("Core::FunctionReply");
connect(this, &IsmImportBuildings::importDone, this, &IsmImportBuildings::importNext);
}
// ------------------------------------------------------------------------------
bool IsmImportBuildings::init(int domainId, const QUrl &tcpDiscoveryUrl)
{
INFO_LOG(m_logger) << "init begin";
// initialize DDS, always on exercise 0
m_ddsConnector.reset(new DDSConnector::DdsConnector(domainId, IDL::PartitionType::Global, 0, 0, tcpDiscoveryUrl));
if (!m_ddsConnector->init())
return false;
m_ddsConnector->initPublisherSubscriber();
DEBUG_LOG(m_logger) << "create dtc";
m_dtc = InfrastructureManagement::Interface::Dtc::create(m_ddsConnector);
DEBUG_LOG(m_logger) << "create ftc";
m_ftc = InfrastructureManagement::Interface::Ftc::create(m_ddsConnector);
DEBUG_LOG(m_logger) << "init dtc & ftc";
bool bRet = m_ftc->enableMainStructureElementModify() &&
m_ftc->enableMainStructureElementRemove() &&
m_ftc->enableMountingPointAssetRemove() &&
m_ftc->enableMountingPointAssetModify() &&
m_ftc->enableMountingPointPlanModify() &&
m_ftc->enableStructureElementModify() &&
m_dtc->enableMainStructureElement() &&
m_dtc->enableInstrumentationAsset() &&
m_dtc->enableMountingPointAsset() &&
m_dtc->enableMainSchedule();
DEBUG_LOG(m_logger) << "init dtc, ftc end - bRet = " << bRet;
DEBUG_LOG(m_logger) << "Domain Id = " << domainId;
return bRet;
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::import(const ImportData &importData)
{
m_currentData = importData;
QTimer::singleShot(0, this, &IsmImportBuildings::doImport);
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::import(const QVector<ImportData> &importData)
{
m_importData = importData;
if (m_importData.isEmpty())
{
QCoreApplication::quit();
return;
}
DEBUG_LOG(m_logger) << "Trying to import " << m_importData.size() << " buildings";
m_curImportIdx = 0;
import(m_importData.at(m_curImportIdx));
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::remove(const QVector<int> &ids)
{
m_idsToBeRemoved = ids;
removeNext();
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::removeNext()
{
if (m_idsToBeRemoved.isEmpty())
{
if (m_isInRestoringMode)
return;
QCoreApplication::quit();
return;
}
remove(m_idsToBeRemoved.front());
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::importNext()
{
if (m_curImportIdx < 0 || m_curImportIdx + 1 >= m_importData.size())
{
QCoreApplication::quit();
return;
}
++m_curImportIdx;
import(m_importData.at(m_curImportIdx));
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::remove(int buildingId)
{
bool assetsMounted = false;
m_dtc->waitForHistoricalDataMainStructureElement();
m_dtc->waitForHistoricalDataInstrumentationAsset();
m_dtc->waitForHistoricalDataMountingPointAsset();
auto predicate = [](const InfrastructureManagement::InstrumentationAsset & a)
{
return (!a.isDeleted() && (a.mountingPointTypeId() != InfrastructureManagement::MountingPointType::BuildingControlUnit));
};
QMap<int, QVector<InfrastructureManagement::InstrumentationAsset>> assetsMapBuilding;
m_dtc->getAllAssetsPerBuilding(predicate, assetsMapBuilding);
DEBUG_LOG(m_logger) << "assetsMapBuilding.size = " << assetsMapBuilding.size();
assetsMounted = (assetsMapBuilding[buildingId].size() > 0);
DEBUG_LOG(m_logger) << "Building id = " << buildingId << " has assets mounted = " << assetsMounted;
// cfroebel 2018-11-30:
// Currently the ISM service fails to correctly remove a building when it has mounted assets (other than BCU).
// It then removes the building but leaves the assets in a mounted state.
// Thus for now we need to check here whether the building has mounted assets or not.
if (assetsMounted)
{
QString msg = QStringLiteral("Not possible to remove building with id %1 because there are assets mounted!").arg(buildingId);
ERROR_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
m_idsToBeRemoved.pop_front();
IsmImportBuildings::removeNext();
}
else
IsmImportBuildings::doRemove(buildingId);
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::doImport()
{
INFO_LOG(m_logger) << "trying to Import / Modify";
ParseBuildingXml buildingXml(m_currentData.xmlFileName,
m_currentData.vulFileName,
m_currentData.egcuToRoomFileName,
m_currentData.soundAreaFileName,
m_currentData.geoPos,
m_currentData.angleDegree);
if (!buildingXml.parseXml())
{
ERROR_LOG(m_logger) << "Can not parse building files: " << buildingXml.lastError();
std::cerr << "Can not parse building files name: " << m_currentData.xmlFileName
<< " error: " << buildingXml.lastError() << std::endl;
QCoreApplication::exit(1);
return;
}
INFO_LOG(m_logger) << "Sending request";
MainStructureElementModifyRequest req = buildingXml.parsedRequest();
QByteArray propertiesBa = QByteArray::fromStdString(req.properties());
QJsonParseError parserError;
const QJsonDocument doc(QJsonDocument::fromJson(propertiesBa, &parserError));
if (parserError.error != QJsonParseError::NoError)
WARNING_LOG(m_logger) << "Error parsing json document: " << parserError.errorString() << " '" << propertiesBa << "'";
DEBUG_LOG(m_logger) << "json to parse: " << doc.toJson();
QJsonObject obj(doc.object());
if (m_currentData.exerciseId > 0)
{
QJsonArray array;
array.push_back(m_currentData.exerciseId);
obj.insert(QLatin1String("available_in_exercise"), array);
req.properties(QJsonDocument(obj).toJson(QJsonDocument::Compact).toStdString());
}
if (m_currentData.buildingId > 0)
req.id(m_currentData.buildingId);
req.externalWlsId(m_currentData.externalWlsId);
req.groupId(m_currentData.bauabschnitt);
req.structureElementTypeId(InfrastructureManagement::StructureElementType::Building);
// check if building exists
MainStructureElement oldMainStructureElement = mainStructureElementByName(req.name());
std::string msg;
QMap<qint32, QVector<std::string>> oldNamePaths;
QVector<MountingPointAsset> mountings;
if (oldMainStructureElement != MainStructureElement())
{
m_isInRestoringMode = true;
msg = "Building " + req.name() + " already exists. All related data is now saved.";
INFO_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
msg = "Fetching IDs of MountingPints.";
INFO_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
QVector<qint32> mountingPointIds;
for (const StructureElement &structureElement : oldMainStructureElement.elements())
{
if (structureElement.structureElementTypeId() != StructureElementType::MountingPoint)
continue;
mountingPointIds.append(structureElement.id());
}
msg = "Fetching MountingPointAssets.";
INFO_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
// get mountings of mounting points of this building
mountings = mountingsOfStructureElements(mountingPointIds);
// qint32 unmountCounter = 0;
if (!mountings.isEmpty())
{
msg = "Removing MountingPointAssets.";
INFO_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
unmountAssetsOfBuliding(oldMainStructureElement.id());
// // remove mounting point assets
// for (const MountingPointAsset &mountingPointAsset : mountings)
// {
// ++unmountCounter;
// m_ftc->mountingPointAssetRemoveRequest(Core::RemoveElementRequest(mountingPointAsset.id()), [this, &unmountCounter](const Core::FunctionReplyObject &rep){this->onMountingPointAssetRemoveReply(rep); --unmountCounter;});
// }
}
msg = "Fetching MountingPointPlans.";
INFO_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
// get mounting points in plans of this building
auto mppsBySchedule = MountingPointPlanByScheduleOfStructureElements(mountingPointIds);
// Don't know, why these are deleted anyways...
for (auto it = mppsBySchedule.cbegin(); it != mppsBySchedule.cend(); ++it)
{
INFO_LOG(m_logger) << "Removing MountingPointPlans.";
auto copy = it.value();
for (auto &elem : copy)
elem.mountingPointState() = MountingPointState_def::Idle;
m_ftc->mountingPointPlanModifyRequest(MountingPointPlanModifyRequest(it.key(),copy), this);
}
msg = "Fetching paths of MountingPoints by name ... for later reconstruction.";
INFO_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
for (const StructureElement &structureElement : oldMainStructureElement.elements())
oldNamePaths.insert(structureElement.id(), pathWithNames(structureElement, oldMainStructureElement));
//msg = "Waiting for removing operations.";
connect(this, &IsmImportBuildings::removeDone, this, [this, oldMainStructureElement, oldNamePaths, mountings, mppsBySchedule, req]()
{
connect(this, &IsmImportBuildings::importDone, this, [this, oldMainStructureElement, oldNamePaths, mountings, mppsBySchedule]()
{
restoreData(oldMainStructureElement, oldNamePaths, mountings, mppsBySchedule);
});
createNewMainStructureElement(req);
});
// while(unmountCounter)
// {
// std::cerr << "Unmount counter: " << unmountCounter << std::endl;
// QThread::sleep(1);
// }
remove(oldMainStructureElement.id());
}
else
createNewMainStructureElement(req);
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::doRemove(int buildingId)
{
std::string msg = "Trying to Remove building with id " + QString::number(buildingId).toStdString();
INFO_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
if (!m_ftc->mainStructureElementRemoveRequest(MainStructureElementRemoveRequest(buildingId), this))
{
ERROR_LOG(m_logger) << "Error requesting remove";
std::cerr << "Error requesting remove" << std::endl;
QCoreApplication::exit(1);
return;
}
}
// ------------------------------------------------------------------------------
MainStructureElement IsmImportBuildings::mainStructureElementByName(const std::string &name) const
{
m_dtc->waitForHistoricalDataMainStructureElement();
QMap<qint32, MainStructureElement> mainStructureElements = m_dtc->mainStructureElements();
for (auto it = mainStructureElements.constBegin(); it != mainStructureElements.constEnd(); ++it)
{
if (it.value().name() == name)
return it.value();
}
return MainStructureElement();
}
// ------------------------------------------------------------------------------
QHash<int, std::vector<MountingPointPlan> > IsmImportBuildings::MountingPointPlanByScheduleOfStructureElements(const QVector<qint32> &structureElementIds) const
{
m_dtc->waitForHistoricalDataMainSchedule();
QHash<int, std::vector<MountingPointPlan> > result;
for (const MainSchedule &schedule : m_dtc->mainSchedules())
{
for (const MountingPointPlan &plan : schedule.elements())
{
if (structureElementIds.contains(plan.structureElementId()))
result[schedule.id()].push_back(plan);
}
}
return result;
}
// ------------------------------------------------------------------------------
QVector<MountingPointAsset> IsmImportBuildings::mountingsOfStructureElements(const QVector<qint32> &structureElementIds) const
{
m_dtc->waitForHistoricalDataMountingPointAsset();
QMap<qint32, MountingPointAsset> mountings = m_dtc->mountingPointAssets();
QVector<MountingPointAsset> result;
for (auto it = mountings.constBegin(); it != mountings.constEnd(); ++it)
{
if (structureElementIds.contains(it.value().structureElementId()))
result.append(it.value());
}
return result;
}
// ------------------------------------------------------------------------------
QVector<std::string> IsmImportBuildings::pathWithNames(const StructureElement &structureElement, const MainStructureElement &mainStructureElement) const
{
QVector<std::string> result;
result.reserve(structureElement.path().size());
for (int32_t structureElementId : structureElement.path())
result.push_back(structureElementNameById(structureElementId, mainStructureElement.elements()));
return result;
}
// ------------------------------------------------------------------------------
std::string IsmImportBuildings::structureElementNameById(qint32 id, const std::vector<StructureElement> &structureElements) const
{
for (const StructureElement &structureElement : structureElements)
{
if (structureElement.id() == id)
return structureElement.name();
}
return std::string();
}
// ------------------------------------------------------------------------------
StructureElement IsmImportBuildings::structureElementById(qint32 id, const MainStructureElement &mainStructureElement) const
{
for (const StructureElement &structureElement : mainStructureElement.elements())
{
if (structureElement.id() == id)
return structureElement;
}
return StructureElement();
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::createNewMainStructureElement(const MainStructureElementModifyRequest &request)
{
std::string msg = "Creating new MainStructureElement.";
INFO_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
if (!m_ftc->mainStructureElementModifyRequest(request, this))
{
if (m_currentData.buildingId > 0)
ERROR_LOG(m_logger) << "Error requesting update";
else
ERROR_LOG(m_logger) << "Error requesting create";
std::cerr << "Error requesting update/create" << std::endl;
QCoreApplication::exit(1);
return;
}
INFO_LOG(m_logger) << "Waiting for answer";
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::restoreData(const MainStructureElement &oldMainStructureElement,
const QMap<qint32, QVector<std::string> > &oldNamePaths,
const QVector<MountingPointAsset> &mountings,
const QHash<int, std::vector<MountingPointPlan> > &mountingPointPlansBySchedule)
{
std::string msg;
if (oldMainStructureElement == MainStructureElement())
return;
MainStructureElement newMainStructureElement = mainStructureElementByName(oldMainStructureElement.name());
if (newMainStructureElement == MainStructureElement())
{
FATAL_LOG(m_logger) << "There was no new MainStructureElement created. Please consider restoring the database by backup.";
QCoreApplication::exit(1);
}
QVector<qint32> newMountingPointIds;
for (const StructureElement &structureElement : newMainStructureElement.elements())
{
if (structureElement.structureElementTypeId() != StructureElementType::MountingPoint)
continue;
newMountingPointIds.append(structureElement.id());
}
QMap<qint32, QVector<std::string> > newNamePaths;
INFO_LOG(m_logger) << "Restoring mounting point data.";
for (const StructureElement &structureElement : newMainStructureElement.elements())
newNamePaths.insert(structureElement.id(), pathWithNames(structureElement, oldMainStructureElement));
if (oldNamePaths.size() != newNamePaths.size())
INFO_LOG(m_logger) << "old name path size: " + QString::number(oldNamePaths.size()).toStdString() + " , new name path size: " + QString::number(newNamePaths.size()).toStdString();;
QMap<qint32, qint32> oldStructureElementIdToNewStructureElementId;
for (auto it = oldNamePaths.constBegin(); it != oldNamePaths.constEnd(); ++it)
{
for (auto innerIt = newNamePaths.constBegin(); innerIt != newNamePaths.constEnd(); ++innerIt)
{
if (it.value() == innerIt.value())
{
oldStructureElementIdToNewStructureElementId.insert(it.key(), innerIt.key());
break;
}
}
}
StructureElementModifyRequest modifyRequest;
modifyRequest.mainStructureElementId(newMainStructureElement.id());
for (auto it = oldStructureElementIdToNewStructureElementId.constBegin(); it != oldStructureElementIdToNewStructureElementId.constEnd(); ++it)
{
StructureElement oldStructureElement = structureElementById(it.key(), oldMainStructureElement);
if (!oldStructureElement.barcode().size() && !oldStructureElement.properties().size())
continue;
StructureElement newStructureElement = structureElementById(it.value(), newMainStructureElement);
newStructureElement.barcode(oldStructureElement.barcode());
newStructureElement.properties(oldMainStructureElement.properties());
modifyRequest.elements().push_back(newStructureElement);
}
if (modifyRequest.elements().size())
m_ftc->structureElementModifyRequest(modifyRequest, this);
if (!mountings.isEmpty())
{
msg = "Restoring MountingPointAssets.";
INFO_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
// restore mountings
for (const MountingPointAsset &mountingPointAsset : mountings)
{
if (!oldStructureElementIdToNewStructureElementId.contains(mountingPointAsset.structureElementId()))
{
msg = "There is no new StructureElement ID to old StructureElement ID " + QString::number(mountingPointAsset.structureElementId()).toStdString() + ". If somethind else looks suspicious, restore database data by backup.";
FATAL_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
continue;
}
MountingPointAssetModifyRequest mountingRequest;
mountingRequest.assetId(mountingPointAsset.assetId());
mountingRequest.structureElementId(oldStructureElementIdToNewStructureElementId.value(mountingPointAsset.id()));
m_ftc->mountingPointAssetModifyRequest(mountingRequest, this);
}
}
if (mountingPointPlansBySchedule.empty())
return;
msg = "Restoring MountingPointPlans.";
INFO_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
// restore mounting point plans
MountingPointPlanModifyRequest createRequest;
for (auto it = mountingPointPlansBySchedule.cbegin(); it != mountingPointPlansBySchedule.cend(); ++it)
{
createRequest.mountingPointScheduleId() = it.key();
// NO constRef! We change values...
for(MountingPointPlan mountingPointPlan : it.value())
{
if (!oldStructureElementIdToNewStructureElementId.contains(mountingPointPlan.structureElementId()))
{
FATAL_LOG(m_logger) <<"There is no new StructureElement ID to old StructureElement ID " + QString::number(mountingPointPlan.structureElementId()).toStdString() + ". If somethind else looks suspicious, restore database data by backup.";
continue;
// mountingPointPlan.structureElementId() = oldStructureElementIdToNewStructureElementId.value(mountingPointPlan.structureElementId());
// createRequest.mountingPointPlans().push_back(mountingPointPlan);
}
}
if (!createRequest.mountingPointPlans().empty())
m_ftc->mountingPointPlanModifyRequest(createRequest, this);
}
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::unmountAssetsOfBuliding(qint32 buildingId)
{
QWebSocket socket;
std::string msg;
QUrl url;
url.setPort(2080);
url.setHost(QLatin1String("localhost"));
socket.open(url);
while(socket.state() != QAbstractSocket::ConnectedState)
{
msg = "Waiting for socket to open";
std::cerr << msg << std::endl;
INFO_LOG(m_logger) << msg;
QThread::sleep(1);
}
QJsonObject jsonObj;
QJsonObject dataObj;
jsonObj.insert(QLatin1String("type"), QLatin1String("unmountObject"));
jsonObj.insert(QLatin1String("uuid"), QLatin1String("UUID"));
dataObj.insert(QLatin1String("objectId"), buildingId);
jsonObj.insert(QLatin1String("data"), dataObj);
bool hasAnswer = false;
connect(&socket, &QWebSocket::textMessageReceived, this, [this, &hasAnswer](const QString &message)
{
std::string msg = "Got reply: " + message.toStdString();
std::cerr << msg << std::endl;
INFO_LOG(m_logger) << msg;
hasAnswer = true;
});
socket.sendTextMessage(QString::fromLatin1(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact)));
while(!hasAnswer)
{
msg = "Waiting for socket to answer";
std::cerr << msg << std::endl;
INFO_LOG(m_logger) << msg;
QThread::sleep(1);
}
socket.close();
}
// ------------------------------------------------------------------------------
void IsmImportBuildings::onMainStructureElementModifyReply(const Core::FunctionReplyObject &replyObject)
{
if (handleReply(replyObject))
emit importDone();
}
// ------------------------------------------------------------------
void IsmImportBuildings::onMainStructureElementRemoveReply(const Core::FunctionReplyObject &replyObject)
{
int buildingId = -1;
if (!m_idsToBeRemoved.isEmpty())
m_idsToBeRemoved.front();
if (replyObject.error())
{
QString msg = QStringLiteral("Failed to remove building with id %1: %2").arg(buildingId).arg(QString::fromStdString(replyObject()));
ERROR_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
}
else
{
QString msg = QStringLiteral("Removed building with id %1").arg(buildingId);
INFO_LOG(m_logger) << msg;
std::cerr << msg << std::endl;
}
emit removeDone();
if (!m_idsToBeRemoved.isEmpty())
m_idsToBeRemoved.pop_front();
removeNext();
}
// ------------------------------------------------------------------
void IsmImportBuildings::onMountingPointPlanModifyReply(const Core::FunctionReplyObject &reply)
{
if (reply.error())
{
ERROR_LOG(m_logger) << reply.error();
std::cerr << reply.error() << std::endl;
}
}
// ------------------------------------------------------------------
void IsmImportBuildings::onMountingPointAssetRemoveReply(const Core::FunctionReplyObject &reply)
{
ERROR_LOG(m_logger) << "REMOVE REPLY";
if (reply.error())
{
ERROR_LOG(m_logger) << reply.error();
std::cerr << reply.error() << std::endl;
}
}
// ------------------------------------------------------------------
void IsmImportBuildings::onMountingPointAssetModifyReply(const Core::FunctionReplyObject &reply)
{
if (reply.error())
{
ERROR_LOG(m_logger) << reply.error();
std::cerr << reply.error() << std::endl;
}
}
// ------------------------------------------------------------------
void IsmImportBuildings::onStructureElementModifyReply(const Core::FunctionReplyObject &reply)
{
if (reply.error())
{
ERROR_LOG(m_logger) << reply.error();
std::cerr << reply.error() << std::endl;
}
}
// ------------------------------------------------------------------
bool IsmImportBuildings::handleReply(const Core::FunctionReplyObject &replyObject)
{
if (replyObject.error())
{
ERROR_LOG(m_logger) << "Got Reply error: " << replyObject.translated();
std::cerr << "Error importing building" << std::endl;
QCoreApplication::exit(1);
return false;
}
if (replyObject.id() > 0)
{
const QString buildingName = m_currentData.xmlFileName.split(QLatin1Char('.')).first();
NOTICE_LOG(m_logger) << "Imported building '" << buildingName << "' with id " << replyObject.id() << " (groupId = " << m_currentData.bauabschnitt << ")";
std::cerr << "Imported building '" << qPrintable(buildingName) << "' with id " << replyObject.id() << " (groupId = " << m_currentData.bauabschnitt << ")" << std::endl;
}
return true;
}
// ------------------------------------------------------------------
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
{
public:
CmdLineParser()
: LtsCommandLineParser(ProvideCommandLineParameterOptions(TcpConnectionUrl | DomainId))
{
addOption({QStringList() << QLatin1String("f") << QLatin1String("importFileName"),
QLatin1String("Import buildings specified in csv file"),
QLatin1String("csv file")
});
addOption({QStringList() << QLatin1String("x") << QLatin1String("xmlFile"),
QLatin1String("Import building xml file"),
QLatin1String("xml file")
});
// v ist schon belegt ...
addOption({QStringList() << QLatin1String("y") << QLatin1String("vulnerabilityFile"),
QLatin1String("Import vulnerability (damage) xml file"),
QLatin1String("vul file")
});
addOption({QStringList() << QLatin1String("z") << QLatin1String("egcuToRoomFile"),
QLatin1String("Import Egcu to Room xml file"),
QLatin1String("egcu file")
});
addOption({QStringList() << QLatin1String("s") << QLatin1String("soundAreasFile"),
QLatin1String("Import SoundAreas xml file"),
QLatin1String("soundAreas file")
});
addOption({QStringList{QStringLiteral("r"), QStringLiteral("removeBuilding")},
QStringLiteral("Remove a building from the database (handle with care!). Can be given multiple times or as a comma-separated list"),
QStringLiteral("id")
});
addOption({QStringList() << QLatin1String("u") << QLatin1String("updateBuilding"),
QLatin1String("Update a building from the database (handle with care!)"),
QLatin1String("id")
});
addOption({ QStringList() << QLatin1String("p") << QLatin1String("position"),
QLatin1String("The position to place the building (lon,lat,z,rotationDegree)"),
QLatin1String("lon,lat,z,rotDegree")
});
addOption({QStringList() << QLatin1String("e") << QLatin1String("availableInExercise"),
QLatin1String("Make building available in exercise"),
QLatin1String("exerciseId")
});
addOption({QStringList() << QLatin1String("w") << QLatin1String("wirelessLocationId"),
QLatin1String("The external wls id to use for this building (default: 0)"),
QLatin1String("externalWlsId")
});
}
QString csvFile() const { return value(QLatin1String("f")); }
QString xmlFile() const { return value(QLatin1String("x")); }
QString vulnerabilityFile() const { return value(QLatin1String("y")); }
QString egcuToRoomFile() const { return value(QLatin1String("z")); }
QString soundAreaFile() const { return value(QLatin1String("s")); }
bool removeBuilding() const { return isSet(QLatin1String("r")); }
QVector<int> removeBuildingIds() const
{
QVector<int> ids;
const auto optionValues = values(QStringLiteral("r"));
for (const auto &optionValue : optionValues)
{
const auto idsAsString = optionValue.split(QLatin1Char(','));
for (const auto &idAsString : idsAsString)
ids.push_back(idAsString.toInt());
}
return ids;
}
bool updateBuilding() const { return isSet(QLatin1String("u")); }
int updateBuildingId() const { return value(QLatin1String("u")).toInt(); }
int availableExerciseId() const { return value(QLatin1String("e")).toInt(); }
int externalWlsId() const { return value(QLatin1String("w")).toInt(); }
QString positionString() const { return value(QLatin1String("p")); }
};
static bool parsePositionString(const QStringRef &positionString,
Core::GeoPosition &pos,
double &rotationDegree)
{
QVector<QStringRef> parts = positionString.split(QLatin1Char(','));
if (parts.size() != 4)
return false;
bool bOk;
pos.lon(parts.at(0).toDouble(&bOk));
if (!bOk)
return false;
pos.lat(parts.at(1).toDouble(&bOk));
if (!bOk)
return false;
pos.z(parts.at(2).toDouble(&bOk));
if (!bOk)
return false;
rotationDegree = parts.at(3).toDouble(&bOk);
if (!bOk)
return false;
return true;
}
struct csvFileIndex
{
csvFileIndex()
{
reset();
}
int idxXmlFile;
int idxVulnerabilityFile;
int idxPosition;
int idxEgcuToRoomFile;
int idxExternalWlsId;
int idxBauabschnitt; // akn groupId
void reset()
{
idxXmlFile = 0;
idxVulnerabilityFile = 1;
idxPosition = 2;
// optional
idxEgcuToRoomFile = -1;
idxExternalWlsId = -1;
idxBauabschnitt = -1;
}
bool parseHeader(QString &headerline)
{
// should look like:
// #xmlFile;vulnerabilityFile;position
// #xmlFile;vulnerabilityFile;egcuToRoomFile;position
std::cout << " detecting order of columns: '" << headerline << "'" << std::endl;
std::cerr << " (#xmlFile;vulnerabilityFile;[egcuToRoomFile];position,[externalWlsId])" << std::endl;
headerline = headerline.trimmed();
if (headerline.startsWith(QLatin1Char('#')))
headerline.remove(0, 1);
else
{
std::cerr << " no header found, assume defaults..." << std::endl;
reset();
return true; // use defaults
}
QStringList sl = headerline.split(QLatin1Char(';'));
idxXmlFile = sl.indexOf(QStringLiteral("xmlFile"));
idxVulnerabilityFile = sl.indexOf(QStringLiteral("vulnerabilityFile"));
idxPosition = sl.indexOf(QStringLiteral("position"));
// optional:
idxEgcuToRoomFile = sl.indexOf(QStringLiteral("egcuToRoomFile"));
idxExternalWlsId = sl.indexOf(QStringLiteral("externalWlsId"));
idxBauabschnitt = sl.indexOf(QStringLiteral("bauabschnitt"));
std::cout << " detect following order: " << std::endl;
std::cout << " idxXmlFile= " << idxXmlFile << std::endl;
std::cout << " idxVulnerabilityFile= " << idxVulnerabilityFile << std::endl;
std::cout << " idxPosition= " << idxPosition << std::endl;
std::cout << " idxEgcuToRoomFile= " << idxEgcuToRoomFile << std::endl;
std::cout << " idxExternalWlsId= " << idxExternalWlsId << std::endl;
std::cout << " idxBauabschnitt= " << idxBauabschnitt << std::endl;
if ((idxXmlFile >= 0) && (idxVulnerabilityFile >= 0) && (idxPosition >= 0))
return true;
else
{
std::cerr << " parsing header failed, assume defaults..." << std::endl;
reset();
return false;
}
}
};
// ------------------------------------------------------------------
int main(int argc, char **argv)
{
NGLCoreApplication app(argc, argv);
app.createLogger("ISM", 0);
NOTICE_LOG(app.baseLogger()) << "Starting...";
CmdLineParser options;
if (!options.init())
{
FATAL_LOG(app.baseLogger()) << "init failed";
std::cerr << "init failed" << std::endl;
return -1;
}
int iRet = -1;
{
std::unique_ptr<InfrastructureManagement::IsmImportBuildings> importXml(new InfrastructureManagement::IsmImportBuildings);
if (!importXml->init(options.domainId(), options.tcpConnectionUrl()))
{
FATAL_LOG(app.baseLogger()) << "Can not init, domainId=" << options.domainId() << ", tcpConnectionUrl: '" << options.tcpConnectionUrl().toDisplayString() << "'";
std::cerr << "Can not init, domainId=" << options.domainId() << ", tcpConnectionUrl: '" << options.tcpConnectionUrl().toDisplayString() << "'" << std::endl;
return -2;
}
if (options.removeBuilding())
importXml->remove(options.removeBuildingIds());
else
{
const QString csvFile = options.csvFile();
NOTICE_LOG(app.baseLogger()) << "using csvFile '" << csvFile << "'";
if (csvFile.isEmpty())
{
InfrastructureManagement::IsmImportBuildings::ImportData data;
const QString ps = options.positionString();
if (!parsePositionString(QStringRef(&ps), data.geoPos, data.angleDegree))
{
ERROR_LOG(app.baseLogger()) << "Error parsing position string! str='" << ps << "'" ;
std::cerr << "Error parsing position string! str='" << ps << "'" << std::endl;
return -3;
}
data.xmlFileName = options.xmlFile();
data.vulFileName = options.vulnerabilityFile();
data.egcuToRoomFileName = options.egcuToRoomFile();
data.soundAreaFileName = options.soundAreaFile();
data.exerciseId = options.availableExerciseId();
data.bauabschnitt = 1;
data.externalWlsId = options.externalWlsId();
if (options.updateBuilding())
data.buildingId = options.updateBuildingId();
importXml->import(data);
}
else
{
QFile f(csvFile);
if (!f.open(QIODevice::ReadOnly))
{
WARNING_LOG(app.baseLogger()) << "Can not open file '" << csvFile << "' for reading: " << f.errorString();
std::cerr << "Can not open file '" << csvFile << "' for reading: " << f.errorString() << std::endl;
return -4;
}
QTextStream ts(&f);
QString line;
csvFileIndex cfi;
bool bIsHeaderParesed = false;
InfrastructureManagement::IsmImportBuildings::ImportData data;
// exerciseId
data.exerciseId = options.availableExerciseId();
QVector<InfrastructureManagement::IsmImportBuildings::ImportData> dataVec;
while (ts.readLineInto(&line))
{
std::cerr << "line '" << line << "'" << std::endl;
// read header (at first line)
if (!bIsHeaderParesed)
{
bIsHeaderParesed = true;
line = line.trimmed();
if (line.startsWith(QLatin1Char('#')))
{
cfi.parseHeader(line);
continue;
} else {
std::cerr << " no header found, assume defaults..." << std::endl;
}
}
const QVector<QStringRef> parts = line.splitRef(QLatin1Char(';'));
if (parts.size() < 3 || parts.size() > 6)
{
WARNING_LOG(app.baseLogger()) << "Can not parse line: '" << line << "' - skipping";
continue;
}
// xmlFile
data.xmlFileName = parts.at(cfi.idxXmlFile).toString();
// vulnerabilityFile
data.vulFileName = parts.at(cfi.idxVulnerabilityFile).toString();
// position
if (!parsePositionString(parts.at(cfi.idxPosition), data.geoPos, data.angleDegree))
{
ERROR_LOG(app.baseLogger()) << "Can not parse position string of line = '" << line << "'";
std::cerr << "Can not parse position string of line = '" << line << "'" << std::endl;
ERROR_LOG(app.baseLogger()) << "Can not parse position string: '" << parts.at(cfi.idxPosition).toString() << "'";
std::cerr << "Can not parse position string: '" << parts.at(cfi.idxPosition).toString() << "'" << std::endl;
return -5;
}
//
// optional:
//
// egcuToRoomFile
if ((cfi.idxEgcuToRoomFile>=0) && (parts.size() > cfi.idxEgcuToRoomFile))
data.egcuToRoomFileName = parts.at(cfi.idxEgcuToRoomFile).toString();
// externalWlsId
data.externalWlsId = 0;
if ((cfi.idxExternalWlsId>=0) && (parts.size() > cfi.idxExternalWlsId))
data.externalWlsId = parts.at(cfi.idxExternalWlsId).toInt();
// bauabschnitt
// Normally '-1', but Steve and Iuliana use '0' as default.
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::UnknownGroup;
if ((cfi.idxBauabschnitt>=0) && (parts.size() > cfi.idxBauabschnitt))
{
// postprocessing uses ba0 -> 0 , ba1 -> 1 ...
// DB: ism.ism_buildung_group is different: Section0 -> 2 ; Section1 = 3 ; ...
const int ba = parts.at(cfi.idxBauabschnitt).toInt();
switch (ba) {
case 0:
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Section0;
break;
case 1:
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Section1;
break;
case 2:
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Section2;
break;
case 3:
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Section3;
break;
case 4:
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Section4;
break;
case 5:
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::Salchau;
break;
default:
data.bauabschnitt = InfrastructureManagement::BuildingGroup_def::type::UnknownGroup;
break;
}
}
dataVec += data;
} // while
importXml->import(dataVec);
}
}
STARTUP_LOG(app.baseLogger());
iRet = app.exec();
SHUTDOWN_LOG(app.baseLogger());
}
return iRet;
}