/* 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;
}

}}

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 compiler's internal workflow. There are 4 distinctive stages managed by XreateManager:
 *  - `initPasses()` To init passes.
 *  - `executePasses()` To execute passes.
 *  - `analyse()` To run the reasoner.
 *  - `run()` To run the compiler.
 *
 * * \section xm_adapt Adaptability
 * For adaptability reasons XreateManager comes with several *frontends*:
 *  - `xreate::details::tier2::XreateManager` exposes all the stages to clients for full control.
 *  - `xreate::details::tier1::XreateManager` exposes `analyse()` along with `run()`, where `analyse()` combines execution of all previous stages.
 *  - `xreate::XreateManager` exposes `run()` only which properly initializes and executes all the stages for convenient use.
 *
 * Besides, there are also *backends* as follows:
 *  - \ref XreateManagerDecoratorBase Simple backend intended for inheritance, does not provide much functionality.
 *  - \ref XreateManagerDecoratorFull Backend intended to initialize all builtin passes.
 *
 * Thus, client could combine a desired frontend along with a desired backend as it sees fit.
 * Default xreate::XreateManager wraps around the full backend to init all builtin passes, and 
 * the simplest frontend with the only  `run()` exposed to execute all stages at once.
 */