#!/usr/bin/env python
#!/bin/env python

""" Reads in all the generated manual pages, and creates the index
for the manualpages, ordering the indices into sections based
on the 'Level of Difficulty'.

 Usage:
   wwwindex.py PETSC_DIR LOC
"""

import os
import sys
import re
import glob
import posixpath
import subprocess

HLIST_COLUMNS = 3

# Read an optional header file, whose contents are first copied over
# Use the level info, and print a formatted index table of all the manual pages
#
def printindex(outfilename, headfilename, levels, titles, tables):
      # Read in the header file
      headbuf = ''
      if posixpath.exists(headfilename) :
            with open(headfilename, "r") as fd:
                headbuf = fd.read()
                headbuf = headbuf.replace('PETSC_DIR', '../../../')
      else:
            print('Error! SUBMANSEC header file "%s" does not exist' % headfilename)
            print('Likley you introduced a new set of manual pages but did not add the header file that describes them')

      with open(outfilename, "w") as fd:
          # Since it uses three columns we must remove right sidebar so all columns are displayed completely
          # https://pydata-sphinx-theme.readthedocs.io/en/stable/user_guide/page-toc.html
          fd.write(':html_theme.sidebar_secondary.remove: true\n')
          fd.write(headbuf)
          fd.write('\n')
          all_names = []
          for i, level in enumerate(levels):
                title = titles[i]
                if not tables[i]:
                      if level != 'none' and level != 'deprecated':
                          fd.write('\n## No %s routines\n' % level)
                      continue

                fd.write('\n## %s\n' % title)
                fd.write('```{hlist}\n')
                fd.write("---\n")
                fd.write("columns: %d\n" % HLIST_COLUMNS)
                fd.write("---\n")

                for filename in tables[i]:
                      path,name     = posixpath.split(filename)
                      func_name,ext = posixpath.splitext(name)
                      fd.write('- [](%s)\n' % name)
                      all_names.append(name)
                fd.write('```\n\n\n')

          fd.write('\n## Single list of manual pages\n')
          fd.write('```{hlist}\n')
          fd.write("---\n")
          fd.write("columns: %d\n" % HLIST_COLUMNS)
          fd.write("---\n")
          for name in sorted(all_names):
              fd.write('- [](%s)\n' % name)
          fd.write('```\n\n\n')


# This routine takes in as input a dictionary, which contains the
# alhabetical index to all the man page functions, and prints them all in
# a single index page
def printsingleindex(outfilename, alphabet_dict):
      with open(outfilename, "w") as fd:
          fd.write("# Single Index of all PETSc Manual Pages\n\n")
          fd.write(" Also see the [Manual page table of contents, by section](/manualpages/index.md).\n\n")
          for key in sorted(alphabet_dict.keys()):
                fd.write("## %s\n\n" % key.upper())
                fd.write("```{hlist}\n")
                fd.write("---\n")
                fd.write("columns: %d\n" % HLIST_COLUMNS)
                fd.write("---\n")
                function_dict = alphabet_dict[key]
                for name in sorted(function_dict.keys()):
                      if name:
                            path_name = function_dict[name]
                      else:
                            path_name = ''
                      fd.write("- [%s](%s)\n" % (name, path_name))
                fd.write("```\n")


# Read in the filename contents, and search for the formatted
# String 'Level:' and return the level info.
# Also adds the BOLD HTML format to Level field
def modifylevel(filename,secname,edit_branch):
      with open(filename, "r") as fd:
          buf = fd.read()

      re_name = re.compile('\*\*Location:\*\*(.*)')  # As defined in myst.def
      m = re_name.search(buf)
      if m:
        loc_html = m.group(1)
        if loc_html:
          pattern = re.compile(r"<A.*>(.*)</A>")
          loc = re.match(pattern, loc_html)
          if loc:
              source_path = loc.group(1)
              buf += "\n\n---\n[Edit on GitLab](https://gitlab.com/petsc/petsc/-/edit/%s/%s)\n\n" % (edit_branch, source_path)
          else:
              print("Warning. Could not find source path in %s" % filename)
      else:
        print('Error! No location in file:', filename)

      re_level = re.compile(r'(Level:)\s+(\w+)')
      m = re_level.search(buf)
      level = 'none'
      if m:
            level = m.group(2)
      else:
            print('Error! No level info in file:', filename)

      # Reformat level and location
      tmpbuf = re_level.sub('',buf)
      re_loc = re.compile('(\*\*Location:\*\*)')
      tmpbuf = re_loc.sub('\n## Level\n' + level + '\n\n## Location\n',tmpbuf)

      # Modify .c#,.h#,.cu#,.cxx# to .c.html#,.h.html#,.cu.html#,.cxx.html#
      tmpbuf = re.sub('.c#', '.c.html#', tmpbuf)
      tmpbuf = re.sub('.h#', '.h.html#', tmpbuf)
      tmpbuf = re.sub('.cu#', '.cu.html#', tmpbuf)
      tmpbuf = re.sub('.cxx#', '.cxx.html#', tmpbuf)

      # Add footer links
      outbuf = tmpbuf + '\n[Index of all %s routines](index.md)  \n' % secname + '[Table of Contents for all manual pages](/manualpages/index.md)  \n' + '[Index of all manual pages](/manualpages/singleindex.md)  \n'

      # write the modified manpage
      with open(filename, "w") as fd:
          fd.write(':orphan:\n'+outbuf)

      return level

