#include "XSyntaxBase.h"

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

Link::Link(const QString & alias, Element * elm)
    : alias_name(alias), host_ins(elm), tail_mark(false) {}

QString Link::aliasName() const { return alias_name; }

QString Link::refer() const
{
    return name(this->aliasName());
}

QString Link::name(const QString & s)
{
    QRegExp exp("^([^0-9]+)[0-9]*$");
    if (exp.indexIn(s) == -1)
        return "";
    return exp.capturedTexts()[1];
}

Element * Link::host() const { return host_ins; }

bool Link::tailTest() const { return tail_mark; }

void Link::markTail(bool v)
{
    tail_mark = v;
}

void Link::appendNext(Link * ins) { next_inss << ins; }

QList<Link*> Link::nextElements() const { return next_inss; }

std::tuple<Element::rst_mark, Element::match_len>
Link::linkCheck(const QList<LexResult>& tokens, int offset) const
{
    // 本节点匹配失败，剩余标记长度不足
    if (tokens.size() <= offset)
        return std::make_tuple(false, 0);

    // 节点元素匹配，获取匹配结果
    auto rst0 = host()->elementCheck(tokens, offset);
    if (!std::get<0>(rst0))
        return rst0;

    // 本节点匹配成功，尝试下一节点匹配，调用参数向下传递
    for (auto inss : next_inss) {
        auto rst1 = inss->linkCheck(tokens, offset + std::get<1>(rst0));

        // 随后节点完全匹配，返回累积匹配结果
        if (std::get<0>(rst1))
            return std::make_tuple(true, std::get<1>(rst0) + std::get<1>(rst1));
    }

    // 解析链上的允许结尾，本节点是尾结点则成功，否则失败
    if (tailTest())
        return rst0;
    else
        return std::make_tuple(false, std::get<1>(rst0));
}

/**
* 校验标记序列是否符合语法定义.
*
* \param tokens 标记序列
* \param offset 偏移量
* \return tuple(完全匹配指示，最大匹配长度)
*/
Element::Element(const QString & token)
    : value_store(token) {}


QString Element::name() const
{
    return Link::name(value_store);
}

DefType Element::type() const
{
    return DefType::ELEMENT;
}

std::tuple<Element::rst_mark, Element::match_len>
Element::elementCheck(const QList<LexResult>& tokens, int offset) const
{
    auto u = tokens[offset];

    if (u.Token == name())
        return std::make_tuple(true, 1);
    return std::make_tuple(false, 0);
}

Expression::Expression(const QString & name)
    : Element(name), name_store(name), chain_store(nullptr)
{
}

Link * Expression::parseFlow() const
{
    return chain_store;
}

void Expression::resetLinks(Link * entry)
{
    chain_store = entry;
}

DefType Expression::type() const
{
    return DefType::EXPRESSION;
}

std::tuple<Element::rst_mark, Element::match_len>
Expression::elementCheck(const QList<LexResult>& tokens, int offset) const
{
    if (!chain_store)
        return std::make_tuple(false, 0);

    return chain_store->linkCheck(tokens, offset);
}

ParseRule::ParseRule(XSyntaxBase * host, const QString & rule_name, unsigned short level,
                     std::function<ParseResult(const QList<LexResult>&, int)> exc)
    : enable_state(true), host_ins(host), level_store(level),
      name_store(rule_name), exc_store(exc) {}

int ParseRule::level() const
{
    return level_store;
}

QString ParseRule::name() const
{
    return name_store;
}

void ParseRule::setEnable(bool v)
{
    this->enable_state = v;
}

void Syntax::ParseRule::addExpression(const QString &name, const QList<Elm> &defines)
{
    // 生成表达式实例
    auto exp = host_ins->get_expression(Link::name(name));

    // 逐个构建表达式或者元素
    QList<Link*> link_rebuilds;
    for (auto& def_it : defines) {
        // 校验既有元素回环
        auto size0 = link_rebuilds.size();
        for (auto prv_it : link_rebuilds) {
            if (prv_it->aliasName() == def_it.aliasName()) {
                link_rebuilds << prv_it;
                break;
            }
        }

        // 没有找到元素回环
        if (size0 == link_rebuilds.size()) {
            Link* tins = nullptr;
            if (def_it.type() == DefType::ELEMENT)
                tins = new Link(def_it.aliasName(), host_ins->get_element(def_it.refer()));
            else
                tins = new Link(def_it.aliasName(), host_ins->get_expression(def_it.refer()));

            link_rebuilds << tins;
        }

        // 标记结尾可能性
        if (!link_rebuilds.last()->tailTest())
            link_rebuilds.last()->markTail(def_it.isTail());
    }

    // 匹配链构建
    for (auto idx = 1; idx < link_rebuilds.size(); ++idx) {
        auto prv_it = link_rebuilds[idx - 1];
        prv_it->appendNext(link_rebuilds[idx]);
    }

    exp->resetLinks(link_rebuilds.first());
    expression_list << exp;
}

std::tuple<bool, int> ParseRule::tokensMatch(const QList<LexResult>& token) const
{
    if(enable_state)
        for (auto expx : expression_list) {
            auto result = expx->elementCheck(token, 0);
            if (std::get<0>(result)) {
                return std::make_tuple(true, std::get<1>(result));
            }
        }

    return std::make_tuple(false, 0);
}

ParseResult ParseRule::syntaxTrigger(const QList<LexResult>& srcs, int count) {
    return exc_store(srcs, count);
}

XSyntaxBase::XSyntaxBase(const QString & section, MatchType type)
    : target_type(type), section_name(section), current_level(INT_MAX), current_node(nullptr) {}

