#!/usr/bin/python

r'''Constructs README, README.org files

The README files are generated by this script. They are made from:

- The main module docstring, with some org markup applied to the README.org, but
  not to the README
- The docstrings from each API function in the module, with some org markup
  applied to the README.org, but not to the README
- README.footer.org, copied verbatim

The main module name must be passed in as the first cmdline argument.
'''

import sys

try:
    modname = sys.argv[1]
except:
    raise Exception("Need main module name as the first cmdline arg")

exec( 'import {} as mod'.format(modname) )

import inspect
import re
import StringIO

def dirmod():
    r'''Same as dir(mod), but returns only functions, in the definition order'''
    with open('{}.py'.format(modname), 'r') as f:
        for l in f:
            m = re.match(r'def +([a-zA-Z0-9_]+)\(', l)
            if m:
                yield m.group(1)

with open('README.org', 'w') as f_target_org:
    with open('README', 'w') as f_target:

        def write(s):
            f_target.    write(s)
            f_target_org.write(s)

        def write_orgized(s):
            r'''Writes the given string, reformatted slightly with org in mind.

            The only change this function applies, is to look for indented block
            (signifying examples) and to wrap then in a #+BEGIN_SRC or
            #+BEGIN_EXAMPLE.

            '''

            # the non-org version is written as is
            f_target.write(s)

            # the org version neeeds massaging
            f = f_target_org

            in_quote = None # can be None or 'example' or 'src'
            queued_blanks = 0
            indent_size = 4

            prev_indented = False

            sio = StringIO.StringIO(s)
            for l in sio:

                if in_quote is None:
                    if len(l) <= 1:
                        # blank line
                        f.write(l)
                        continue

                    if not re.match(' '*indent_size, l):
                        # don't have full indent. not quote start
                        prev_indented = re.match(' ', l)
                        f.write(l)
                        continue

                    if re.match(' '*indent_size + '-', l):
                        # Start of indented list. not quote start
                        prev_indented = re.match(' ', l)
                        f.write(l)
                        continue

                    if prev_indented:
                        # prev line(s) were indented, so this can't start a quote
                        f.write(l)
                        continue

                    # start of quote. What kind?
                    if re.match('    >>>', l):
                        in_quote = 'example'
                        f.write('#+BEGIN_EXAMPLE\n')
                    else:
                        in_quote = 'src'
                        f.write('#+BEGIN_SRC python\n')

                    f.write(l[indent_size:])
                    continue

                # we're in a quote. Skip blank lines for now
                if len(l) <= 1:
                    queued_blanks = queued_blanks+1
                    continue

                if re.match(' '*indent_size, l):
                    # still in quote. Write it out
                    f.write( '\n'*queued_blanks)
                    queued_blanks = 0
                    f.write(l[indent_size:])
                    continue

                # not in quote anymore
                if in_quote == 'example': f.write('#+END_EXAMPLE\n')
                else:                     f.write('#+END_SRC\n')
                f.write( '\n'*queued_blanks)
                f.write(l)
                queued_blanks = 0
                in_quote = None
                prev_indented = False

            f.write('\n')
            if   in_quote == 'example': f.write('#+END_EXAMPLE\n')
            elif in_quote == 'src':     f.write('#+END_SRC\n')




        header = '* NAME\n{}: '.format(modname)
        write( header )






        write_orgized(inspect.getdoc(mod))
        write( '\n' )

        # extract the global function docstrings. I'm not sure why I'm doing
        # that for the docstrings, but not for the class or methods. I guess the
        # bulk of the documentation isn't there, but in the module docstring.
        write('* GLOBAL FUNCTIONS\n')

        for func in dirmod():
            if re.match('_', func):
                continue

            if not inspect.isfunction(mod.__dict__[func]):
                continue

            doc = inspect.getdoc(mod.__dict__[func])
            if doc:
                write('** {}()\n'.format(func))
                write_orgized( doc )
                write( '\n' )

        with open('README.footer.org', 'r') as f_footer:
            write( f_footer.read() )
