/* 
 * File:   versionspass.h
 * Author: v.melnychenko@xreate.org
 *
 * Created on January 4, 2017, 3:09 PM
 */

#ifndef VERSIONSPASS_H
#define VERSIONSPASS_H

#include "pass/abstractpass.h"
#include <list>
#include  <functional>

namespace xreate {
    
    enum PlaceholderFlag {SYMBOL, PLACEHOLDER};

    struct SymbolOrPlaceholder {
        PlaceholderFlag flagEndOfLifePlaceholder;
        Symbol symbol;
    };


} namespace std {
    
    template<>
    struct hash<xreate::SymbolOrPlaceholder>{
        std::size_t operator()(xreate::SymbolOrPlaceholder const& s) const;
    };

    template<>
    struct equal_to<xreate::SymbolOrPlaceholder>{
      bool operator()(const xreate::SymbolOrPlaceholder& __x, const xreate::SymbolOrPlaceholder& __y) const;
    };
    
    template<>
    struct hash<xreate::Symbol>{
        size_t operator()(xreate::Symbol const& s) const;
    };

    template<>
    struct equal_to<xreate::Symbol>{
      bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const;
    };
    
} namespace xreate {

struct VersionImposedDependency{};

template<>
struct AttachmentsDict<VersionImposedDependency>
{
    typedef std::list<Symbol> Data;
    static const unsigned int key = 8;
};
    
class VersionsGraph{
    public:
        //processing API:
        void applyNatualDependencies(const Symbol& symbol, const std::list<Symbol>& dependencies);
        void applyDependentEndOfLife(const SymbolOrPlaceholder& symbol, const std::list<Symbol>& dependencies);
        
        void defineEndOfLife(const Symbol& symbol, const Symbol& symbolSuccessor);
        SymbolOrPlaceholder getEndOfLife(const Symbol& s);
        
        bool validate();

        //examination API:
        AttachmentsContainerDefault<std::list<Symbol>>* representAsAttachments() const;
        void __debug_print(std::ostream& output) const;
        
    private:
        typedef std::unordered_map<SymbolOrPlaceholder, unsigned int> Path;

        std::unordered_multimap<Symbol, Symbol> __inferiorsNatural;
        std::unordered_multimap<SymbolOrPlaceholder, SymbolOrPlaceholder> __inferiors;
        std::unordered_map<Symbol, Symbol> __dictSuccessors;

        std::list<Symbol> expandPlaceholder(const SymbolOrPlaceholder& symbol, const Symbol& symbolPrev) const;
        std::list<SymbolOrPlaceholder> extractCycle(const Path& path, const SymbolOrPlaceholder& symbolBeginning);
        bool tryEliminateEofAliases(const std::list<SymbolOrPlaceholder>& aliases);
        bool validateCycles();
        bool validateCycles(const SymbolOrPlaceholder& s, 
                            std::unordered_multimap<SymbolOrPlaceholder, SymbolOrPlaceholder>& graph,
                            std::unordered_set<SymbolOrPlaceholder>& symbolsVisited, 
                            Path& path);
};
        
template<>
std::list<Symbol>
defaultValue<std::list<Symbol>>();

class VersionsPass: public AbstractPass<std::list<Symbol>> {
    typedef AbstractPass<std::list<Symbol>> Parent;
    
public:
    VersionsPass(PassManager* manager): AbstractPass<std::list<Symbol>>(manager){}
    std::list<Symbol> process(const Expression& expression, PassContext context, const std::string& hintSymbol="") override;
    VersionsGraph& getResultGraph();
    virtual void finish();
    
protected:
    std::list<Symbol> processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol="") override;
    
private:
    VersionsGraph __graph;
    
    AttachmentsContainerDefault<bool> __symbolsVisited;
};

}   //end of xreate

#endif /* VERSIONSPASS_H */

