#include "directorynode.h"
using Xybrid::UI::DirectoryNode;

#include <algorithm>
#include <functional>

#include <QStringBuilder>
#include <QCollator>
#include <QHash>

DirectoryNode::DirectoryNode(DirectoryNode* parent, QString name, QVariant data) {
    this->parent = parent;
    this->name = name;
    this->data = data;
    if (parent) {
        index = parent->children.size();
        parent->children.push_back(this);
    }
}

DirectoryNode::~DirectoryNode() {
    qDeleteAll(children);
}

void DirectoryNode::clear() {
    qDeleteAll(children);
    children.clear();
}

void DirectoryNode::sortChildren() {
    QCollator col;
    col.setNumericMode(true);
    std::sort(children.begin(), children.end(), [&col](auto a, auto b) {
        if (a->isDirectory() != b->isDirectory()) return a->isDirectory();
        return col.compare(a->name, b->name) < 0;
    });
    for (int i = 0; i < children.size(); i++) children[i]->index = i;
}

void DirectoryNode::sortTree() {
    sortChildren();
    for (auto c : children) c->sortTree();
}

DirectoryNode* DirectoryNode::subdir(QString name) {
    if (name.isEmpty()) return this;
    QString first = name.section('/', 0, 0, QString::SectionSkipEmpty);
    QString rest = name.section('/', 1, -1, QString::SectionSkipEmpty);
    DirectoryNode* sd = nullptr;
    for (auto c : children) if (c->isDirectory() && c->name == first) { sd = c; break; }
    if (!sd) sd = new DirectoryNode(this, first);
    return sd->subdir(rest);
}

DirectoryNode* DirectoryNode::placeData(QString name, QVariant data) {
    QString dir = name.section('/', 0, -2, QString::SectionSkipEmpty);
    QString file = name.section('/', -1, -1, QString::SectionSkipEmpty);
    return new DirectoryNode(subdir(dir), file, data);
}

QString DirectoryNode::path() const {
    if (!parent || parent->name.isEmpty()) return name;
    if (name.isEmpty()) return parent->path(); // nameless nodes don't add an extra /
    return parent->path() % "/" % name;
}

DirectoryNode* DirectoryNode::findPath(QString path) {
    if (path.isEmpty()) return this;
    QString first = path.section('/', 0, 0, QString::SectionSkipEmpty);
    QString rest = path.section('/', 1, -1, QString::SectionSkipEmpty);
    DirectoryNode* sd = nullptr;
    for (auto c : children) if (c->name == first) { sd = c; break; }
    if (!sd) return nullptr;
    return sd->findPath(rest);
}

DirectoryNode* DirectoryNode::findData(const QVariant& d) {
    if (data == d) return this;
    for (auto c : children) {
        if (auto cd = c->findData(d); cd) return cd;
    }
    return nullptr;
}

bool DirectoryNode::isChildOf(Xybrid::UI::DirectoryNode* dn) const {
    auto c = this;
    forever {
        if (!c) return false;
        if (c == dn) return true;
        c = c->parent;
    }
}

void DirectoryNode::treeExec(const std::function<void(Xybrid::UI::DirectoryNode*)>& f) {
    for (auto c : children) c->treeExec(f);
    f(this);
}

/*void DirectoryNode::placeData(const QVector<std::pair<QString, QVariant>>& data) {
    QHash<QString, DirectoryNode*> dirs; // lookup table for directories
    dirs[""] = this;
}*/
