#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 isNewer(std::int64_t a, std::int64_t b, std::int64_t tolNs) {
return (a - b) > 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;
r.diffPaths.insert(it.key());
r.mergeList.append(s);
if (isNewer(u->mtimeNs, s.mtimeNs, f.toleranceNs))
r.destNewerPaths.insert(it.key());
}
if (sizeDiff || timeDiff || f.display == FilterSettings::Display::All)
r.sourceRows.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;
}
}