#!/usr/bin/env python

"""
WHAT THIS FILE DOES:
    converts an RST file to a .ipynb file
HOW THIS FILE WORKS:
    1. calls pandoc to convert between .rst and .md
    2. calls notedown to convert between .md and .ipynb
TODO:
    * properly parse command line args (escape chars etc)
    * Features notedown needs:
        * figure emedding
        * unicode
DEPS:
    * [notedown], [pandoc]

[notedown]:https://github.com/aaren/notedown
[pandoc]:http://pandoc.org
"""

import io
import os
pjoin = os.path.join
import re
import sys
from subprocess import Popen, PIPE
import argparse
import json


parser = argparse.ArgumentParser(description="Convert a reStructuredText (.rst) file to a Jupyter notebook (.ipynb)")
parser.add_argument("input", nargs='?', help="input file (default: read from standard input)")
parser.add_argument("output", nargs='?', help="output file (default: write to standard output)")
parser.add_argument("-o", "--output", help="output file")
parser.add_argument("-k", "--kernel", help="sets the Jupyter kernel in the notebook")
parser.add_argument("-v", "--verbose", action="store_true", help="be verbose")
parser.add_argument("-d", "--debug", action="store_true", help="write debug information and keep temporary .md file")
args = parser.parse_args()

if args.verbose:
    print(args.input, args.output)

if args.input:
    input_text = io.open(args.input).read()
else:
    input_text = sys.stdin.read()
input_text = '\n'.join([
    # add default-role: math for sage rst
    '.. default-role:: math',
    input_text])
# pandoc doesn't properly handle : immediately-following close-`
input_text = input_text.replace('`:', '` :')

# Interpret simple :ref:'s as crosslinks to notebooks in the same directory with the same name
input_text = re.sub(r":ref:`([\w-]*)`",r"`\1 <\1.ipynb>`_", input_text)
input_text = re.sub(r":ref:`([\w -]*) *<([\w-]*)>`",r"`\1 <\2.ipynb>`_", input_text)

# convert rst->markdown with pandoc
if args.verbose:
    sys.stderr.write("Calling pandoc to convert from rst to markdown\n")
p = Popen([
        'pandoc',
        '--filter', 'rst2ipynb-sageblock-filter',
        '--atx-headers',
        '--from', 'rst',
        '--to', 'markdown_github+tex_math_dollars+fenced_code_attributes',
    ], stdout=PIPE, stdin=PIPE)

# pipe_tables are supported by the notebook; don't know why pandoc seem to ignore the option ...
# grid_tables does not seem supported by the notebook
# Using markdown_github requires:
# +tex_math_dollars to handle maths (see tests/math.rst)
# +fenced_code_attributes to handle outputs (see tests/sage_code_blocks.rst)

intermediate_md, _ = p.communicate(input_text.encode('utf8'))

if p.returncode:
    sys.exit("pandoc failed: %s" % p.returncode)

intermediate_md = intermediate_md.decode('utf8', 'replace')

# define some math macros for mathjax
intermediate_md = '\n'.join([
    # add some sage-defined macros:
    '$$',
    r'\def\CC{\bf C}',
    r'\def\QQ{\bf Q}',
    r'\def\RR{\bf R}',
    r'\def\ZZ{\bf Z}',
    r'\def\NN{\bf N}',
    '$$',
    intermediate_md])

# Workaround:
# notedown does not handle nicely indented fenced code blocks
# This at least deindents the starting and trailing ```.

regexp = re.compile("^\s*```", flags=re.M)
intermediate_md = regexp.sub("```", intermediate_md)
intermediate_md = intermediate_md.replace("``` {", "```{") # Temporary workaround for older versions of notedown; see: https://github.com/aaren/notedown/issues/29.

# write intermediate markdown for debugging:
if args.debug:
    md = args.input.replace(".rst", ".md")
    sys.stderr.write("Writing intermediate markdown in %s\n"%md)
    with open(md, 'w') as f:
        f.write(intermediate_md)

# convert md->ipynb via notedown + postprocess custom kernel
if args.verbose:
    sys.stderr.write("Calling notedown to convert from markdown to ipynb\n")

p = Popen(['notedown', '--match=fenced'], stdin=PIPE, stdout=PIPE)

intermediate_ipynb, _ = p.communicate(intermediate_md.encode('utf8'))

if p.returncode:
    sys.exit("notedown failed: %s" % p.returncode)

intermediate_ipynb = intermediate_ipynb.decode('utf8', 'replace')

if args.kernel:
    worksheet = json.loads(intermediate_ipynb)
    worksheet['metadata']['kernelspec'] = {"display_name": args.kernel, 'name': args.kernel}
    intermediate_ipynb = json.dumps(worksheet,indent=1)

if args.output:
    with open(args.output, 'w') as f:
        f.write(intermediate_ipynb)
else:
    print(intermediate_ipynb)

