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

#ifndef  PASSMANAGER_H
#define PASSMANAGER_H

#include <string>
#include <map>

//stdio external
struct _IO_FILE;
typedef struct _IO_FILE FILE;

namespace xreate { namespace grammar { namespace main {
    class Scanner;
}}}

namespace xreate {
class AbstractPassBase;
class ClaspLayer;
class LLVMLayer;
class AST;

enum class PassId {
	CFGPass,
	CompilePass,
	DFGPass,
	EnvironmentTestsPass,
	LoggerPass,
	AdhocPass,
	RulesPass,
        InterpretationPass,
        VersionsPass
};

class PassManager{
public:
    void                prepare(AST* ast);
    void                registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* prerequisite=nullptr);
    AbstractPassBase*   getPassById(const PassId& id);
    bool                isPassRegistered(const PassId& id);
    void                executePasses();
    
    virtual ~PassManager();

    ClaspLayer* clasp;
    LLVMLayer* llvm;
    AST* root;
    
private:
    std::map<PassId, AbstractPassBase*> __passes;
    std::multimap<AbstractPassBase*,  AbstractPassBase*> __passDependencies;    
};

namespace details{ namespace tier2{
class XreateManager: public virtual PassManager{
public:
    virtual     ~XreateManager(){};
    
    virtual void                    initPasses()=0;
//  virtual void                    executePasses()=0;
    virtual void                    analyse()=0;
    virtual void*                   run()=0;
    
    static XreateManager* prepare(std::string&& code);
    static XreateManager* prepare(FILE* code);
};

template<class Decorator>
class XreateManagerImpl: public Decorator {
public:
};

}} //namespace details::tier2

namespace details{ namespace tier1{
class XreateManager: public virtual PassManager{
public:
    virtual void                  analyse()=0;
    virtual void*                 run()=0;
    
    static XreateManager* prepare(std::string&& code);
    static XreateManager* prepare(FILE* code);
}; 

template<class Decorator>
class XreateManagerImpl: public XreateManager, public details::tier2::XreateManagerImpl<Decorator> {
    typedef details::tier2::XreateManagerImpl<Decorator> PARENT;

    public:
        void analyse(){
            PARENT::initPasses();
            PARENT::executePasses();
            PARENT::analyse();
        }

        void* run(){
            return PARENT::run();
        }
};

}}  //namespace details::tier1

class XreateManager: public virtual PassManager{
public:
    virtual void*                 run()=0;
    
    static XreateManager* prepare(std::string&& code);
    static XreateManager* prepare(FILE* code);
}; 

template<class Decorator>
class XreateManagerImpl: public XreateManager, public details::tier1::XreateManagerImpl<Decorator>{
    typedef details::tier1::XreateManagerImpl<Decorator> PARENT;

public:
    void* run(){
        PARENT::analyse();
        return PARENT::run();
    }
};

}  //namespace xreate

#endif
