#include "manager_docs.h"
#include "DocsManager.h"
#include "keywordshighlighter.h"

using namespace Components;
using namespace Core;
using namespace DataModel;

DocumentsManager::DocumentsManager(AppCore *src,
                                   Project::ProjectManager *project,
                                   PresentHost *direct_con)
    : rtcore(src), pjtins(project), present_ui(direct_con) {}

Project::ProjectManager *DocumentsManager::projectManager() const
{
    return pjtins;
}

void DocumentsManager::newPackage(const Route &link)
{
    pjtins->newPackage(link.links());
}

void DocumentsManager::newPackage(const Route &group, const QString &name)
{
    newPackage(group|name);
}

QList<QString> DocumentsManager::fileTypes() const
{
    QList<QString> all_types;
    for(auto &it : rtcore->allViews())
        all_types.append(it->suffixes());

    all_types.removeAll("*");
    return all_types;
}

void DocumentsManager::newFile(const Route &group_path, const QString &name, const QString &suffix)
{
    auto list = rtcore->extensions(suffix);
    QDir root = pjtins->projectDir();

    auto rst = list.first()->create(root, name, suffix);
    if(std::get<0>(rst)){
        auto rpath = root.relativeFilePath(std::get<1>(rst));
        auto idx = pjtins->signFile(converter(group_path), name, rpath);
        openFile(converter(idx));
    }
    else{
        throw new SimpleException("无法创建文件：" + name);
    }
}

QModelIndex DocumentsManager::converter(const Route &path)
{
    auto path_list = path.links();
    auto itor_node = pjtins->model()->item(0);
    while (path_list.size() > 1) {
        auto item = path_list.takeAt(1);
        int idx = 0;
        for(; idx<itor_node->rowCount(); ++idx){
            if(itor_node->child(idx)->text() == item){
                itor_node = itor_node->child(idx);
                break;
            }
        }

        if (idx == itor_node->parent()->rowCount())
            throw new SimpleException("指定的path非法：/"+ path.links().join("/"));
    }
    return itor_node->index();
}

Route DocumentsManager::converter(const QModelIndex &index)
{
    Route path;
    auto item = pjtins->model()->itemFromIndex(index);
    while (item != nullptr) {
        path.prepend(item->text().trimmed());
        item = item->parent();
    }

    return path;
}

void DocumentsManager::removeNode(const Route &node_path)
{
    auto node_mindex = converter(node_path);

    auto activie_file_nodes = actives();
    auto file_nodes = pjtins->filesGather(node_mindex);

    QList<Route> path_buff;
    for(auto &n : file_nodes){
        auto target = converter(n);
        if(activie_file_nodes.contains(target))
            path_buff << target;
    }

    close(path_buff);
    pjtins->deleteTarget(node_mindex);
}

void DocumentsManager::renameNode(const Route &node_path, const QString &name)
{
    pjtins->rename(converter(node_path), name);

    auto activie_file_nodes = actives();
    if(activie_file_nodes.contains(node_path)){
        auto inst = activePresentOf(node_path);
        inst->applySetting(name, rtcore);
        present_ui->active(node_path);
    }
}

