/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2024 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License fro more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Melin Software HB - software@melin.nu - www.melin.nu
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
************************************************************************/
#include "StdAfx.h"
#include "machinecontainer.h"
#include "meos_util.h"
#include "xmlparser.h"
#include "gdioutput.h"
#include "TabAuto.h"
int MachineContainer::AbstractMachine::getInt(const string &v) const {
return _wtoi(getString(v).c_str());
}
const wstring &MachineContainer::AbstractMachine::getString(const string &v) const {
auto res = props.find(v);
if (res != props.end())
return res->second;
return _EmptyWString;
}
vector MachineContainer::AbstractMachine::getVectorInt(const string &v) const {
auto &s = getString(v);
vector sp;
split(s, L",", sp);
vector res(sp.size());
for (size_t j = 0; j < sp.size(); j++)
res[j] = _wtoi(sp[j].c_str());
return res;
}
set MachineContainer::AbstractMachine::getSetInt(const string &v) const {
std::set res;
for (int i : getVectorInt(v)) {
res.insert(i);
}
return res;
}
void MachineContainer::AbstractMachine::set(const string &name, int v) {
if (v != 0)
props[name] = itow(v);
}
void MachineContainer::AbstractMachine::set(const string &name, const vector &v) {
wstring &r = props[name];
for (size_t j = 0; j < v.size(); j++) {
if (j == 0)
r = itow(v[j]);
else
r += L"," + itow(v[j]);
}
}
void MachineContainer::AbstractMachine::load(const xmlobject &data) {
xmlList out;
data.getObjects(out);
for (auto &x : out) {
props[x.getName()] = x.getWStr();
}
}
void MachineContainer::AbstractMachine::save(xmlparser &data) const {
for (auto &p : props) {
data.write(p.first.c_str(), p.second);
}
}
namespace {
string encode(const string &in) {
string out;
out.reserve(in.length());
for (size_t j = 0; j < in.length(); j++) {
if (in[j] == '|' || in[j] == '$' || in[j] == '%') {
out.push_back('%');
if (in[j] == '|')
out.push_back('1');
else if (in[j] == '$')
out.push_back('2');
else if (in[j] == '%')
out.push_back('3');
}
else
out.push_back(in[j]);
}
return out;
}
string decode(const string &in) {
string out;
out.reserve(in.length());
for (size_t j = 0; j < in.length(); j++) {
if (in[j] == '%') {
j++;
if (j < in.length()) {
if (in[j] == '1')
out.push_back('|');
else if (in[j] == '2')
out.push_back('$');
else if (in[j] == '3')
out.push_back('%');
}
}
else
out.push_back(in[j]);
}
return out;
}
}
void MachineContainer::AbstractMachine::load(const string &data) {
vector parts;
split(data, "|", parts);
for (int j = 0; j < parts.size(); j+=2) {
const wstring &w = gdioutput::fromUTF8(decode(parts[j + 1]));
props[parts[j]] = w;
}
}
string MachineContainer::AbstractMachine::save() const {
string out;
for (auto &p : props) {
if (!out.empty())
out += "|";
out.append(p.first);
out += "|";
out.append(encode(gdioutput::toUTF8(p.second)));
}
return out;
}
void MachineContainer::AbstractMachine::set(const string &name, const wstring &v) {
if (!v.empty())
props[name] = v;
}
vector> MachineContainer::enumerate() const {
vector> res;
for (auto v : machines)
res.push_back(v.first);
return res;
}
void MachineContainer::load(const xmlobject &data) {
xmlList out;
data.getObjects("Machine", out);
for (auto &m : out) {
string type;
wstring tag;
m.getObjectString("type", type);
m.getObjectString("name", tag);
if (!type.empty() && !tag.empty()) {
auto res = machines.emplace(make_pair(type, tag), MachineContainer::AbstractMachine());
if (res.second)
res.first->second.load(m);
}
}
}
void MachineContainer::save(xmlparser &data) {
for (auto &m : machines) {
vector p({ wstring(L"type"), gdioutput::widen(m.first.first),
wstring(L"name"), m.first.second });
data.startTag("Machine", p);
m.second.save(data);
data.endTag();
}
}
void MachineContainer::load(const string &data) {
vector parts;
split(data, "$", parts);
if ((parts.size() % 3) != 0) {
// Data is corrupt. Repair by delete...
if (parts.size() > 3)
parts.resize(3);
}
machines.clear();
for (size_t j = 0; j + 2 < parts.size(); j+=3) {
const string &type = parts[j];
if (AutoMachine::getType(type) == Machines::Unknown)
continue;
wstring tag = gdioutput::fromUTF8(decode(parts[j + 1]));
auto res = machines.emplace(make_pair(type, tag), MachineContainer::AbstractMachine());
if (res.second)
res.first->second.load(parts[j+2]);
}
}
string MachineContainer::save() {
vector ml;
ml.reserve(machines.size() * 3);
size_t tSize = 0;
for (auto &m : machines) {
ml.push_back(m.first.first);
tSize += ml.back().length() + 2;
ml.push_back(encode(gdioutput::toUTF8(m.first.second)));
tSize += ml.back().length() + 2;
ml.push_back(m.second.save());
tSize += ml.back().length() + 2;
}
string out;
out.reserve(tSize);
for (const string & m : ml) {
if (!out.empty())
out.append("$");
out.append(m);
}
return out;
}
void MachineContainer::rename(const string& type, const wstring& oldName, const wstring& newName) {
if (newName != oldName) {
auto res = machines.find(make_pair(type, oldName));
if (res != machines.end()) {
machines.emplace(make_pair(type, newName), res->second);
machines.erase(res);
}
}
}