#/usr/bin/env python3

from pyquery import PyQuery as pq
from collections import defaultdict
from sys import argv 
import os.path as op
import codecs

# if _in is part of args, return true.
def check_type(_in, args):
  if _in in args:
    return True
  else:
    return False

root_path=argv[1]
d = pq(filename=op.join(op.sep, root_path,'index.xml'), parser="xml")
compounds=[p.text() for p in list(d('compound').items())]
types=[p.attr('kind') for p in list(d('compound').items())]
type_map = defaultdict(list) #map <type, name>
dict_map = defaultdict(dict)#map <name, map<member type, member name>>
#FOREACH compounds : fill maps
for i in range(0,len(compounds)):
  if check_type(types[i], "typedef"):
    types[i]="type"
  name=d('compound').children("name").eq(i).text()
  members=[p.text() for p in list(d('compound').eq(i).children("member").items())]
  m_types=[p.attr('kind') for p in list(d('compound').eq(i).children("member").items())]
  if (not check_type(types[i], ['example', 'file', 'dir', 'page', 'group']) and
      not (types[i] == "namespace" and len(members) == 0) and
      not (types[i] == "enum" and len(members) == 0) ):
    if (types[i] == "class"):#check if the class is a concept class
      compound=d('compound').children("name").eq(i).text().replace('_', '__').replace('::', '_1_1')
      filepath='class'+compound+'.xml'
      total_path=op.join(op.sep, root_path,filepath)
      if(op.isfile(total_path)):
        file_content = codecs.open(total_path, 'rb')
        e = pq(file_content.read(), parser="xml")
        compoundnames=[p.text() for p in list(e('includes').items())]
        
        if(len(compoundnames) > 1 and compoundnames[0].find("Concept") != -1):
          types[i] = 'Concept '+types[i].lower()
    type_map[types[i]].append(name)

    mtype_map = defaultdict(list)# map<member type, member name>

    #FOREACH member :
    for j in range(0,len(members)):
      if(check_type(types[i], ['class', 'Concept class'])
         and m_types[j] == "function"):
        m_types[j]="method"
      if(m_types[j] == "typedef"):
        m_types[j]="type"
      mtype_map[m_types[j]].append(members[j])
	  #end FOREACH member
    dict_map[name]=mtype_map
#end FOREACH compound
indent=""


    

#print
#FOREACH type
for btype in type_map:
  out=btype
  if btype.endswith('s'):
    out+='e'
  print(out.title()+'s')
  indent+="  "
  #FOREACH name
  for name in type_map[btype]:
    filepath=""
    if check_type(btype, ['class', 'Concept class']):
      filepath='/class'+name.replace('_', '__').replace('::', '_1_1')+'.xml'
    elif btype == 'namespace':
      filepath='/namespace'+name.replace('_', '__').replace('::', '_1_1')+'.xml'
    templates=[]
    if op.isfile(op.join(op.sep, root_path,filepath)):
      f=pq(filename=op.join(op.sep, root_path,filepath), parser="xml")
      templateparams=list(f("compounddef").children("templateparamlist").eq(0).children("param").items())
      for param in templateparams:
        template_type=""
        template_name=""
        template_defval=""
        template_type=param.children("type").text()
        template_name=param.children("declname").text()
        template_defval=param.children("defval").text()
        complete_template=""
        if not template_type is None:
          complete_template+=template_type+' '
        if not template_name is None:
          complete_template+=template_name
        if not template_defval is None:
          complete_template+=' = '+template_defval
        templates.append(complete_template)        
        if templates==[]:#if no child was found, just take param.text()
         templates=[t.text() for t in list(param.items())]
    suffix="<"
    #as template got type, defname and declname, name is twice in template. keep only one of them.
    to_remove=[""]
    for template in templates:
      suffix+=template+', '
    if suffix == "<":
      suffix=""
    if suffix.endswith(', '):
      suffix = suffix[:-2]+'>'
    print(indent+name+suffix)

    indent+="  "
    #FOREACH mtype
    for mtype in (dict_map[name]):
      out=mtype
      if mtype.endswith('s'):
        out+='e'
      print(indent+out.title()+'s')
      indent+="  "
      #FOREACH member
      overload_map = defaultdict(int) #contains the number of times a member has appeared (to manage the overloads)
      templateparams=[]
      for member in dict_map[name][mtype]:
        templates=[]
        args="" # will contain the arguments of the methods and functions
        return_type="" #will contain the return type of a function/method
        
        #look for arguments
        if op.isfile(op.join(op.sep, root_path,filepath)):
          f=pq(filename=op.join(op.sep, root_path,filepath), parser="xml")
          index=0
          memberdefs=[m.text() for m in list(f("memberdef").items())]
          for i in range(0,len(memberdefs)):
            member_names=[member_name.text() for member_name in list(f('memberdef').eq(i).children("name").items())]
            if f('memberdef').eq(i).children("name").text() == member:
              if (index < overload_map[member]):
                index+=1
              elif (index == overload_map[member]):
                if check_type(mtype, ['function', 'method']):
                  args=[f('memberdef').eq(i).children("argsstring").text()]
                  templateparams=list(f('memberdef').eq(i).children("templateparamlist").children("param").items())
                if check_type(mtype, ['function', 'method', 'type', 'variable']):
                  return_type=[f('memberdef').eq(i).children("type").text()]
                break;
          #end foreach memberdef
        arguments=""
        for arg in args:
          arguments+=arg
        template_types=[]
        template_names=[]
        for param in templateparams:
          template_type=""
          template_name=""
          template_defval=""
          template_type=param.children("type").text()
          template_name=param.children("declname").text()
          template_defval=param.children("defval").text()
          complete_template=""
          if not template_type is None:
            complete_template+=template_type+' '
          if not template_name is None:
            complete_template+=template_name
          if not template_defval is None:
            complete_template+=' = '+template_defval
          templates.append(complete_template)        
          if templates==[]:#if no child was found, just take param.text()
           templates=[t.text() for t in list(param.items())]

        prefix="template <"
        for template in templates:
          prefix+=template+', '
        if prefix == "template <":
          prefix=""
        if prefix.endswith(', '):
          prefix = prefix[:-2]+'>\n'+indent+"  "
        for definition in return_type:
          prefix+=definition
        if(prefix != ""):
          prefix+=" "
        print(indent+prefix+member+arguments)
        overload_map[member]+=1
      #END foreach member
      indent=indent[:-2]
    #END foreach mtype
    indent=indent[:-2]
  #END foreach name
  indent=indent[:-2]
#END foreach type
