/* 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/.
 *
 * contextrule.cpp
 *
 *  Created on: Jan 2, 2016
 *      Author: pgess <v.melnychenko@xreate.org>
 */

/**
 * \file    contextrule.h
 * \brief   Context rules support. See more on [context rules](/w/concepts/context#context-rules)
 */

#include "contextrule.h"
#include "clasplayer.h"
#include "analysis/aux.h"

#include <boost/format.hpp>

using namespace xreate;
using namespace std;

ContextRule::ContextRule(const Expression& rule) {
	assert(rule.op == Operator::CONTEXT_RULE);
	assert(rule.operands.size() == 3);

	head = rule.operands.at(0);
	guards = rule.operands.at(1);
	body = rule.operands.at(2);
}

std::string
ContextRule::compile(const ScopePacked& scopeId) const{

	const string prolog =
	"        %context rule visibility implemenetation\n"
	"context_rule_visibility(X, Y) :- X=Y, scope(X), scope(Y).\n"
	"context_rule_visibility(X, Y) :- cfa_parent(X, scope(Y)), scope(X), scope(Y).\n";

	list<string>repHead_ = xreate::analysis::compile(head);
	assert(repHead_.size() == 1);

	list<string>repGuards_ = xreate::analysis::compile(guards);
	assert(repGuards_.size() == 1);

	list<string>repBody_ = xreate::analysis::compile(body);
	assert(repBody_.size() == 1);

	const std::string& atomBindingScope = Config::get("clasp.bindings.scope");
	boost::format formatContextVisibility("context_rule_visibility(ScopeX, %1%)");
	boost::format formatScopeBind(atomBindingScope + "(ScopeX, %1%, Linkage)");

	const string& repHead  = str(formatScopeBind % repHead_.front());
	const string& repGuards  = str(formatScopeBind % repGuards_.front());
	const string& repVisibility  = str(formatContextVisibility % scopeId);

	boost::format formatRule("%1%:- %2%, %3%, %4%.");
	return prolog + str(formatRule % repHead % repGuards % repBody_.front() % repVisibility);
}
