/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * File:   polymorph.cpp
 * Author: pgess <v.melnychenko@xreate.org>
 *
 * Created on November 9, 2017, 12:14 PM
 */

#include "polymorph.h"
#include "aux/transcend-decorators.h"
using namespace std;
namespace xreate{
namespace polymorph{

const std::string atomPolymorph = "dfa_callguard";

void
PolymorphQuery::init(TranscendLayer* transcend) {
    __transcend = transcend;

    StaticModel queryResult = transcend->query(atomPolymorph);
    if (queryResult.size()) {
        for (auto entry : queryResult) {
            auto answer = TranscendLayer::parse<SymbolNode, Gringo::Symbol>(entry.second);
            SymbolNode symbCaller = std::get<0>(answer);
            SymbolGeneralized symbCallerUnpacked = transcend->unpack(symbCaller);

            __cacheEarlyReasoning.emplace(symbCallerUnpacked, entry.second);
        }
    }

    auto transcendLate =
        Decorators<LateReasoningTranscendDecoratorTag>::getInterface(__transcend);
    latereasoning::LateAnnotationsGroup group = transcendLate->queryLate(atomPolymorph);

    for(auto entry : group.annotations) {
        auto targetWrapper = Gringo::Symbol::createTuple(Gringo::SymSpan{&entry.first, 1});
        auto targetSP = __transcend->parse<SymbolNode>(targetWrapper);
        SymbolGeneralized targetS = __transcend->unpack(std::get<0>(targetSP));
        __cacheLateReasoning.emplace(targetS, entry.second);
    }
}

latereasoning::LateAnnotation
PolymorphQuery::get(const Expression& e) const {
    SymbolGeneralized targetS = Attachments::exists<SymbolAlias>(e) ?
        SymbolGeneralized(Attachments::get<SymbolAlias>(e))
        : SymbolGeneralized(SymbolAnonymous{e.id});

    if (__cacheEarlyReasoning.count(targetS)) {
        return latereasoning::LateAnnotation(__cacheEarlyReasoning.at(targetS));
    }

    if (__cacheLateReasoning.count(targetS)) {
        return __cacheLateReasoning.at(targetS);
    }

    assert(false && "Can't find a guard");
}

Expression
PolymorphQuery::getValue(const Gringo::Symbol& symbol) const {
    auto result = __transcend->parse<Gringo::Symbol, Expression>(symbol);
    return std::get<1>(result);
}

}
} //end of xreate::polymorph
