#include "core/Comparator.h"
#include <cstdlib>
#include <QSet>
namespace whittle {
namespace {
bool timeDiffers(std::int64_t a, std::int64_t b, std::int64_t tolNs) {
return std::llabs(a - b) > tolNs;
}
bool sourceIsNewer(std::int64_t src, std::int64_t dst, std::int64_t tolNs) {
return (src - dst) > tolNs;
}
QSet<QString> impliedParents(const QHash<QString, FileRecord>& source) {
QSet<QString> out;
for (auto it = source.constBegin(); it != source.constEnd(); ++it) {
const QString& key = it.key();
for (int p = key.indexOf('/'); p > 0; p = key.indexOf('/', p + 1))
out.insert(key.left(p));
}
return out;
}
}
DiffResult Comparator::compare(const QHash<QString, FileRecord>& source,
const QHash<QString, FileRecord>& usb,
const FilterSettings& f) {
DiffResult r;
for (auto it = source.constBegin(); it != source.constEnd(); ++it) {
const FileRecord& s = it.value();
const auto u = usb.constFind(it.key());
if (u == usb.constEnd()) {
r.sourceRows.append(s);
r.mergeList.append(s);
if (!s.isDir) { ++r.newFileCount; r.newBytes += s.size; }
continue;
}
if (s.isDir) {
if (f.display == FilterSettings::Display::All)
r.sourceRows.append(s);
continue;
}
const bool sizeDiff = f.compareSize && (s.size != u->size);
const bool timeDiff = f.compareTime &&
timeDiffers(s.mtimeNs, u->mtimeNs, f.toleranceNs);
if (sizeDiff || timeDiff) { ++r.diffFileCount; r.diffBytes += s.size; }
if (sizeDiff || timeDiff || f.display == FilterSettings::Display::All)
r.sourceRows.append(s);
if (sourceIsNewer(s.mtimeNs, u->mtimeNs, f.toleranceNs))
r.mergeList.append(s);
}
const QSet<QString> parents = impliedParents(source);
for (auto it = usb.constBegin(); it != usb.constEnd(); ++it) {
if (source.contains(it.key())) continue;
if (it->isDir && parents.contains(it.key())) continue;
r.usbOnlyRows.append(it.value());
}
return r;
}
}