//print demangled typename in tree format
#ifndef UTILITY_STR_TREE_TYPE_NAME_PRINT_HPP
#define UTILITY_STR_TREE_TYPE_NAME_PRINT_HPP
#include <boost/spirit/core.hpp>
#include <boost/spirit/attribute.hpp>
#include <boost/spirit/utility/chset.hpp>
#include <boost/spirit/phoenix/binders.hpp>
#include <boost/io/filters/mout.hpp>
namespace utility
{
struct str_tree_type_name_parser_print 
: public boost::spirit::grammar<str_tree_type_name_parser_print> 
{
      marg_ostream&
    my_out
    ;
    explicit str_tree_type_name_parser_print(marg_ostream& a_out=mout())
    : my_out(a_out)
    {}
    struct children_closure : boost::spirit::closure<children_closure, char> 
    {
        member1 tag
        //Start character for delimiting children.
        //e.g. { or { or <.
        ;
    };
    struct print_label
    {
          marg_ostream&
        my_out
        ;
        explicit print_label(marg_ostream& a_out)
        : my_out(a_out)
        {}
        template <typename ActionIterT>
        void operator() (ActionIterT const &first, ActionIterT const &last) const
        {
            std::string item(first,last-first);
            my_out<<item<<"\n";
        }
    
    };
    struct print_open
    {
          marg_ostream&
        my_out
        ;
        explicit print_open(marg_ostream& a_out)
        : my_out(a_out)
        {}
        template <typename ActionIterT>
        void operator() (ActionIterT const &first, ActionIterT const &last) const
        {
            std::string item(first,last-first);
            my_out<<item<<" ";
            ++my_out;
        }
    
    };
    struct print_infix
    {
          marg_ostream&
        my_out
        ;
        explicit print_infix(marg_ostream& a_out)
        : my_out(a_out)
        {}
        template <typename ActionIterT>
        void operator() (ActionIterT const &first) const
        {
            --my_out;
            my_out<<first<<" ";
            ++my_out;
        }
    
    };
    struct print_close
    {
          marg_ostream&
        my_out
        ;
        explicit print_close(marg_ostream& a_out)
        : my_out(a_out)
        {}
        template <typename ActionIterT>
        void operator() (ActionIterT const &first, ActionIterT const &last) const
        {
            std::string item(first,last-first);
            --my_out;
            my_out<<item<<"\n";
        }
    
    };
    struct print_string
    {
          marg_ostream&
        my_out
        ;
        explicit print_string(marg_ostream& a_out)
        : my_out(a_out)
        {}
        template <typename ActionIterT>
        void operator() (ActionIterT const &first, ActionIterT const &last) const
        {
            if(first == last) return;
            std::string item(first,last-first);
            my_out<<item<<"\n";
        }
    
    };
    
    static char const* delimiters_open(void)
    {
        static char const*s="(<";
        return s;
    }
    static char const* delimiters_close(void)
    {
        static char const*s=")>";
        return s;
    }
    static char const delimiter_infix  = ','  ;
    static char close_delimiter(char open_delimiter)
    {
        char*const openp=strchr(delimiters_open(),open_delimiter);
        int  const openi=openp-delimiters_open();
        return delimiters_close()[openi];
    }
    template <typename ScannerT>
    struct definition 
    {

          marg_ostream& 
        my_out
        ;
        definition(str_tree_type_name_parser_print const& a_parser)
        : my_out(a_parser.my_out)
        {
        
            using namespace boost::spirit;
            using namespace phoenix;

            children 
              =  start_tag[print_open(my_out)]
              >> !( tree
                  >> *(  ch_p(delimiter_infix)[print_infix(my_out)]
                      >> tree
                      )
                  ) 
              >> end_tag[print_close(my_out)]
              ;

            start_tag =
              chset_p(delimiters_open())
              [ 
                  children.tag = construct_<char>(arg1)
              ]
              ;

            end_tag = f_ch_p(phoenix::bind(&close_delimiter)(children.tag));
            
            std::string not_label_chr
              =std::string(delimiters_open())+delimiters_close()+delimiter_infix;
            ident = 
              +(anychar_p - chset_p(not_label_chr.c_str()))
              //identifier
              ;
            label = 
              ( (  ch_p('(')
                >> ident
                >> ch_p(')')
                >> uint_p
                )//for example, for an enum numeral in mpl::integral_c<Enum,Valu>.
              | ident
              )[print_string(my_out)]
              ;
            
            modifiers =
              (*( ch_p('*')
                | '&'
                | "const"
                )
              )[print_string(my_out)]
              ;
               
            tree
              = label
              >> !children
              >> modifiers
              ;
        }

            typedef
          boost::spirit::rule
          < ScannerT
          , children_closure::context_t
          > 
        children_type;
        children_type children;
        boost::spirit::rule<ScannerT> start_tag;
        boost::spirit::rule<ScannerT> end_tag;
        boost::spirit::rule<ScannerT> ident;
        boost::spirit::rule<ScannerT> label;
        boost::spirit::rule<ScannerT> modifiers;
        boost::spirit::rule<ScannerT> tree;

        boost::spirit::rule<ScannerT> const&
        start() const { return tree; }
    };
};

  boost::spirit::parse_info<> 
str_tree_type_name_print(std::string const& str)
/**@brief
 *  Prints a string representing a typename in formatted
 *  tree form. For example, the string:
 *
 *   x<a,b<c,d>const &,e &>
 *
 *  is printed as:
 *
 *   x
 *   < a
 *   , b
 *     < c
 *     , d
 *     > const &
 *   , e &
 *   >
 *
 */
{
    str_tree_type_name_parser_print p;    //  Our parser
    return boost::spirit::parse(str.c_str(), p, boost::spirit::space_p);
}
  boost::spirit::parse_info<> 
str_tree_type_name_print_trace(std::string const& str)
/**@brief
 *  Same as str_tree_type_name_print but also prints input
 *  and diagnostics.
 */
{
    bool const trace=false;
    str_tree_type_name_parser_print p(mout());    //  Our parser
    if(trace)
    {
        p.my_out << "String:\n";
        ++p.my_out;
        p.my_out<<str<<"\n";
        --p.my_out;
        p.my_out<<"Tree:\n";
        ++p.my_out;
    }
    boost::spirit::parse_info<> info 
      = boost::spirit::parse(str.c_str(), p, boost::spirit::space_p);
    if(trace)
    {
        --p.my_out;
    }

    if (info.full)
    {
        if(trace)
        {
            p.my_out << "-------------------------\n";
            p.my_out << "Parsing succeeded\n";
            p.my_out << "-------------------------\n";
        }
    }
    else
    {
        p.my_out << "-------------------------\n";
        p.my_out << "Parsing failed\n";
        p.my_out << "input: \"" << str <<"\"\n";
        p.my_out << "stopped at: \": " << info.stop << "\"\n";
        p.my_out << "-------------------------\n";
    }
    return info;
}

}//exit utility namespace
#endif
