/* 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:   dfa.h
 * Author: pgess  <v.melnychenko@xreate.org>
 *
 * Created on June 27, 2016, 1:50 PM
 */

#ifndef DFA_H
#define DFA_H

#include "clasplayer.h"
#include <unordered_set>

namespace xreate {namespace dfa {
    struct SymbolAnonymous {
        unsigned int id;
        bool flagIsUsed = false;
    };
    
    bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2);

    typedef boost::variant<SymbolAnonymous, SymbolPacked> SymbolNode;
}}

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

namespace xreate {namespace dfa {
class DFACallInstance{
public:
    unsigned int id;
    std::string fnName;
    std::vector<std::pair<SymbolPacked, SymbolNode>> args;
    SymbolNode retActual;
    
    void print(std::ostringstream& output) const;
};

/** \brief Holds DFA Analysis report produced by DFAPass */
class DFAGraph: public IAnalysisReport{
public:
   // DFAGraph(ClaspLayer* engine): __clasp(engine){}
    virtual void print(std::ostringstream& output) const override;
    void addCallInstance(DFACallInstance && instance);
    void addDependency(const SymbolNode& node, const SymbolNode& subnodeBlock);
    void printInplaceAnnotations(SymbolNode node, const Expression& expression);
    void printAlias(const SymbolNode& symbolFormal, const SymbolNode& symbActual);
    void printFunctionRet(ManagedFnPtr function, const SymbolNode& symbolRet);
    void printDependencies(std::ostringstream& output) const;
    void markSymbolsAsUsed(const std::vector<SymbolNode>& usedNodes);
    void printSymbols(ClaspLayer* clasp);
    
private:
    mutable std::ostringstream __output;
    std::list<DFACallInstance> __callInstances;
    std::unordered_multimap<SymbolNode, SymbolNode> __dependencies;
    std::unordered_set<unsigned int> __usedAnonymousSymbols;
    std::unordered_set<SymbolNode> __roots;
    
    
    void printDependency(std::ostringstream& output, const SymbolNode& nodeCurrent, const SymbolNode& nodeDependent) const;
    bool isSymbolUsed(const SymbolNode& node) const;
};
}} // end of namespace xreate::dfa

#endif /* DFA_H */

