#include "libParse.h"
#include "SyntaxBase.h"
#include "StoryUnitDocumentParser.h"
#include <QFileInfo>

using namespace Parse;
using namespace Lex;
using namespace Syntax;
using namespace Parse::Result;

namespace Parse {
    class Unknown : public DesNode
    {
    public:
        explicit Unknown(DocCore *ins) : DesNode(ins, NODE_UNKNOWNHOST, nullptr){}

        // 通过 DesNode 继承
        virtual bool check(QList<ErrorMessage>&) const override
        {
            return true;
        }
        virtual QString toString() const override
        {
            return QString();
        }

        void xClear(){
            clear_refers();
        }
    };
}

ErrorMessage::ErrorMessage(const DesNode *obj): object(obj){}

NamedNode::NamedNode(const QString &name, DocCore *core, int type, DesNode *pnode)
    : Result::DesNode(core, type, pnode), name_store(name){}

QList<QString> NamedNode::name() const
{
    return QList<QString>() << name_store;
}

DesNode::DesNode(DocCore *core, int type_value, DesNode *pnode)
    : doc_store(core), type_value(type_value), parent_node(pnode)
{

}

DesNode::~DesNode()
{
    for(auto &i : children())
        delete i;
    children_nodes.clear();
}

int DesNode::depth() const
{
    if(parent_node==nullptr)
        return 0;
    return parent_node->depth() + 1;
}

DocCore *DesNode::doc() const
{
    return this->doc_store;
}

int DesNode::typeValue() const
{
    return type_value;
}

DesNode *DesNode::parent() const
{
    return parent_node;
}

void DesNode::appendChild(DesNode *ins)
{
    children_nodes << ins;
}

QList<DesNode *> DesNode::children() const
{
    return children_nodes;
}

void DesNode::registerWords(Words *ins)
{
    words_collection << ins;
}

QList<Words *> DesNode::refered() const
{
    return words_collection;
}

void DesNode::clear_refers()
{
    this->words_collection.clear();
}



ParseCore::ParseCore()
{

}

void ParseCore::registerDoc(DocCore *ins)
{
    if(!doc_nodes.contains(ins))
        doc_nodes << ins;
}

QList<DocCore *> ParseCore::allDocuments() const
{
    return doc_nodes;
}

DocCore *ParseCore::queryDocument(const QFileInfo &file_src) const
{
    for(auto &d : doc_nodes){
        auto anchor_file = d->filePath();
        if(anchor_file == file_src.absoluteFilePath())
            return d;
    }
    return nullptr;
}

void ParseCore::deleteDocument(DocCore *ins)
{
    ins->clear();
    doc_nodes.removeAll(ins);
    delete ins;
}

void ParseCore::clear()
{
    for(auto &ins : doc_nodes) {
        ins->clear();
        delete ins;
    }

    doc_nodes.clear();
}

QList<DesNode *> ParseCore::allStoryChains() const
{
    QList<Result::DesNode*> retlist;

    for(auto &k : doc_nodes)
        if(k->docType() == DocType::STORYCHAIN)
            for(auto &n : k->syntaxNodes())
                if(n->typeValue()==NODE_STORYCHAIN)
                    retlist << n;

    return retlist;
}

QList<Result::DesNode*> ParseCore::queryStoryChain(const QString &name) const
{
    QList<Result::DesNode*> retlist;

    for(auto &xnode : allStoryChains())
        if(static_cast<NamedNode*>(xnode)->name()[0] == name)
            retlist << xnode;

    return retlist;
}

QList<Result::DesNode*> ParseCore::queryStoryPoint(DesNode *chain, const QString &name) const
{
    QList<Result::DesNode*> retlist;
    for(auto &n : chain->children())
        if(n->typeValue() == NODE_STORYPOINT &&
                static_cast<NamedNode*>(n)->name()[0] == name)
            retlist << n;

    return retlist;
}

QList<DesNode *> ParseCore::allStoryUnits() const
{
    QList<Result::DesNode*> retlist;

    for(auto &k : doc_nodes)
        if(k->docType() == DocType::STORYUNIT)
            for(auto &n : k->syntaxNodes()){
                if(n->typeValue()==NODE_STORYUNIT)
                    retlist << n;
            }

    return retlist;
}

QList<Result::DesNode*> ParseCore::queryStoryUnit(const QString &name) const
{
    QList<Result::DesNode*> retlist;

    for(auto &k : allStoryUnits())
        if(static_cast<NamedNode*>(k)->name()[0] == name)
            retlist << k;

    return retlist;
}

QList<Result::DesNode*> ParseCore::queryStoryFragment(DesNode *unit, const QString &name) const
{
    QList<Result::DesNode*> retlist;
    for(auto &n : unit->children())
        if(n->typeValue() == NODE_STORYFRAGMENT &&
                static_cast<NamedNode*>(n)->name()[0] == name)
            retlist << n;
    return retlist;
}