# Go through each manpage file, present in dirname,
# and create and return a table for it, wrt levels specified.
def createtable(dirname,levels,secname,editbranch):
      listdir =  os.listdir(dirname)
      mdfiles = [os.path.join(dirname,f) for f in listdir if f.endswith('.md')]
      mdfiles.sort()
      if mdfiles == []:
            print('Cannot create table for empty directory:',dirname)
            return None

      table = []
      for level in levels: table.append([])

      for filename in mdfiles:
            level = modifylevel(filename,secname,editbranch)
            if level.lower() in levels:
                  table[levels.index(level.lower())].append(filename)
            else:
                  print('Error! Unknown level \''+ level + '\' in', filename)
      return table

# This routine is called for each man dir. Each time, it
# adds the list of manpages, to the given list, and returns
# the union list.

def addtolist(dirname,singlelist):
      mdfiles = [os.path.join(dirname,f) for f in os.listdir(dirname) if f.endswith('.md')]
      mdfiles.sort()
      if mdfiles == []:
            print('Error! Empty directory:',dirname)
            return None

      singlelist.extend(mdfiles)

      return singlelist

# This routine creates a dictionary, with entries such that each
# key is the alphabet, and the vaue corresponds to this key is a dictionary
# of FunctionName/PathToFile Pair.
def createdict(singlelist):
      newdict = {}
      for filename in singlelist:
            path,name     = posixpath.split(filename)
            # grab the short path Mat from /wired/path/Mat
            junk,path     = posixpath.split(path)
            index_char    = name[0:1].lower()
            # remove the .name suffix from name
            func_name,ext = posixpath.splitext(name)
            if index_char not in newdict:
                  newdict[index_char] = {}
            newdict[index_char][func_name] = path + '/' + name

      return newdict


def getallmandirs(dirs):
      """ Gets the list of man* dirs present in the doc dir. Each dir will have an index created for it. """
      mandirs = []
      for filename in dirs:
            path,name = posixpath.split(filename)
            if name == 'RCS' or name == 'sec' or name == "concepts" or name  == "SCCS" : continue
            if posixpath.isdir(filename):
                  mandirs.append(filename)
      return mandirs


def main(PETSC_DIR,LOC):
      HEADERDIR = 'doc/classic/manualpages-sec'
      dirs      = glob.glob(LOC + '/manualpages/*')
      mandirs   = getallmandirs(dirs)

      levels = ['beginner','intermediate','advanced','developer','deprecated','none']
      titles = ['Beginner - Basic usage',
                'Intermediate - Setting options for algorithms and data structures',
                'Advanced - Setting more advanced options and customization',
                'Developer - Interfaces rarely needed by applications programmers',
                'Deprecated - Functionality scheduled for removal in the future',
                'None: Not yet cataloged']

      singlelist = []
      git_ref = subprocess.check_output(['git', 'rev-parse', 'HEAD']).rstrip()
      try:
        git_ref_release = subprocess.check_output(['git', 'rev-parse', 'origin/release']).rstrip()
        edit_branch = 'release' if git_ref == git_ref_release else 'main'
      except subprocess.CalledProcessError:
        print("WARNING: checking branch for man page edit links failed")
        edit_branch = 'main'

      for dirname in mandirs:
            outfilename  = dirname + '/index.md'
            dname,secname  = posixpath.split(dirname)
            headfilename = PETSC_DIR + '/' + HEADERDIR + '/header_' + secname
            table        = createtable(dirname,levels,secname,edit_branch)
            if not table: continue
            singlelist   = addtolist(dirname,singlelist)
            printindex(outfilename,headfilename,levels,titles,table)

      alphabet_dict = createdict(singlelist)
      outfilename   = LOC + '/manualpages/singleindex.md'
      printsingleindex (outfilename,alphabet_dict)

if __name__ == '__main__':
      main(os.path.abspath(os.environ['PETSC_DIR']),os.path.abspath(os.environ['LOC']))
