/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/
 *
 * latereasoning.cpp
 *
 * Author: pgess <v.melnychenko@xreate.org>
 * Created on April 21, 2018, 5:10 PM
 */

#include "xreatemanager.h"
#include "clasplayer.h"
#include <boost/format.hpp>
#include "gtest/gtest.h"

using namespace xreate;

TEST(LateReasoning, test2) {
    FILE* input = fopen("scripts/latereasoning/test2.xreate", "r");
    assert(input != nullptr);

    std::unique_ptr<XreateManager> man(XreateManager::prepare(input));

    int (*main)() = (int (*)())man->run();
    int result = main();

    ASSERT_EQ(3, result);
}

/**
 *   Test plan:
 *     - add late annotation(several variants)
 *     - define late bindings
 *     - get late variant wrt defined bindings
 **/

TEST(LateReasoning, PutAndGetLateAnnotation1) {
    #define FORMATSYMBOL(s) (formatSymb % s.identifier % s.version  % s.scope).str()

    Attachments::init<LateBinding>();
    Attachments::init<versions::VariableVersion>();
    std::unique_ptr<ClaspLayer> clasp(new ClaspLayer());

    std::unique_ptr<CodeScope> scope(new CodeScope(nullptr));
    Symbol symbA = scope->addDefinition(Atom<Identifier_t>("a"), Expression());
    Symbol symbB = scope->addDefinition(Atom<Identifier_t>("b"), Expression());
    Symbol symbC = scope->addDefinition(Atom<Identifier_t>("c"), Expression());
    Symbol symbTarget = scope->addDefinition(Atom<Identifier_t>("target"), Expression());

    SymbolPacked symbpA = clasp->pack(symbA, "a");
    SymbolPacked symbpB = clasp->pack(symbB, "b");
    SymbolPacked symbpC = clasp->pack(symbC, "c");
    SymbolPacked symbpTarget = clasp->pack(symbTarget, "target");

    boost::format formatSymb("s(%1%,%2%,%3%)");
    boost::format formatLateAnnotation("late(%1%, (%2%, %3%, %4%), (%5%, %6%, %7%), %8%).");

    //Add `variant1` variant
    clasp->addRawScript((formatLateAnnotation
        % FORMATSYMBOL(symbpTarget)
        % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC)
        % "guard1" % "guard1" % "guard1"
        % "result(variant1)"
    ). str());

    //Add `result2` variant
    clasp->addRawScript((formatLateAnnotation
        % FORMATSYMBOL(symbpTarget)
        % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC)
        % "guard2" % "guard2" % "guard2"
        % "result(variant2)"
    ). str());

    clasp->run();

    //Define keys
    Attachments::put<LateBinding>(symbA, Expression(Operator::CALL, {Atom<Identifier_t>("guard2")}));
    Attachments::put<LateBinding>(symbB, Expression(Operator::CALL, {Atom<Identifier_t>("guard2")}));
    Attachments::put<LateBinding>(symbC, Expression(Operator::CALL, {Atom<Identifier_t>("guard2")}));

    //Fetch late annotation
    ReasoningModel model = clasp->queryCompiled();
    StaticModel answer = model.queryLate("result", symbpTarget);
    ASSERT_EQ(1, answer.size());

    std::tuple<std::string> answerParsed = clasp->parse<std::string>(answer.begin()->second);

    ASSERT_STREQ("variant2", std::get<0>(answerParsed).c_str());
}