void DocumentsManager::openFile(const Route &path_node)
{
    auto info = pjtins->queryInfo(converter(path_node));
    if(!info.isFile())
        throw new SimpleException("打开的节点不是文件节点");

    if(actives().contains(path_node)){
        doc_openning[path_node]->applySetting(path_node.links().last(), rtcore);
        present_ui->active(path_node);
        return;
    }

    auto list = rtcore->extensions(info.suffix());
    auto nview = list.first()->newInst();
    nview->load(info);
    nview->applySetting(path_node.links().last(), rtcore);

    doc_openning[path_node] = nview;
    present_ui->append(nview, path_node);

    functions_build[nview] = [this, nview](const QString &file_path) {
        auto nv = dynamic_cast<MakeTools::CompileFeature *>(nview);
        auto content = nv->getText();
        rtcore->getMakeCore()->compileSource(file_path, content, nview->name());
    };

    functions_render[nview] = [nview, this](const QString &) {
        QObject::disconnect(nview, &MakeTools::FilePresent::dataChanged, nullptr, nullptr);

        auto nv = dynamic_cast<Enhancement::HighlightFeature *>(nview);
        nv->renderRepeat();

        auto func_build = functions_build[nview];
        auto func_render = functions_render[nview];
        QObject::connect(nview, &MakeTools::FilePresent::dataChanged, func_build);
        QObject::connect(nview, &MakeTools::FilePresent::dataChanged, func_render);
    };

    auto flags = nview->features();
    // 编译机制 =========================================
    if (flags.testFlag(MakeTools::FilePresent::Feature::Compile)) {
        QObject::connect(nview, &MakeTools::FilePresent::dataChanged, functions_build[nview]);
    }

    // 高亮机制 =========================================
    if (flags.testFlag(MakeTools::FilePresent::Feature::HighLight)) {
        auto nv = dynamic_cast<Enhancement::HighlightFeature *>(nview);
        nv->contexBinding(rtcore);

        QObject::connect(nview, &MakeTools::FilePresent::dataChanged, functions_render[nview]);
    }
}

QList<Route> DocumentsManager::actives() const { return doc_openning.keys(); }

MakeTools::FilePresent *DocumentsManager::activePresentOf(const Route &node_path)
{
    return doc_openning[node_path];
}

void DocumentsManager::save(const QList<Route> &docs_path)
{
    auto actives_paths = this->actives();
    for(auto &idx_path : docs_path)
        if(actives_paths.contains(idx_path))
            activePresentOf(idx_path)->saveAs();
}

void DocumentsManager::close(const QList<Route> &doc_paths)
{
    auto actives = this->actives();
    for(auto &idx : doc_paths)
        if(actives.contains(idx)){
            auto inst = activePresentOf(idx);
            inst->saveAs();

            present_ui->remove(idx);
            delete inst;
            doc_openning.remove(idx);
        }
}

Route DocumentsManager::pathOf(MakeTools::FilePresent *ins) const
{
    return doc_openning.key(ins);
}

Route DocumentsManager::pathOf(const QModelIndex &p) const
{
    if(!p.isValid())
        throw new SimpleException("传入非法QModelIndex");

    auto item = projectManager()->model()->itemFromIndex(p);
    auto proot = projectManager()->model()->item(0);

    Route retv;
    while(proot != item){
        retv = retv|item->text();
        item = item->parent();
    }

    return retv;
}

void DocumentsManager::build(bool all_from_disk)
{
    if(!all_from_disk)
        save();

    auto chains = pjtins->filesWithEnds("storychain");
    for(auto &it : chains){
        rtcore->getMakeCore()->compile(std::get<1>(it), std::get<0>(it));
    }

    auto units = pjtins->filesWithEnds("storyunit");
    for(auto &it : units)
        rtcore->getMakeCore()->compile(std::get<1>(it), std::get<0>(it));

    auto storys = pjtins->filesWithEnds("storyboard");
    for(auto &it : storys)
        rtcore->getMakeCore()->compile(std::get<1>(it), std::get<0>(it));

    auto volumes = pjtins->filesWithEnds("storyvolume");
    for(auto &it : volumes)
        rtcore->getMakeCore()->compile(std::get<1>(it), std::get<0>(it));

    auto concepts = pjtins->filesWithEnds("storyconcept");
    for(auto &it : concepts)
        rtcore->getMakeCore()->compile(std::get<1>(it), std::get<0>(it));
}

QString DocumentsManager::name() const
{
    return NAME(DocumentsManager);
}

void DocumentsManager::hasBeenAccepted(const Core::Route &key) {}

void DocumentsManager::hasBeenRemoved(const Core::Route &key) {
    
}

void DocumentsManager::hasBeenClosed(const Core::Route &key) {
    if (!doc_openning.contains(key))
        return;

    auto inst = doc_openning[key];
    inst->widget()->setVisible(false);
    delete inst;
    doc_openning.remove(key);
}
