/* 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/.
 * 
 * File:   versionspass.h
 * Author: v.melnychenko@xreate.org
 *
 * Created on January 4, 2017, 3:09 PM
 */

/**
 * \file    versionspass.h
 * \brief   The versions analysis pass
 */

#ifndef VERSIONSPASS_H
#define VERSIONSPASS_H

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

namespace xreate { namespace versions {
    struct SymbolOrPlaceholder;    
}}

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

namespace xreate { namespace versions {
    
enum PlaceholderFlag {SYMBOL, PLACEHOLDER};

struct SymbolOrPlaceholder {
    PlaceholderFlag flagEndOfLifePlaceholder;
    Symbol symbol;
};

struct VersionImposedDependency{};
  
/** 
 * \brief Represents the results of the versions analysis provided by \ref VersionsPass
 * \sa VersionsPass
 */
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);
};
        
/** \brief Implements the versions analysis and stores the results in \ref VersionsGraph */
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::versions

namespace xreate{
    template<>
    std::list<Symbol>
    defaultValue<std::list<Symbol>>();
    
    template<>
    struct AttachmentsDict<versions::VersionImposedDependency>
    {
        typedef std::list<Symbol> Data;
        static const unsigned int key = 8;
    };
}
#endif /* VERSIONSPASS_H */

