require 'rexml/document'

#FIXME unhardcode stuff
system( "g++ -c -fdump-translation-unit-all -I/usr/include/sigc++-2.0 -I/usr/lib/sigc++-2.0/include -I.. -I../_build/default/ ./ept.cpp" )
#system( "head -n 50000 ept.cpp.t00.tu > ept.cpp.t01.tu" )

file = File.new( "ept.cpp.t00.tu" )
conf = "ept::configuration::apt"
Blacklist = /Amorph/
Prefix  = "Apt"
$ent = Array.new;

class Entry
  def initialize( s )
    @id = /^@([0-9]+)/.match( s )[ 1 ].to_i
    @t = /^@[0-9]+ +([a-z_]+)/.match( s )[ 1 ]
    @name = getid( "name", s )
    @scope = getid( "scpe", s )
    @type = getid( "type", s )
    @base = getid( "base", s )
    @chain = getid( "chan", s )
    if ( s =~ /lngt: ([0-9]+)/ and s =~ /strg: / )
      len = /lngt: ([0-9]+)/.match( s )[ 1 ].to_i
      @str = /strg: (.{#{len}})/.match( s )[ 1 ]
      #puts "named object: #{@str}"
    end
  end

  def t()
    return @t
  end

  def id()
    return @id
  end

  def getid( l, s )
    m = /#{l}: @([0-9]+)/.match( s )
    return nil if m == nil
    return m[ 1 ].to_i
  end

  def getent( id )
    return nil if id == nil
    return $ent[ id ]
  end

  def str(); return @str; end

  def scope(); return getent( @scope ); end
  def type(); return getent( @type ); end
  def base(); return getent( @base ); end
  def chain(); return getent( @chain ); end

  def name()
    return $ent[ @name ].str() unless @name == nil or $ent[ @name ] == nil
    return nil
  end

  def qname()
    return nil if name == nil
    return name if scope == nil
    r = String.new
    scopes.each { |s|
      r << "#{s.name}::"
    }
    r << name
    return r
  end

  def scopes()
    a = Array.new
    s = self
    while s.scope != nil
      s = s.scope
      a << s
    end
    return a.reverse
  end

  class << self
    def id_from_s( s )
      m = /^@([0-9]+)/.match( s );
      return -1 if m == nil
      return m[1].to_i
    end
  end

end

#inp.scan( /^.*?\n@/ ) { |s|
file.each( "\n@" ) { |s|
  s = s.sub( /^@*/, "@" );
  s = s.sub( /@$/, "" );
  id = Entry.id_from_s( s )
  printf "\rSECTION: " + id.to_s + "               " if id % 50 == 0
  $ent[ Entry.id_from_s( s ) ] = Entry.new( s )
}
puts

# $ent.each { |e|
#   next if e == nil
#   next if e.t != "type_decl"
#   e.scopes.each { |s|
#     printf "#{s.name}::"
#   }
#   printf "#{e.name} (#{e.id})"
#   printf "; #{e.type.name} (#{e.type.id})" if e.type
#   puts
# }

puts "----------------------------"
#root = $ent[ 3305 ]
i = $ent[ 3896 ];

while i.chain
  puts "#{i.qname} -> #{i.type.qname}"
  i = i.chain
end

# def output( root, id, typedef = "", level = 0 )
#   puts "// output called: " + id + " " + typedef + " " + level.to_s
#   ids = []
#   el = root.elements[ "Namespace[@id='" + id + "']" ];
#   if el == nil
#     el = root.elements[ "Typedef[@id='" + id + "']" ];
#     unless el == nil
#       ids = el.attributes[ "type" ].split( / / );
#       typedef = el.attributes[ "name" ] if ( typedef == "" );
#       puts "// output found typedef " + id + ": " + ids.to_s()
#     end
#   else
#     ids = el.attributes[ "members" ].split( / / ) unless el == nil
#     puts "// output found namespace " + id + ": " + ids.to_s()
#   end

#   ids.each { |i|
#     puts "// output descending to id " + id
#     output( root, i, typedef, level ) }
#   ids = []

#   el = root.elements[ "Struct[@id='" + id + "']" ];
#   unless el == nil
#     mangled = el.attributes[ "mangled" ];
#     ids = el.attributes[ "bases" ].split( / / ) if el.attributes[ "bases" ];
#     puts "// output found struct " + id + ": " + ids.to_s()
#     ids.each { |i|
#       puts "// output descending to struct " + id
#       output( root, i, typedef, level + 1 ) }
#     demangled = `echo "#{mangled}" | c++filt -t`
#     unless Blacklist.match( demangled )
#       if ( level == 0 )
#         puts "%template( " + Prefix + typedef + " ) " + demangled.chomp() + "; // " + id + " " + typedef
#       else
#         puts "%template( _M_" + mangled + " ) " + demangled.chomp() + "; // " + id + " " + typedef
#       end
#     end
#   end
# end

#ids = doc.root.elements["Namespace[@mangled='" + conf + "']" ].attributes[ "members" ].split( / / )
#ids.each { |id| output( doc.root, id ) }
#output( doc.root, doc.root.elements["Namespace[@mangled='" + conf + "']" ].attributes[ "id" ] )