QList<std::pair<NamedNode *, double> > ParseCore::queryOrdersFragment() const
{
    QList<std::pair<NamedNode*, double>> node_list;
    auto units = allStoryUnits();
    for(auto &uins : units){
        auto children = uins->children();
        for(auto &c : children){
            if(c->typeValue() != NODE_STORYFRAGMENT)
                continue;

            bool isvalid;
            auto fragment = static_cast<NodeStoryFragment*>(c);
            node_list << std::make_pair(fragment, fragment->orderValue(isvalid));
        }
    }

    std::sort(node_list.begin(), node_list.end(),
              [](const std::pair<NamedNode*, double> &a, const std::pair<NamedNode*, double> &b)->bool{
        bool valid;
        auto val_a = static_cast<NodeStoryFragment*>(a.first)->orderValue(valid);
        auto val_b = static_cast<NodeStoryFragment*>(b.first)->orderValue(valid);
        return val_a < val_b;
    });

    return node_list;
}

QList<DesNode *> ParseCore::allStoryBoards() const
{
    QList<Result::DesNode*> retlist;

    for(auto &k : doc_nodes)
        if(k->docType() == DocType::STORYBOARD)
            for(auto &n : k->syntaxNodes()){
                if(n->typeValue() == NODE_STORYBOARD)
                    retlist << n;
            }

    return retlist;
}

QList<Result::DesNode*> ParseCore::queryStoryBoard(const QString &name) const
{
    QList<Result::DesNode*> retlist;

    for(auto &it : allStoryBoards())
        if(static_cast<NamedNode*>(it)->name()[0] == name)
            retlist << it;

    return retlist;
}

QList<DesNode *> ParseCore::queryStoryFragmentRefer(DesNode *unit, const QString &name) const
{
    QList<Result::DesNode*> retlist;
    for(auto &it : unit->children()){
        if(it->typeValue() == NODE_FRAGMENTREFERENCE && static_cast<NamedNode*>(it)->name()[0] == name)
            retlist << it;
    }

    return retlist;
}

QList<DesNode *> ParseCore::allStoryConcept() const
{
    QList<DesNode*> rets;

    for(auto &it : doc_nodes){
        if(it->docType() == DocType::STORYCONCEPTS)
            for(auto n : it->syntaxNodes())
                if(n->typeValue() == NODE_STORYCONCEPT)
                    rets << n;
    }

    return rets;
}

QList<DesNode *> ParseCore::queryStoryConcept(const QString &name) const
{
    QList<DesNode*> rets;
    for(auto &it : allStoryConcept()){
        if(static_cast<NamedNode*>(it)->name()[0] == name)
            rets << it;
    }

    return rets;
}

QList<DesNode *> ParseCore::queryStoryStrongPoint(DesNode *concept, const QString &name) const
{
    QList<DesNode*> rets;
    for(auto &it : concept->children()){
        if(it->typeValue() == NODE_STORYSTRONGPOINT &&
                static_cast<NamedNode*>(it)->name()[0] == name)
            rets << it;
    }

    return rets;
}

QList<DesNode *> ParseCore::queryStoryDepiction(const QString &name) const
{
    QList<Result::DesNode*> retlist;

    for(auto &it : doc_nodes) {
        if(it->docType() == DocType::STORYOUTLINES)
            for(auto &n : it->syntaxNodes())
                if(n->typeValue() == NODE_STORYDEPICTION &&
                        static_cast<NamedNode*>(n)->name()[0] == name)
                    retlist << n;
    }

    return retlist;
}


Words::Words(Result::DesNode *host, DocCore *doc, const QString & value, int row, int col)
    : value_store(value), row_store(row), col_store(col), desnode_store(host), docpresent_store(doc)
{
    host->registerWords(this);
}

int Words::row() const
{
    return row_store;
}

int Words::column() const
{
    return col_store;
}

int Words::length() const
{
    return value_store.length();
}

DesNode * Words::host() const
{
    return desnode_store;
}

DocCore * Words::doc() const
{
    return docpresent_store;
}

QString Words::toString() const
{
    return value_store;
}

DocCore::DocCore(ParseCore * core, DocType type, const QFileInfo & path, const QString &doc_name)
    : unknown_host(new Unknown(this)), core_store(core), doc_name(doc_name),
      file_path_store(path.absoluteFilePath()), type_store(type)
{
}

DesNode * DocCore::unknowns() const
{
    return unknown_host;
}

ParseCore * DocCore::core() const
{
    return core_store;
}

DocType DocCore::docType() const
{
    return type_store;
}

QString DocCore::filePath() const
{
    return file_path_store;
}

QString DocCore::docName() const
{
    return doc_name;
}

void DocCore::clear()
{
    for(auto &it : words_store)
        delete it;
    words_store.clear();

    for(auto &it : root_nodes)
        delete it;
    root_nodes.clear();

    static_cast<Unknown*>(unknown_host)->xClear();
}

int DocCore::append(Words * ins)
{
    words_store << ins;

    return 0;
}

QList<Words *> DocCore::getWords(int row, int col) const
{
    QList<Words*> list;
    for (auto it : words_store)
        if (it->row() == row){
            if(col >= 0 && it->column() <= col && it->column() + it->length() >= col)
                list << it;
            else{
                list << it;
            }
        }

    return list;
}

int DocCore::append(DesNode *ins)
{
    this->root_nodes.append(ins);
    return 0;
}

QList<DesNode *> DocCore::syntaxNodes() const
{
    return this->root_nodes;
}
