/* 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/.
 *
 * xreatemanager.cpp
 *
 * Author: pgess <v.melnychenko@xreate.org>
 * Created on July 3, 2017, 6:03 PM
 */

#include "xreatemanager.h"
#include "pass/abstractpass.h"
#include "aux/transcend-decorators.h"
#include "aux/xreatemanager-decorators.h"
#include "llvmlayer.h"
#include <assert.h>
#include <list>

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

IPass*
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<IPass*> passes{nullptr};
    while (passes.size()){
        IPass* parent = passes.front();

        auto range = __passDependencies.equal_range(parent);

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

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

            passes.push_back(pass);
        }

        passes.pop_front();
    }
}

void
PassManager::prepare(AST* ast){
    root = ast;
    transcend = new DefaultTranscendLayerImpl();
    transcend->ast = ast;
    llvm = new LLVMLayer(ast);
}

PassManager::~PassManager(){}

typedef XreateManagerDecoratorFull XreateManagerDecoratorDefault;

namespace details{ namespace tier2{

XreateManager*
XreateManager::prepare(std::string&& code){
    auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;

    man->prepareCode(std::move(code));
    return man;
}

XreateManager*
XreateManager::prepare(FILE* code){
    auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;

    man->prepareCode(code);
    return man;
}
}}

namespace details { namespace tier1 {

XreateManager*
XreateManager::prepare(std::string&& code){
    auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;

    man->prepareCode(std::move(code));
    return man;
}

XreateManager*
XreateManager::prepare(FILE* code){
    auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;

    man->prepareCode(code);
    return man;
}

}}

/**
 * \class xreate::XreateManager
 * \brief Entry point of Xreate API
 *
 * Manages whole Xreate's internal workflow. There are 4 distinctive stages covered by XreateManager:
 *  - initPasses() To init passes
 *  - executePasses() To execute passes
 *  - analyse() To run reasoner
 *  - run() To run compiler
 *
 * For adaptability manager comes with several *Frontends*:
 *  - xreate::details::tier2::XreateManager has all stages accessible by client for full control
 *  - xreate::details::tier1::XreateManager has only analyse() and run(), where analyse() combines execution of all previous stages
 *  - xreate::XreateManager has only run() to combine all stages for convenient use
 *
 * Moreover there are *Backends*:
 *  - xreate::XreateManagerDecoratorBase Simple backend intended for inheritance without much functionality
 *  - XreateManagerDecoratorFull Backend intended to initialize all builtin passes
 *
 * Thus, client's code could combine desired frontend and desired backend as see fit.
 * Default xreate::XreateManager connects full backend to init all builtin passes
 * to a simplest frontend with only run() available to execute all stages at once
 */

/**
 *\brief Constructs XreateManager for a given code
 */
XreateManager*
XreateManager::prepare(std::string&& code) {
    auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;

    man->prepareCode(std::move(code));
    return man;
}

/**
 *\brief Constructs XreateManager for a given script file
 */
XreateManager*
XreateManager::prepare(FILE* code){
    auto man = new XreateManagerImpl<XreateManagerDecoratorDefault>;

    man->prepareCode(code);
    return man;
}

}
