#include "cfgpass.h"
#include <boost/range/iterator_range_core.hpp>
using namespace std;
using namespace xreate;



void
CFGPass::initSignatures(){
	auto range = man->root->__interfacesData.equal_range(CFA);
	for (auto i = range.first; i!= range.second; ++i){
		__signatures.emplace(i->second.op, i->second);
	}
}

void CFGPass::run(){
	initSignatures();

	return AbstractPass::run();
}

void
CFGPass::finish()
{
    man->clasp->setCFAData(move(__context.graph));

    return AbstractPass::finish();
}

void
CFGPass::processFnCall(ManagedFnPtr function, PassContext context)
{
	ClaspLayer* clasp = man->clasp;
	__context.graph.addCallConnection(clasp->pack(context.scope), function->getName());

	return AbstractPass::processFnCall(function, context);
}

void
CFGPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){
	ClaspLayer* clasp = man->clasp;

	CodeScope* scopeParent = context.scope;
	ScopePacked scopeId = clasp->pack(scope);

	if (scopeParent){
		__context.graph.addParentConnection(scopeId, clasp->pack(scopeParent));
	} else {
		__context.graph.addParentConnection(scopeId, context.function->getName());
	}

		//TEST scope annotations
		//SECTIONTAG context gather scope annotations
	__context.graph.addScopeAnnotations(scopeId, scope->tags);

	__context.graph.addContextRules(scopeId, scope->contextRules);

	return AbstractPass::process(scope, context, hintBlockDecl);
}

//TEST scope annotations via scheme
void
CFGPass::process(const Expression& expression, PassContext context, const std::string& varDecl){
	ClaspLayer* clasp = man->clasp;

	if (expression.__state == Expression::COMPOUND){
		Operator  op= expression.op;

		if (__signatures.count(op)) {
			assert(expression.blocks.size());

			for (const auto& scheme: boost::make_iterator_range(__signatures.equal_range(expression.op))) {
					__context.graph.addScopeAnnotations(clasp->pack(expression.blocks.front()), scheme.second.getOperands());
			}
		}
	}

	return AbstractPass::process(expression, context, varDecl);
}

void
CFGPass::process(ManagedFnPtr function)
{
	__context.graph.addFunctionAnnotations(function->getName(), function->getAnnotations());
	return AbstractPass::process(function);
}

CFGPass::CFGPass(PassManager* manager)
	: AbstractPass(manager)
{}
