#include <pass/abstractpass.h>
#include <pass/loggerpass.h>
#include "query/containers.h"
#include "passmanager.h"
#include "pass/compilepass.h"
#include "pass/adhocpass.h"

#include "Parser.h"
#include "pass/cfapass.h"
#include "pass/dfapass.h"
#include <list>
#include <stdio.h>

using namespace xreate;
using namespace std;

PassManager*
PassManager::prepareForCode(std::string&& code){
      Scanner scanner(reinterpret_cast<const unsigned char*>(code.c_str()), code.size());
      return prepareForCode(&scanner);
}

PassManager*
PassManager::prepareForCode(FILE* code){
      Scanner scanner(code);
      return prepareForCode(&scanner);
}

PassManager*
PassManager::prepareForCode(Scanner* code){
    Parser parser(code);
    parser.Parse();
    assert(!parser.errors->count && "Parser errors");

    PassManager* man = new PassManager;
    AST* ast = new AST(parser.root);

    man->root = ast;
    man->clasp = new ClaspLayer();

    man->clasp->ast = man->root;
    man->llvm = new LLVMLayer(man->root);

    CompilePass::prepareQueries(man->clasp);
    return man;
}

void
PassManager::registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* parent)
{
    __passes.emplace(id, pass);
    __passDependencies.emplace(parent, pass);
}

AbstractPassBase*
PassManager::getPassById(const PassId& id){
	assert(__passes.count(id));
	return __passes[id];
}

bool
PassManager::isPassRegistered(const PassId& id){
    return __passes.count(id);
}

void
PassManager::executePasses(){
    std::list<AbstractPassBase*> passes{nullptr};
    while (passes.size()){
        AbstractPassBase* parent = passes.front();

        auto range = __passDependencies.equal_range(parent);

        for (auto i=range.first; i!=range.second; ++i){
            AbstractPassBase* pass = i->second;

            pass->run();
            pass->finish();

            passes.push_back(pass);
        }

        passes.pop_front();
    }
}

void*
PassManager::run()
{
    runWithoutCompilation();

    CompilePass* compiler = new CompilePass(this);
    compiler->run();

    		//Compiler Dependents:
    LoggerPass* logger = new LoggerPass(this);
	logger->initDependencies(compiler);
	logger->run();

    llvm->print();
    llvm->initJit();
    return llvm->getFunctionPointer(compiler->getEntryFunction());
}

void PassManager::runWithoutCompilation(){
    if (flagIsProcessed) return;
    
    CFAPass* passCFG = new CFAPass(this);

        //TODO is it really DFGPass needs CFGpass?
    this->registerPass(new DFAPass(this), PassId::DFGPass, passCFG);
    this->registerPass(passCFG, PassId::CFGPass);
    this->registerPass(new AdhocPass(this), PassId::AdhocPass);
    
    this->executePasses();
    clasp->run();
    flagIsProcessed = true;
}

PassManager::~PassManager(){}
