2015-08-12 20:21:10 +00:00
|
|
|
#include "DefinitionNode.h"
|
2013-10-30 11:46:18 +00:00
|
|
|
|
2015-08-13 21:46:50 +00:00
|
|
|
#include "Logs.h"
|
2013-11-03 12:00:31 +00:00
|
|
|
#include "PackStream.h"
|
2015-08-17 20:55:30 +00:00
|
|
|
#include "DefinitionWatcher.h"
|
2015-08-16 21:01:56 +00:00
|
|
|
#include "DefinitionDiff.h"
|
2015-08-16 22:29:54 +00:00
|
|
|
#include "DiffManager.h"
|
|
|
|
|
|
|
|
#include <cassert>
|
2015-11-18 18:37:00 +00:00
|
|
|
#include <algorithm>
|
2013-11-03 12:00:31 +00:00
|
|
|
|
2015-12-10 23:36:50 +00:00
|
|
|
DefinitionNode::DefinitionNode(DefinitionNode *parent, const string &name, const string &type_name)
|
2015-11-09 21:30:46 +00:00
|
|
|
: parent(parent), type_name(type_name), name(name) {
|
|
|
|
if (parent) {
|
2013-10-30 14:39:56 +00:00
|
|
|
root = parent->root;
|
2015-08-12 15:02:27 +00:00
|
|
|
parent->addChild(this);
|
2015-08-16 22:29:54 +00:00
|
|
|
diffs = NULL;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2013-10-30 14:39:56 +00:00
|
|
|
root = this;
|
2015-08-16 22:29:54 +00:00
|
|
|
diffs = new DiffManager(this);
|
2013-10-30 14:39:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
DefinitionNode::~DefinitionNode() {
|
|
|
|
if (parent) {
|
2015-08-12 15:02:27 +00:00
|
|
|
parent->removeChild(this);
|
|
|
|
parent = NULL;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (diffs) {
|
2015-08-16 22:29:54 +00:00
|
|
|
delete diffs;
|
|
|
|
diffs = NULL;
|
|
|
|
}
|
|
|
|
|
2015-08-12 17:29:28 +00:00
|
|
|
// Work on a copy, because the child destructor will modify the array by removing itself using removeChild
|
2015-12-10 23:36:50 +00:00
|
|
|
vector<DefinitionNode *> children_copy = children;
|
2015-11-09 21:30:46 +00:00
|
|
|
for (auto child : children_copy) {
|
|
|
|
if (child->getParent() == this) {
|
2015-08-12 15:02:27 +00:00
|
|
|
delete child;
|
|
|
|
}
|
2013-10-30 14:39:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-10 23:36:50 +00:00
|
|
|
void DefinitionNode::setName(const string &name) {
|
2013-10-31 16:59:18 +00:00
|
|
|
this->name = name;
|
2013-10-30 14:39:56 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
const Scenery *DefinitionNode::getScenery() const {
|
2015-11-09 21:30:46 +00:00
|
|
|
if (parent) {
|
2013-11-17 21:36:18 +00:00
|
|
|
return parent->getScenery();
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2013-11-17 21:36:18 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-10 23:36:50 +00:00
|
|
|
string DefinitionNode::toString(int indent) const {
|
|
|
|
string result;
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i < indent; i++) {
|
2015-08-12 15:02:27 +00:00
|
|
|
result += " ";
|
|
|
|
}
|
|
|
|
result += name;
|
2015-11-09 21:30:46 +00:00
|
|
|
if (not children.empty()) {
|
|
|
|
for (auto &child : children) {
|
2015-08-12 15:02:27 +00:00
|
|
|
result += "\n" + child->toString(indent + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-12-10 23:36:50 +00:00
|
|
|
string DefinitionNode::getPath() const {
|
2015-11-09 21:30:46 +00:00
|
|
|
if (parent == root) {
|
2015-08-16 22:29:54 +00:00
|
|
|
return parent->getPath() + name;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else if (parent) {
|
2015-08-16 22:29:54 +00:00
|
|
|
return parent->getPath() + "/" + name;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-08-16 22:29:54 +00:00
|
|
|
return "/";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-10 23:36:50 +00:00
|
|
|
DefinitionNode *DefinitionNode::findByPath(const string &path) const {
|
2015-11-09 21:30:46 +00:00
|
|
|
if (path.empty()) {
|
2015-08-16 22:29:54 +00:00
|
|
|
return NULL;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else if (path[0] == '/') {
|
|
|
|
if (path.length() == 1) {
|
2015-08-16 22:29:54 +00:00
|
|
|
return root;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else if (root == this) {
|
2015-08-16 22:29:54 +00:00
|
|
|
return findByPath(path.substr(1));
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-08-16 22:29:54 +00:00
|
|
|
return root->findByPath(path);
|
|
|
|
}
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-08-16 22:29:54 +00:00
|
|
|
size_t seppos = path.find("/");
|
2015-12-10 23:36:50 +00:00
|
|
|
string child_name = (seppos == string::npos) ? path : path.substr(0, seppos);
|
2015-12-15 23:38:28 +00:00
|
|
|
DefinitionNode *child = findChildByName(child_name);
|
2015-11-09 21:30:46 +00:00
|
|
|
if (child) {
|
2015-12-10 23:36:50 +00:00
|
|
|
if (seppos == string::npos) {
|
2015-08-16 22:29:54 +00:00
|
|
|
return child;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-08-16 22:29:54 +00:00
|
|
|
return child->findByPath(path.substr(seppos + 1));
|
|
|
|
}
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-08-16 22:29:54 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
bool DefinitionNode::applyDiff(const DefinitionDiff *diff, bool) {
|
2015-08-16 21:01:56 +00:00
|
|
|
// Only do type check, subclasses will do the rest
|
2015-11-09 21:30:46 +00:00
|
|
|
if (diff->getTypeName() == type_name) {
|
2015-08-16 21:01:56 +00:00
|
|
|
return true;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-12-13 19:08:38 +00:00
|
|
|
Logs::error("Definition") << "Can't apply " << diff->getTypeName() << " diff to " << getName() << " "
|
|
|
|
<< type_name << " node" << endl;
|
2015-08-16 21:01:56 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-10 23:36:50 +00:00
|
|
|
void DefinitionNode::generateInitDiffs(vector<const DefinitionDiff *> *) const {
|
2015-08-17 20:55:30 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void DefinitionNode::addWatcher(DefinitionWatcher *watcher, bool init_diff) {
|
|
|
|
if (root && root->diffs) {
|
|
|
|
if (init_diff) {
|
2015-12-10 23:36:50 +00:00
|
|
|
vector<const DefinitionDiff *> diffs;
|
2015-08-17 20:55:30 +00:00
|
|
|
generateInitDiffs(&diffs);
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
for (auto diff : diffs) {
|
2015-08-17 20:55:30 +00:00
|
|
|
watcher->nodeChanged(this, diff);
|
|
|
|
delete diff;
|
|
|
|
}
|
|
|
|
}
|
2015-08-16 22:29:54 +00:00
|
|
|
root->diffs->addWatcher(this, watcher);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
int DefinitionNode::getWatcherCount() const {
|
|
|
|
if (root && root->diffs) {
|
2015-09-21 21:10:43 +00:00
|
|
|
return root->diffs->getWatcherCount(this);
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-09-21 21:10:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void DefinitionNode::save(PackStream *stream) const {
|
2015-12-17 00:13:20 +00:00
|
|
|
int children_count = static_cast<int>(children.size());
|
2015-08-13 21:46:50 +00:00
|
|
|
stream->write(&children_count);
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
for (auto child : children) {
|
2015-08-13 21:46:50 +00:00
|
|
|
stream->write(child->name);
|
|
|
|
|
|
|
|
int child_size = child->getStreamSize();
|
2015-11-09 21:30:46 +00:00
|
|
|
if (child_size >= 0) {
|
2015-08-13 21:46:50 +00:00
|
|
|
stream->write(&child_size);
|
|
|
|
child->save(stream);
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-08-13 21:46:50 +00:00
|
|
|
// Child size not known, write it to a temporary stream to know it
|
2015-12-13 19:08:38 +00:00
|
|
|
Logs::debug("Definition") << "Unknown size for child " << child->name
|
|
|
|
<< ", unefficient writing to temporary stream" << endl;
|
2015-08-13 21:46:50 +00:00
|
|
|
PackStream substream;
|
|
|
|
child->save(&substream);
|
|
|
|
stream->writeFromBuffer(substream, true);
|
|
|
|
}
|
2013-10-30 14:39:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void DefinitionNode::load(PackStream *stream) {
|
2015-08-13 21:46:50 +00:00
|
|
|
int children_count;
|
|
|
|
|
|
|
|
stream->read(&children_count);
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i < children_count; i++) {
|
2015-12-10 23:36:50 +00:00
|
|
|
string child_name = stream->readString();
|
2015-08-13 21:46:50 +00:00
|
|
|
|
|
|
|
int child_size;
|
|
|
|
stream->read(&child_size);
|
|
|
|
|
|
|
|
DefinitionNode *child = findChildByName(child_name);
|
2015-11-09 21:30:46 +00:00
|
|
|
if (child) {
|
2015-08-13 21:46:50 +00:00
|
|
|
// TODO type check
|
|
|
|
child->load(stream);
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-08-13 21:46:50 +00:00
|
|
|
// TODO Ask subclass if it can instanciate a child
|
|
|
|
// Else skip length of unknown child
|
|
|
|
stream->skipBytes(child_size);
|
2015-12-13 19:08:38 +00:00
|
|
|
Logs::warning("Definition") << "Skipped unknown child '" << child_name << "'" << endl;
|
2015-08-13 21:46:50 +00:00
|
|
|
}
|
2013-10-30 14:39:56 +00:00
|
|
|
}
|
2013-10-30 11:46:18 +00:00
|
|
|
}
|
2013-10-31 16:59:18 +00:00
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void DefinitionNode::copy(DefinitionNode *destination) const {
|
|
|
|
if (destination->getTypeName() == getTypeName()) {
|
2015-08-16 21:01:56 +00:00
|
|
|
destination->setName(name);
|
2015-11-09 21:30:46 +00:00
|
|
|
for (auto &child : children) {
|
2015-08-23 23:23:05 +00:00
|
|
|
DefinitionNode *dest_child = destination->findChildByName(child->name);
|
2015-11-09 21:30:46 +00:00
|
|
|
if (dest_child) {
|
2015-08-23 23:23:05 +00:00
|
|
|
child->copy(dest_child);
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-12-13 19:08:38 +00:00
|
|
|
Logs::warning("Definition") << "Can't copy to child " << child->name << " of "
|
|
|
|
<< destination->getTypeName() << endl;
|
2015-08-23 23:23:05 +00:00
|
|
|
}
|
|
|
|
}
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-12-13 19:08:38 +00:00
|
|
|
Logs::error("Definition") << "Can't copy from " << getTypeName() << " to " << destination->getTypeName()
|
|
|
|
<< endl;
|
2015-08-16 21:01:56 +00:00
|
|
|
}
|
2013-10-31 16:59:18 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void DefinitionNode::validate() {
|
|
|
|
for (auto child : children) {
|
2013-12-10 21:32:58 +00:00
|
|
|
child->validate();
|
2013-10-31 16:59:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void DefinitionNode::addChild(DefinitionNode *child) {
|
2015-12-10 23:36:50 +00:00
|
|
|
if (find(children.begin(), children.end(), child) == children.end()) {
|
2013-12-10 21:32:58 +00:00
|
|
|
children.push_back(child);
|
2013-10-31 16:59:18 +00:00
|
|
|
child->parent = this;
|
|
|
|
child->root = this->root;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void DefinitionNode::removeChild(DefinitionNode *child) {
|
2015-12-10 23:36:50 +00:00
|
|
|
vector<DefinitionNode *>::iterator it = find(children.begin(), children.end(), child);
|
2015-11-09 21:30:46 +00:00
|
|
|
if (it != children.end()) {
|
2015-08-12 15:02:27 +00:00
|
|
|
child->parent = NULL;
|
2013-12-10 21:32:58 +00:00
|
|
|
children.erase(it);
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-12-13 19:08:38 +00:00
|
|
|
Logs::warning("Definition") << "Trying to remove not found child '" << child->name << "' from '" << name << "'"
|
|
|
|
<< endl;
|
2013-12-10 21:32:58 +00:00
|
|
|
}
|
2013-10-31 16:59:18 +00:00
|
|
|
}
|
2015-08-13 21:46:50 +00:00
|
|
|
|
2015-12-15 23:38:28 +00:00
|
|
|
DefinitionNode *DefinitionNode::findChildByName(const string &name) const {
|
2015-11-09 21:30:46 +00:00
|
|
|
for (auto child : children) {
|
|
|
|
if (child->name == name) {
|
2015-08-13 21:46:50 +00:00
|
|
|
return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
int DefinitionNode::getStreamSize() const {
|
2015-08-13 21:46:50 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2015-08-16 22:29:54 +00:00
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void DefinitionNode::addDiff(const DefinitionDiff *diff) {
|
2015-08-16 22:29:54 +00:00
|
|
|
assert(diff->getTypeName() == type_name);
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (root && root->diffs) {
|
2015-08-16 22:29:54 +00:00
|
|
|
root->diffs->addDiff(this, diff);
|
2015-11-20 00:07:31 +00:00
|
|
|
} else {
|
2015-12-16 00:32:25 +00:00
|
|
|
// TODO Apply diff ?
|
2015-11-20 00:07:31 +00:00
|
|
|
delete diff;
|
2015-08-16 22:29:54 +00:00
|
|
|
}
|
|
|
|
}
|