22 #include "MSSessionStorage.hpp" 24 #include "MSContext.hpp" 27 #include "MSElement.hpp" 28 #include "MSSessionStorageInterface.hpp" 33 #include <qdatetime.h> 36 #include <qsqlerror.h> 37 #include <qsqlquery.h> 38 #include <qsqldatabase.h> 42 #include <boost/make_shared.hpp> 54 MSSessionStorage::~MSSessionStorage()
66 if (!SessionSingleton)
70 return SessionSingleton;
84 MC_WARNING(
"A database or storage has been opened for playback already.");
102 MC_WARNING(
"A database or storage has been opened for record already.");
156 MC_WARNING(
"This storage is registered already!");
167 MC_WARNING(
"No storage have been loaded yet!");
192 MC_WARNING(
"Nor a recorded neither a new database has not been opened yet.");
197 MC_WARNING(
"The element instance has been registered already.");
200 if (element.
GetType() != MS::Source)
202 MC_WARNING(
"The class of the element is not a source class.");
205 QString ClassName = element.
GetClass();
212 SqlQuery1 =
"SELECT DISTINCT ID FROM "+ClassName.toUpper()+
213 " WHERE ID = "+QString::number(element.
GetElementID())+
';';
214 SqlQuery2 =
"SELECT DISTINCT ID FROM "+ClassName.toUpper()+
';';
218 bool ConversionResult =
true;
219 int CandidateID = Result.toInt(&ConversionResult);
222 if (Result.contains(
','))
224 QString Message =
"The source element ("+ClassName+
") is not found in the database with the ID "+
225 QString::number(element.
GetElementID())+
" and there are more candidate IDs ("+
226 Result+
"), thus re-mapping cannot be done reliably.";
230 if (!ConversionResult)
232 QString Message =
"The element class "+ClassName+
" with ID "+QString::number(element.
GetElementID())+
233 " is not found in the played session and no candidate ID available.";
239 RemappedIDs.insert(element.
GetElementID(), CandidateID);
240 QString Message =
"The source element "+ClassName+
" with ID "+QString::number(element.
GetElementID())+
241 " has been re-mapped to the candidate ID "+Result+
'.';
250 bool DataEnd =
false;
256 QString Column = ResultStr.section(
',', 1+i1*6, 1+i1*6);
258 if (!Column.isEmpty())
269 QString QuesryStr = QString(
"SELECT BEATID FROM %1 ORDER BY BEATID DESC LIMIT 1;").arg(ClassName);
274 if (!Columns.isEmpty())
282 MC::DataContainerSPtr ElementsContainer =
PlaybackStorage->GetContainer(
"SourceElements");
284 if (!ElementsContainer.get())
286 MC_ERROR(
"No SourceElements container in the session storage in playback mode");
289 MCDataItemBase* ElementsPtr = ElementsContainer->GetData(
"Elements");
291 if (!IDsPtr || !ElementsPtr)
293 MC_ERROR(
"No IDs or Elements items in SourceElements container in the session storage in playback mode");
295 MC::StringList* IDs =
reinterpret_cast<MC::StringList*
>(IDsPtr->DataPtr);
296 MC::StringList* Elements =
reinterpret_cast<MC::StringList*
>(ElementsPtr->DataPtr);
299 if (ElementsInStorage == 0)
301 MC_WARNING(
"Can't register %s element because it is not in the playback storage",
302 qPrintable(ClassName));
306 if (ElementsInStorage > 1)
308 QString Message =
"The source element ("+ClassName+
") is not found in the storage with the ID "+
309 QString::number(element.
GetElementID())+
" and there are more candidate IDs ("+
310 QString::number(ElementsInStorage)+
"), thus re-mapping cannot be done reliably.";
314 bool ConversionResult =
true;
316 int CandidateID = QString::fromStdString(Result).toInt(&ConversionResult);
318 if (!ConversionResult)
320 QString Message =
"The element class "+ClassName+
" with ID "+QString::number(element.
GetElementID())+
321 " is not found in the played session storage and no candidate ID available.";
328 RemappedIDs.insert(element.
GetElementID(), CandidateID);
329 QString Message =
"The source element "+ClassName+
" with ID "+QString::number(element.
GetElementID())+
330 " has been re-mapped to the candidate ID "+Result.c_str()+
'.';
336 void* HeartBeatsPtr = ElementsContainer->GetData(
"HeartBeats")->DataPtr;
344 QString QueryStr = QString(
"INSERT INTO SOURCE_ELEMENTS VALUES(%1, '%2');").
345 arg(QString::number(element.
GetElementID()), ClassName);
347 MC_LOG(
"New element into the db: %s", qPrintable(QueryStr));
367 MC::DataContainerSPtr ElementContainer =
RecordStorage->GetContainer(
"SourceElements");
369 if (!ElementContainer.get())
371 MC::StringList TempList;
374 ElementContainer =
RecordStorage->CreateContainer(
"SourceElements");
377 ElementContainer->AddData(*
new MCDataItem<int>(TempInt,
"HeartBeats",
true));
379 void* IDsPtr = ElementContainer->GetData(
"IDs")->DataPtr;
380 MC::StringList* IDs =
reinterpret_cast<MC::StringList*
>(IDsPtr);
381 void* ElementsPtr = ElementContainer->GetData(
"Elements")->DataPtr;
382 MC::StringList* Elements =
reinterpret_cast<MC::StringList*
>(ElementsPtr);
385 Elements->push_back(ClassName.toStdString());
386 MC_LOG(
"New element into the storage: %s", qPrintable(ClassName));
408 MC_WARNING(
"A database has been opened for record already.");
413 MC_WARNING(
"Record path has not been specified.");
428 if (QFile(StorageName).exists())
481 const QString& output_name,
484 if (output_name.isEmpty())
486 MC_WARNING(
"Empty output name is not valid.");
489 if (base_path.isEmpty())
496 MC_WARNING(
"Unknown storage interface type is not valid.");
499 QString BinaryFileName = base_path;
501 BinaryFileName += QDir::separator();
502 BinaryFileName += QString::number(element_id);
503 BinaryFileName += QDir::separator();
504 BinaryFileName += output_name.toUpper();
510 BinaryFileName +=
'_';
511 BinaryFileName += QString::number(beat_id);
513 BinaryFileName +=
'.';
514 return BinaryFileName;
520 if (!QSqlDatabase::drivers().contains(
"QSQLITE"))
522 MC_ERROR(
"Please install or compile the Qt's SQL driver for SQLite, it is required for AiBO+.");
526 DatabaseName +=
"/Session.db";
528 *
RecordDatabase = QSqlDatabase::addDatabase(
"QSQLITE",
"RecordSession");
536 #if defined(__MINGW32__) || defined(__MINGW64__) 549 MC_WARNING(
"Database has not been created for record yet.");
555 bool TypeFound =
false;
556 QString ClassName = element.
GetClass();
558 TableHeader = QString(
"CREATE TABLE IF NOT EXISTS %1 (ID INTEGER, BEATID INTEGER, OUTPUTS TEXT").
559 arg(ClassName.toUpper());
562 if (OutputList.isEmpty())
566 for (
int i = 0; i < OutputList.size(); ++i)
568 if (OutputList[i].isEmpty())
570 MC_WARNING(
"The %d. parameter is empty in the output list of the element class: %s",
571 i, qPrintable(ClassName));
574 if (OutputList[i].contains(
","))
576 MC_ERROR(
"The %d. parameter contains prohibited COMMA in the output list of the element class: %s",
577 i, qPrintable(ClassName));
579 QString OutputName = OutputList[i].section(
':', 0, 0);
580 QString OutputType = OutputList[i].section(
':', 1, 1);
582 if (OutputName.isEmpty() || OutputType.isEmpty())
584 MC_ERROR(
"An output parameter has wrong syntax for class %s. " 585 "The string \'%s\' must follow the 'name:type' format.",
586 qPrintable(ClassName), qPrintable(OutputList[i]));
593 MC_ERROR(
"Unable to find a storage for type %s.", qPrintable(OutputType));
600 MC_ERROR(
"Output data %s cannot be fetched from %s.", qPrintable(OutputList[i]), qPrintable(ClassName));
609 MC_ERROR(
"Type %s cannot be translated to an Sql type.", qPrintable(OutputType));
617 TableHeader += OutputName.toUpper();
622 TableHeader +=
"TEXT";
626 TableHeader +=
"INTEGER";
630 TableHeader +=
"REAL";
637 if (iter.key().isEmpty())
639 MC_ERROR(
"A parameter is empty in the field list of the type: %s", qPrintable(OutputType));
641 QString FieldName = iter.key().section(
':', 0, 0);
642 QString FieldType = iter.key().section(
':', 1, 1);
644 if (FieldName.isEmpty() || FieldType.isEmpty())
646 MC_ERROR(
"A field has wrong syntax for type %s. The string \'%s\' must follow the 'name:type' format.",
647 qPrintable(OutputType), qPrintable(iter.key()));
654 MC_ERROR(
"Field %s in the type %s cannot be translated to an Sql type.",
655 qPrintable(FieldType), qPrintable(OutputType));
662 TableHeader +=
", "+OutputName.toUpper()+
'_'+FieldName.toUpper()+
' ';
666 TableHeader +=
"TEXT";
670 TableHeader +=
"INTEGER";
674 TableHeader +=
"REAL";
683 MC_ERROR(
"No output type to store from a source element?!?");
694 MC_WARNING(
"Database has not been opened for play yet.");
700 QStringList OutputList =
RegElements[i]->GetOutputList();
707 if (OutputList.isEmpty())
712 if (RemappedIDs.contains(ElementID))
714 ElementID = RemappedIDs[ElementID];
717 QueryPart2 =
"FROM "+ClassName.toUpper()+
" WHERE ID = "+QString::number(ElementID)+
718 " AND BEATID = "+QString::number(BeatID)+
';';
723 for (
int i1 = 0; i1 < OutputList.size(); ++i1)
727 if (OutputList[i1].isEmpty())
729 MC_WARNING(
"The %d. parameter is empty in the output list of the element class: %s",
730 i1, qPrintable(ClassName));
734 QString OutputName = OutputList[i1].section(
':', 0, 0);
735 QString OutputType = OutputList[i1].section(
':', 1, 1);
738 if (!
RegElements[i]->CurrentOutputList.contains(OutputList[i1]))
741 if (OutputName.isEmpty() || OutputType.isEmpty())
743 MC_ERROR(
"An output has wrong syntax for class %s. The string \'%s\' must follow the 'name:type' format.",
744 qPrintable(ClassName), qPrintable(OutputList[i1]));
751 MC_ERROR(
"Unable to find a storage for type %s.", qPrintable(OutputType));
758 MC_ERROR(
"Output data %s cannot be fetched from %s.", qPrintable(OutputList[i1]), qPrintable(ClassName));
768 MC_ERROR(
"Type %s cannot be translated to a storage type. Implementation is missing " 769 "in the registered storages.", qPrintable(OutputType));
776 if (!
TableColumns[ClassName].contains(OutputName.toUpper()))
779 QueryPart1 =
"SELECT "+OutputName.toUpper()+
' '+QueryPart2;
784 MC_ERROR(
"Type %s cannot be extracted from the Sql string. Implementation is missing " 785 "in the storages in MSSessionStorageInterface::ConvertSqlStringToData().",
786 qPrintable(OutputType));
797 MC_ERROR(
"Unable to load type %s as binary. Implementation is missing in the storages in " 798 "MSSessionStorageInterface::LoadBinaryDataFromFile().", qPrintable(OutputType));
804 QList<QString> FieldTypeList;
805 QList<void*> FieldDataList;
807 QueryPart1 =
"SELECT ";
812 if (iter.key().isEmpty())
814 MC_ERROR(
"A parameter is empty in the field list of the type: %s",
815 qPrintable(OutputType));
820 MC_ERROR(
"Field %s in the type %s cannot be extracted.",
821 qPrintable(iter.key()), qPrintable(OutputType));
823 QString FieldName = iter.key().section(
':', 0, 0);
824 QString FieldType = iter.key().section(
':', 1, 1);
826 if (FieldName.isEmpty() || FieldType.isEmpty())
828 MC_ERROR(
"A field has wrong syntax for type %s. " 829 "The string \'%s\' must follow the 'name:type' format.",
830 qPrintable(OutputType), qPrintable(iter.key()));
838 MC_ERROR(
"Field %s in the type %s cannot be translated to an Sql type." 839 "Implementation is missing in the storages in MSSessionStorageInterface::FindStorageType().",
840 qPrintable(FieldType), qPrintable(OutputType));
847 if (!
TableColumns[ClassName].contains(OutputName.toUpper()+
'_'+FieldName.toUpper()))
850 QueryPart1 += OutputName.toUpper()+
'_'+FieldName.toUpper()+
',';
851 FieldTypeList += FieldType;
852 FieldDataList += iter.value();
858 QString IDStr = OutputName.toUpper()+
'_'+FieldName.toUpper();
863 MC_ERROR(
"Unable to load type %s as binary. Implementation is missing in the storages in " 864 "MSSessionStorageInterface::LoadBinaryDataFromFile().", qPrintable(FieldType));
871 QueryPart1.remove(QueryPart1.length()-1, 1);
872 QueryPart1 +=
' '+QueryPart2;
876 for (
int i3 = 0; i3 < FieldTypeList.size(); ++i3)
880 MC_ERROR(
"Type %s cannot be extracted from the Sql string. Implementation is missing in " 881 "the storages in MSSessionStorageInterface::ConvertSqlStringToData().",
882 qPrintable(FieldTypeList[i3]));
892 MC_LOG(
"End of played session database");
902 MC_WARNING(
"Database has not been created for record yet.");
908 QStringList OutputList =
RegElements[i]->GetOutputList();
910 QString InsertValueStr;
916 if (OutputList.isEmpty())
921 InsertIDStr = QString(
"INSERT INTO %1 (ID, BEATID, OUTPUTS").arg(ClassName.toUpper());
922 InsertValueStr = QString(
"VALUES (%1, %2, '%3'").arg(QString::number(ElementID), QString::number(BeatID),
926 for (
int i1 = 0; i1 < OutputList.size(); ++i1)
928 if (OutputList[i1].isEmpty())
930 MC_WARNING(
"The %d. parameter is empty in the output list of the element class: %s",
931 i1, qPrintable(ClassName));
934 QString OutputName = OutputList[i1].section(
':', 0, 0);
935 QString OutputType = OutputList[i1].section(
':', 1, 1);
938 if (!
RegElements[i]->CurrentOutputList.contains(OutputList[i1]))
942 if (OutputName.isEmpty() || OutputType.isEmpty())
944 MC_ERROR(
"An output has wrong syntax for class %s. The string \'%s\' must follow the 'name:type' format.",
945 qPrintable(ClassName), qPrintable(OutputList[i1]));
953 MC_ERROR(
"Unable to find a storage for type %s.", qPrintable(OutputType));
971 MC_ERROR(
"Type %s cannot be translated to a storage type. Implementation is missing " 972 "in the storages in MSSessionStorageInterface::FindStorageType().",
973 qPrintable(OutputType));
981 if (SqlValue.isEmpty())
983 MC_ERROR(
"Type %s cannot be converted to an Sql type. Implementation is missing " 984 "in the storages in MSSessionStorageInterface::ConvertDataToSqlString().",
985 qPrintable(OutputType));
987 InsertIDStr +=
", "+OutputName.toUpper();
988 InsertValueStr +=
", \""+SqlValue+
"\"";
999 MC_ERROR(
"Unable to save type %s as binary. Implementation is missing " 1000 "in the storages in MSSessionStorageInterface::SaveBinaryDataToFile().",
1001 qPrintable(OutputType));
1010 if (iter.key().isEmpty())
1012 MC_ERROR(
"A parameter is empty in the field list of the type: %s",
1013 qPrintable(OutputType));
1018 MC_ERROR(
"Field %s in the type %s cannot be extracted.",
1019 qPrintable(iter.key()), qPrintable(OutputType));
1022 QString FieldName = iter.key().section(
':', 0, 0);
1023 QString FieldType = iter.key().section(
':', 1, 1);
1025 if (FieldName.isEmpty() || FieldType.isEmpty())
1027 MC_ERROR(
"A field has wrong syntax for type %s. " 1028 "The string \'%s\' must follow the 'name:type' format.",
1029 qPrintable(OutputType), qPrintable(iter.key()));
1037 MC_ERROR(
"Field %s in the type %s cannot be translated to an Sql type." 1038 "Implementation is missing in the storages in MSSessionStorageInterface::FindStorageType().",
1039 qPrintable(FieldType), qPrintable(OutputType));
1047 if (SqlValue.isEmpty())
1049 MC_ERROR(
"Type %s cannot be converted to an Sql type. Implementation is missing " 1050 "in the storages in MSSessionStorageInterface::ConvertDataToSqlString().",
1051 qPrintable(OutputType));
1053 InsertIDStr +=
", "+OutputName.toUpper()+
'_'+FieldName.toUpper();
1054 InsertValueStr +=
", "+SqlValue;
1061 QString IDStr = OutputName.toUpper()+
'_'+FieldName.toUpper();
1066 MC_ERROR(
"Unable to save type %s as binary. Implementation is missing " 1067 "in the storages in MSSessionStorageInterface::SaveBinaryDataToFile().",
1068 qPrintable(OutputType));
1077 InsertIDStr +=
") "+InsertValueStr+
");";
1085 if (type_name.isEmpty())
1103 if (query_str.isEmpty())
1105 MC_WARNING(
"Empty query string is not valid.");
1108 QSqlQuery Query(database);
1109 QStringList Results;
1111 if (!Query.exec(qPrintable(query_str)))
1113 if (!Query.lastError().text().isEmpty())
1115 MC_WARNING(
"Sqlite query: %s", qPrintable(query_str));
1116 MC_WARNING(
"Sqlite error in the query: %s", qPrintable(Query.lastError().text()));
1118 if (!database.lastError().text().isEmpty())
1120 MC_WARNING(
"Sqlite error in the database: %s", qPrintable(database.lastError().text()));
1125 while (Query.next())
1127 for (
int i = 0; Query.value(i) != QVariant::Invalid; ++i)
1128 Results += Query.value(i).toString();
1131 if (!Results.isEmpty())
1133 return Results.join(
",");
1144 MC_WARNING(
"Database has not been created for record yet.");
1147 #if defined(__MINGW32__) || defined(__MINGW64__) 1154 QSqlDatabase::removeDatabase(
"RecordSession");
1162 MC_WARNING(
"Session playback location has not been set.");
1167 MC_WARNING(
"A database has been opened for play already.");
1172 DatabaseName +=
"/Session.db";
1173 if (!QSqlDatabase::drivers().contains(
"QSQLITE"))
1175 MC_ERROR(
"Please install or compile the Qt's SQL driver for SQLite, it is required for AiBO+.");
1178 *
PlaybackDatabase = QSqlDatabase::addDatabase(
"QSQLITE",
"PlaybackSession");
1180 if (!QFile(DatabaseName).exists())
1182 MC_ERROR(
"Database file does not exist: %s", qPrintable(DatabaseName));
1196 MC_WARNING(
"Database has not been opened for play yet.");
1201 QSqlDatabase::removeDatabase(
"PlaybackSession");
1207 QString StorageName =
RecordPath+
"/Session.bdb";
1212 MC_ERROR(
"Can't create session storage (%s)", qPrintable(StorageName));
1221 MC_WARNING(
"Storage has not been created for record yet.");
1227 if (OutputList.isEmpty())
1230 bool TypeFound =
false;
1231 std::string ClassName = element.
GetClass().toStdString();
1232 MC::StringTable NewTable;
1233 MC::StringList TableHeader;
1234 MC::DataContainerSPtr ElementContainer =
RecordStorage->GetContainer(ClassName);
1236 if (!ElementContainer.get())
1238 ElementContainer =
RecordStorage->CreateContainer(ClassName);
1241 TableHeader.push_back(
"ID");
1243 TableHeader.push_back(
"Outputs");
1245 for (
int i = 0; i < OutputList.size(); ++i)
1247 if (OutputList[i].isEmpty())
1249 MC_WARNING(
"The %d. parameter is empty in the output list of the element class: %s",
1250 i, ClassName.c_str());
1253 QString OutputName = OutputList[i].section(
':', 0, 0);
1254 QString OutputType = OutputList[i].section(
':', 1, 1);
1256 if (OutputName.isEmpty() || OutputType.isEmpty())
1258 MC_ERROR(
"An output parameter has wrong syntax for class %s. " 1259 "The string \'%s\' must follow the 'name:type' format.",
1260 ClassName.c_str(), qPrintable(OutputList[i]));
1267 MC_ERROR(
"Unable to find a storage for type %s.", qPrintable(OutputType));
1273 MC_ERROR(
"Output data %s cannot be fetched from %s.", qPrintable(OutputList[i]),
1283 MC_ERROR(
"Type %s cannot be translated to an Sql type.", qPrintable(OutputType));
1292 TableHeader.push_back(OutputName.toStdString());
1296 TableHeader.push_back(OutputName.toStdString());
1300 TableHeader.push_back(OutputName.toStdString());
1307 if (iter.key().isEmpty())
1309 MC_ERROR(
"A parameter is empty in the field list of the type: %s", qPrintable(OutputType));
1311 QString FieldName = iter.key().section(
':', 0, 0);
1312 QString FieldType = iter.key().section(
':', 1, 1);
1314 if (FieldName.isEmpty() || FieldType.isEmpty())
1316 MC_ERROR(
"A field has wrong syntax for type %s. The string \'%s\' must follow the 'name:type' format.",
1317 qPrintable(OutputType), qPrintable(iter.key()));
1323 MC_ERROR(
"Field %s in the type %s cannot be translated to an Sql type.",
1324 qPrintable(FieldType), qPrintable(OutputType));
1333 TableHeader.push_back(OutputName.toStdString()+
'_'+FieldName.toStdString());
1337 TableHeader.push_back(OutputName.toStdString()+
'_'+FieldName.toStdString());
1341 TableHeader.push_back(OutputName.toStdString()+
'_'+FieldName.toStdString());
1350 MC_ERROR(
"No output type to store from a source element?!?");
1353 MC::StringList BeatIDs;
1356 NewTable.push_back(TableHeader);
1365 MC_WARNING(
"Storage has not been opened for playback yet.");
1373 MC::DataContainerSPtr ElementContainer =
PlaybackStorage->GetContainer(ClassName.toStdString());
1375 if (!ElementContainer.get() || !
RegElements[i]->HasOutputs())
1379 void* BeatIDsPtr = ElementContainer->GetData(
"BeatIDs::"+ContainerIndexStr)->DataPtr;
1380 MC::StringList* BeatIDs =
reinterpret_cast<MC::StringList*
>(BeatIDsPtr);
1381 std::string OutputsTableContainerName = ClassName.toStdString()+
"::"+ContainerIndexStr;
1382 void* OutputsTablePtr = ElementContainer->GetData(OutputsTableContainerName)->DataPtr;
1383 MC::StringTable* OutputsTable =
reinterpret_cast<MC::StringTable*
>(OutputsTablePtr);
1385 if (!BeatIDs || !OutputsTable)
1388 std::string BeatIDStr =
MCToStr(BeatID);
1389 std::pair<int, std::string> Result =
MCBinarySearch(*BeatIDs, BeatIDStr);
1390 QStringList OutputList =
RegElements[i]->GetOutputList();
1394 if (Result.first == -1)
1400 if (RemappedIDs.contains(ElementID))
1402 ElementID = RemappedIDs[ElementID];
1404 std::string ElementIDStr =
MCToStr(ElementID);
1407 for (
unsigned int i1 = Result.first; i1 < BeatIDs->size(); ++i1)
1409 if ((*OutputsTable)[i1][0] == ElementIDStr)
1416 RegElements[i]->CurrentOutputList = QString::fromStdString((*OutputsTable)[FinalIndex][1]).split(
',');
1418 for (
int i1 = 0; i1 <
RegElements[i]->CurrentOutputList.size(); ++i1)
1420 if (
RegElements[i]->CurrentOutputList[i1].isEmpty())
1427 for (
int i1 = 0; i1 <
RegElements[i]->CurrentOutputList.size(); ++i1)
1429 if (
RegElements[i]->CurrentOutputList[i1].isEmpty())
1431 MC_WARNING(
"The %d. parameter is empty in the output list of the element class: %s",
1432 i1, qPrintable(ClassName));
1436 if (!OutputList.contains(
RegElements[i]->CurrentOutputList[i1]))
1439 QString OutputName =
RegElements[i]->CurrentOutputList[i1].section(
':', 0, 0);
1440 QString OutputType =
RegElements[i]->CurrentOutputList[i1].section(
':', 1, 1);
1442 if (OutputName.isEmpty() || OutputType.isEmpty())
1444 MC_ERROR(
"An output has wrong syntax for class %s. The string \'%s\' must follow the 'name:type' format.",
1445 qPrintable(ClassName), qPrintable(
RegElements[i]->CurrentOutputList[i1]));
1452 MC_ERROR(
"Unable to find a storage for type %s.", qPrintable(OutputType));
1459 MC_ERROR(
"Output data %s cannot be fetched from %s.",
1460 qPrintable(
RegElements[i]->CurrentOutputList[i1]), qPrintable(ClassName));
1470 MC_ERROR(
"Type %s cannot be translated to a storage type. Implementation is missing " 1471 "in the registered storages.", qPrintable(OutputType));
1479 for (
unsigned int i2 = 2; i2 < (*OutputsTable)[0].size(); ++i2)
1481 if (QString::fromStdString((*OutputsTable)[0][i2]) == OutputName)
1485 if (DataIndex == -1)
1488 QString ResultStr = QString::fromStdString((*OutputsTable)[FinalIndex][DataIndex]);
1492 MC_ERROR(
"Type %s cannot be extracted from the Sql string. Implementation is missing " 1493 "in the storages in MSSessionStorageInterface::ConvertSqlStringToData().",
1494 qPrintable(OutputType));
1505 MC_ERROR(
"Unable to load type %s as binary. Implementation is missing in the storages in " 1506 "MSSessionStorageInterface::LoadBinaryDataFromFile().", qPrintable(OutputType));
1515 if (iter.key().isEmpty())
1517 MC_ERROR(
"A parameter is empty in the field list of the type: %s", qPrintable(OutputType));
1522 MC_ERROR(
"Field %s in the type %s cannot be extracted.", qPrintable(iter.key()),
1523 qPrintable(OutputType));
1525 QString FieldName = iter.key().section(
':', 0, 0);
1526 QString FieldType = iter.key().section(
':', 1, 1);
1528 if (FieldName.isEmpty() || FieldType.isEmpty())
1530 MC_ERROR(
"A field has wrong syntax for type %s. " 1531 "The string \'%s\' must follow the 'name:type' format.",
1532 qPrintable(OutputType), qPrintable(iter.key()));
1539 MC_ERROR(
"Field %s in the type %s cannot be translated to an Sql type." 1540 "Implementation is missing in the storages in MSSessionStorageInterface::FindStorageType().",
1541 qPrintable(FieldType), qPrintable(OutputType));
1549 for (
unsigned int i2 = 2; i2 < (*OutputsTable)[0].size(); ++i2)
1551 if (QString::fromStdString((*OutputsTable)[0][i2]) == OutputName+
'_'+FieldName)
1555 if (DataIndex == -1)
1558 QString ResultStr = QString::fromStdString((*OutputsTable)[FinalIndex][DataIndex]);
1561 MC_ERROR(
"Type %s cannot be extracted from the Sql string. Implementation is missing in " 1562 "the storages in MSSessionStorageInterface::ConvertSqlStringToData().",
1563 qPrintable(FieldType));
1570 QString IDStr = OutputName.toUpper()+
'_'+FieldName.toUpper();
1575 MC_ERROR(
"Unable to load type %s as binary. Implementation is missing in the storages in " 1576 "MSSessionStorageInterface::LoadBinaryDataFromFile().", qPrintable(FieldType));
1589 MC_LOG(
"End of played session database");
1599 MC_WARNING(
"Storage has not been created for record yet.");
1607 QStringList OutputList =
RegElements[i]->GetOutputList();
1612 if (OutputList.isEmpty())
1615 MC::DataContainerSPtr ElementContainer =
RecordStorage->GetContainer(ClassName.toStdString());
1617 if (!ElementContainer.get())
1622 MCDataItemBase* BeatIDsPtr = ElementContainer->GetData(
"BeatIDs::"+ContainerIndexStr);
1623 std::string OutputsTableContainerName = ClassName.toStdString()+
"::"+ContainerIndexStr;
1624 MCDataItemBase* OutputsTablePtr = ElementContainer->GetData(OutputsTableContainerName);
1626 if (!BeatIDsPtr || !OutputsTablePtr)
1629 BeatIDsPtr = ElementContainer->GetData(
"BeatIDs::"+ContainerIndexStr);
1630 OutputsTablePtr = ElementContainer->GetData(OutputsTableContainerName);
1632 MC::StringList* BeatIDs =
reinterpret_cast<MC::StringList*
>(BeatIDsPtr->DataPtr);
1633 MC::StringTable* OutputsTable =
reinterpret_cast<MC::StringTable*
>(OutputsTablePtr->DataPtr);
1634 MC::StringList NewTableRow;
1636 for (
unsigned int i1 = 0; i1 < (*OutputsTable)[0].size(); ++i1)
1637 NewTableRow.push_back(
"");
1639 BeatIDs->push_back(
MCToStr(BeatID));
1640 NewTableRow[0] =
MCToStr(ElementID);
1641 NewTableRow[1] =
RegElements[i]->CurrentOutputList.join(
",").toStdString();
1644 for (
int i1 = 0; i1 < OutputList.size(); ++i1)
1646 if (OutputList[i1].isEmpty())
1648 MC_WARNING(
"The %d. parameter is empty in the output list of the element class: %s",
1649 i1, qPrintable(ClassName));
1652 QString OutputName = OutputList[i1].section(
':', 0, 0);
1653 QString OutputType = OutputList[i1].section(
':', 1, 1);
1656 if (!
RegElements[i]->CurrentOutputList.contains(OutputList[i1]))
1660 if (OutputName.isEmpty() || OutputType.isEmpty())
1662 MC_ERROR(
"An output has wrong syntax for class %s. The string \'%s\' must follow the 'name:type' format.",
1663 qPrintable(ClassName), qPrintable(OutputList[i1]));
1670 MC_ERROR(
"Unable to find a storage for type %s.", qPrintable(OutputType));
1688 MC_ERROR(
"Type %s cannot be translated to a storage type. Implementation is missing " 1689 "in the storages in MSSessionStorageInterface::FindStorageType().",
1690 qPrintable(OutputType));
1698 if (SqlValue.isEmpty())
1700 MC_ERROR(
"Type %s cannot be converted to an Sql type. Implementation is missing " 1701 "in the storages in MSSessionStorageInterface::ConvertDataToSqlString().",
1702 qPrintable(OutputType));
1706 for (
unsigned int i2 = 2; i2 < (*OutputsTable)[0].size(); ++i2)
1708 if (QString::fromStdString((*OutputsTable)[0][i2]) == OutputName)
1712 if (DataIndex == -1)
1715 NewTableRow[DataIndex] = SqlValue.toStdString();
1726 MC_ERROR(
"Unable to save type %s as binary. Implementation is missing " 1727 "in the storages in MSSessionStorageInterface::SaveBinaryDataToFile().",
1728 qPrintable(OutputType));
1737 if (iter.key().isEmpty())
1739 MC_ERROR(
"A parameter is empty in the field list of the type: %s",
1740 qPrintable(OutputType));
1745 MC_ERROR(
"Field %s in the type %s cannot be extracted.",
1746 qPrintable(iter.key()), qPrintable(OutputType));
1748 QString FieldName = iter.key().section(
':', 0, 0);
1749 QString FieldType = iter.key().section(
':', 1, 1);
1751 if (FieldName.isEmpty() || FieldType.isEmpty())
1753 MC_ERROR(
"A field has wrong syntax for type %s. " 1754 "The string \'%s\' must follow the 'name:type' format.",
1755 qPrintable(OutputType), qPrintable(iter.key()));
1763 MC_ERROR(
"Field %s in the type %s cannot be translated to an Sql type." 1764 "Implementation is missing in the storages in MSSessionStorageInterface::FindStorageType().",
1765 qPrintable(FieldType), qPrintable(OutputType));
1773 if (SqlValue.isEmpty())
1775 MC_ERROR(
"Type %s cannot be converted to an Sql type. Implementation is missing " 1776 "in the storages in MSSessionStorageInterface::ConvertDataToSqlString().",
1777 qPrintable(OutputType));
1781 for (
unsigned int i2 = 2; i2 < (*OutputsTable)[0].size(); ++i2)
1783 if (QString::fromStdString((*OutputsTable)[0][i2]) == OutputName+
'_'+FieldName)
1787 if (DataIndex == -1)
1790 NewTableRow[DataIndex] = SqlValue.toStdString();
1797 QString IDStr = OutputName.toUpper()+
'_'+FieldName.toUpper();
1802 MC_ERROR(
"Unable to save type %s as binary. Implementation is missing " 1803 "in the storages in MSSessionStorageInterface::SaveBinaryDataToFile().",
1804 qPrintable(OutputType));
1813 OutputsTable->push_back(NewTableRow);
1816 MC::DataContainerSPtr ElementsContainer =
RecordStorage->GetContainer(
"SourceElements");
1818 if (ElementsContainer.get() &&
RegElements.size() > 0)
1820 void* HeartBeatsPtr = ElementsContainer->GetData(
"HeartBeats")->DataPtr;
1823 *
reinterpret_cast<int*
>(HeartBeatsPtr) =
RegElements[0]->GetBeatID();
1829 QString StorageName =
RecordPath+
"/Session.bdb";
1833 MC_ERROR(
"Can't save session storage (%s)", qPrintable(StorageName));
1848 MC_WARNING(
"Storage has not been created for record yet.");
1852 QString StorageName =
RecordPath+
"/Session.bdb";
1856 MC_ERROR(
"Can't save session storage (%s)", qPrintable(StorageName));
1866 MC_WARNING(
"Session playback location has not been set.");
1871 MC_WARNING(
"A storage has been opened for playback already.");
1876 if (!QFile(StorageName).exists())
1878 MC_ERROR(
"Session storage file does not exist: %s", qPrintable(StorageName));
1883 MC_ERROR(
"Can't open session storage (%s)", qPrintable(StorageName));
1892 MC_WARNING(
"Storage has not been opened for playback yet.");
void CreateNewDataItemsForAClass(MSElement &object)
Create data container for an element class.
int GetPlayedHeartBeats() const
Get the number of the played heart beats.
MSSessionStorageInterface * GetStorage(const QString &type_name) const
Get the appropriate storage for a type.
Load or store the source elements' output of a session.
QString ExecuteSqlQuery(const QSqlDatabase &database, const QString &query_str) const
Execute an SQL query.
bool MCCreatePath(const QString &path)
Create a new path if it does not exist.
void PreparePlay()
Prepare the play of a recorded session.
static void RegisterTimer(const QString &id, const QString &description)
Register a timer.
void CreateRecordDatabase()
Create an empty record database.
QString GetClass() const
Get the class name.
A helper class to fill the type info to the base structure.
void OpenPlaybackDatabase()
Open a database.
void CreateTableForAClass(MSElement &object)
Create table for an element class.
void EndOfDatabase()
End of the data in the database.
Interface class to handle new types in the storage.
int GetElementID() const
Get the element ID.
void ResetTimers()
Reset the internal timers.
MSSessionStorage()
Class constructor.
void SetPlaybackPath(const QString &path)
Set the playback path.
boost::scoped_ptr< MCDataStorage > PlaybackStorage
Play data storage.
static MSSessionStorage * GetInstance()
Get a static instance of the class.
virtual bool SaveBinaryDataToFile(const QString &file_name, const QString &output_type, const StorageDataType &storage_type, void *output_data)=0
Save binary data to a file.
Basic ancestor class of the elements.
#define MC_ERROR(...)
Error macro.
QString PlaybackPath
Playback path.
static void StartTimer(const QString &id)
Start a timer.
#define MC_WARNING(...)
Warning macro.
int GetBeatID() const
Get the current beat ID.
Data container item base structure to store basic type info.
std::string MCToStr(const T value, bool hex_manipulator=false)
Convert an other type to string with std::stringstream.
virtual bool ConvertSqlStringToData(const QString &type_name, const QString &sql_str, void *output_data)=0
Convert an Sql string to a data.
QMap< QString, QStringList > TableColumns
Cached class outputs.
virtual StorageDataType FindStorageType(const QString &type_name)=0
Translate the type.
boost::scoped_ptr< QSqlDatabase > RecordDatabase
Record database.
QStringList ElementClassNames
Registered class names with an instance.
void RemoveStorages()
Remove the session storages.
virtual QString ConvertDataToSqlString(const QString &type_name, void *output_data)=0
Convert the data to a string for an Sql insert.
boost::scoped_ptr< QSqlDatabase > PlaybackDatabase
Playback database.
int PlayedHeartBeats
Played heart beats.
const QMap< QString, void * > & GetVariableMap() const
Get the variable map.
QList< QPointer< MSSessionStorageInterface > > SessionStorages
Storage implementations.
void CloseRecordStorage()
Close record storage.
void ClosePlaybackDatabase()
Close the database being played.
Data storage with file support.
static void ResetTimer(const QString &id)
Reset a timer.
bool IsStorageAvailable() const
Check if any storage is available.
void LoadStatesFromDatabase()
Load the element states from the database.
QList< MSElement * > RegElements
Registered elements.
std::pair< int, T > MCBinarySearch(const U &container, const T &value, bool nearest=false)
Binary search for a value in a container.
QString GetPlaybackPath() const
Get the playback path.
Base class for the data exchange of the elements.
int MCItemCountInContainer(const U &container, const T item)
Calculate the number of a given item in a container.
void CloseRecordDatabase()
Close the record database.
void OpenPlaybackStorage()
Open playback storage.
QString ConstructFileName(int object_id, int beat_id, const QString &base_path, const QString &output_name, const MSSessionStorageInterface::StorageDataType &storage_type) const
Construct a file name in the storage without extension.
QString RecordPath
Path where the recording goes.
std::vector< int > MCItemIndicesInContainer(const U &container, const T item)
Get item indices in a container.
boost::scoped_ptr< MCDataStorage > RecordStorage
Record data storage.
void Finalize()
Finalize the storage operations.
MSData * GetOutputData(const QString &output_name) const
Get an output data of the element.
void RegisterStorage(MSSessionStorageInterface &storage)
Register a session storage.
MS::ElementType GetType() const
Get the type of the element.
void CreateRecordStorage()
Create a new record storage.
const int RecordStoragePeriod
Record storage period.
void RecordStatesToDatabase()
Record the element states to the database.
#define MC_LOG(...)
Debug macro.
static void StopTimer(const QString &id)
Stop a timer.
QStringList GetOutputList() const
Get the output list.
QString GetRecordPath() const
Get the record path.
void RecordStatesToStorage()
Record element states to storage.
void RegisterElement(MSElement &object)
Register an element.
void SetRecordPath(const QString &record_path)
Set the record path.
void LoadStatesFromStorage()
Load element states from storage.
void PrepareRecord()
Prepare the record of a new session.
void BeatEnd(int beat_id)
This slot is being called by the end of a heart beat.
virtual bool LoadBinaryDataFromFile(const QString &file_name, const QString &output_type, const StorageDataType &storage_type, void *output_data)=0
Load binary data from a file.
void ClosePlaybackStorage()
Close playback storage.