ParseRule * XSyntaxBase::addRule(const QString & name, unsigned short level,
                                 std::function<ParseResult(const QList<LexResult>&, int)> exc)
{
    if (!rule_collect.contains(name)) {
        auto rule = new ParseRule(this, name, level, exc);
        rule_collect[name] = rule;
    }
    return rule_collect[name];
}

inline Expression * XSyntaxBase::get_expression(const QString & name) {
    if (!expressions_store.contains(name)) {
        auto u = new Expression(name);
        expressions_store[name] = u;
    }
    return expressions_store[name];
}

inline Element * XSyntaxBase::get_element(const QString & name)
{
    if (!elements_store.contains(name)) {
        auto u = new Element(name);
        elements_store[name] = u;
    }
    return elements_store[name];
}

void XSyntaxBase::addChild(QList<SyntaxParser*> parsers)
{
    this->child_parsers.append(parsers);
}

void XSyntaxBase::docActive(DocCore * ins)
{
    src_ref = ins;
    for (auto &it : children())
        it->docActive(ins);
}

DocCore * XSyntaxBase::docRef() const
{
    return src_ref;
}

bool XSyntaxBase::applied(const QList<LexResult>& seqs)
{
    // 求取最小等级的parse-rule
    ParseRule* first_rule = *rule_collect.cbegin();
    for (auto &rule : rule_collect) {
        if (rule->level() <= first_rule->level())
            first_rule = rule;
    }

    // 执行准入匹配，在最小等级匹配规则上进行匹配结算
    for (auto &rule : rule_collect) {
        if (rule->level() != first_rule->level())
            continue;

        auto result = rule->tokensMatch(seqs);

        if (std::get<0>(result)) {
            current_level = rule->level();
            return true;
        }
    }

    return false;
}

void XSyntaxBase::reset()
{
    // 重置标记
    current_level = INT_MAX;

    for (auto &x : rule_collect)
        if (current_level > x->level())
            current_level = x->level();

    current_node = nullptr;
}

ParseResult XSyntaxBase::parse(QList<LexResult>& seqs)
{
    // 求取符合等级的parse-rule
    QList<ParseRule*> rules_set;
    for (auto &rule : rule_collect) {
        if (rule->level() >= current_level)
            rules_set << rule;
    }

    std::tuple<bool, int, ParseRule*> max_result = std::make_tuple(false, 0, nullptr);
    // 使用符合等级的解析规则解析
    for (auto &rule : rules_set) {
        auto result = rule->tokensMatch(seqs);
        if (std::get<0>(result) && current_level <= rule->level()) {
            current_level = rule->level();
            max_result = std::make_tuple(true, std::get<1>(result), rule);
        }
    }

    if (!std::get<0>(max_result)) {
        if (target_type == MatchType::Outline)
            return ParseResult::Completed;
        return ParseResult::Failed;
    }
    else {                         // 匹配成功
        if (target_type == MatchType::Outline) {
            if (current_node == nullptr) {
                return std::get<2>(max_result)->syntaxTrigger(seqs, std::get<1>(max_result));
            }
            else {
                return ParseResult::Completed;
            }
        }
        else {
            auto xresult = std::get<2>(max_result)->syntaxTrigger(seqs, std::get<1>(max_result));

            if (target_type == MatchType::Entirely) {
                auto count = std::get<1>(max_result);
                while (count--)
                    seqs.removeFirst();
            }
            return xresult;
        }
    }
}

QList<SyntaxParser*> XSyntaxBase::children() const
{
    return child_parsers;
}

void XSyntaxBase::refocusNode(DesNode * ins)
{
    current_node = ins;
}

Expression *XSyntaxBase::set_common_expression(const QString &name, const QList<Defines::Elm> &defines)
{
    if (expressions_store.contains(Link::name(name)))
        return nullptr;

    auto ins = get_expression(Link::name(name));
    // 逐个构建表达式或者元素
    QList<Link*> link_rebuilds;
    for (auto& def_it : defines) {
        // 校验既有元素回环
        auto size0 = link_rebuilds.size();
        for (auto prv_it : link_rebuilds) {
            if (prv_it->aliasName() == def_it.aliasName()) {
                link_rebuilds << prv_it;
                break;
            }
        }

        // 没有找到元素回环
        if (size0 == link_rebuilds.size()) {
            Link* tins = nullptr;
            if (def_it.type() == DefType::ELEMENT)
                tins = new Link(def_it.aliasName(), get_element(def_it.refer()));
            else
                tins = new Link(def_it.aliasName(), get_expression(def_it.refer()));

            link_rebuilds << tins;
        }

        // 标记结尾可能性
        link_rebuilds.last()->markTail(def_it.isTail());
    }

    // 匹配链构建
    for (auto idx = 1; idx < link_rebuilds.size(); ++idx) {
        auto prv_it = link_rebuilds[idx - 1];
        prv_it->appendNext(link_rebuilds[idx]);
    }

    ins->resetLinks(link_rebuilds.first());
    return ins;
}

void XSyntaxBase::resetMatch(MatchType mtype)
{
    this->target_type = mtype;
}

DesNode * XSyntaxBase::currNode() const
{
    return current_node;
}

Elm::Elm(const QString &alias_name, bool tail_mark)
    : name_store(alias_name), tail_mark(tail_mark),
      type_define(DefType::ELEMENT) {}

QString Elm::aliasName() const
{
    return this->name_store;
}

QString Elm::refer() const
{
    return Link::name(this->name_store);
}


bool Elm::isTail() const
{
    return tail_mark;
}

DefType Elm::type() const
{
    return type_define;
}

Exp::Exp(const QString& alias_name, bool tail_mark)
    : Elm(alias_name, tail_mark)
{
    type_define = DefType::EXPRESSION;
}

DefType Exp::type() const
{
    return type_define;
}
