#!/usr/bin/env python
# coding: utf-8
from __future__ import division, print_function, unicode_literals
import re
import time
import codecs
import argparse
import sys
from builtins import str
import CommonMark


class colors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'


def trace_calls(frame, event, arg):
    co = frame.f_code
    func_name = co.co_name
    if func_name == "write":
        return
    line_no = frame.f_lineno
    filename = co.co_filename
    if event == "call" and not re.match("__", func_name) and \
       re.search("CommonMark.py", filename) \
       and func_name != "dumpAST":
        print("-> " + frame.f_back.f_code.co_name +
              " at " + str(frame.f_back.f_lineno) +
              " called " + func_name + " at " + str(line_no) +
              " in " + filename)
        return trace_calls

parser = argparse.ArgumentParser(
    description="script to run the CommonMark specification tests " +
    "against the CommonMark.py parser")
parser.add_argument(
    '-t',
    help="Single test to run or comma separated list " +
    "of tests (-t 10 or -t 10,11,12,13)")
parser.add_argument(
    '-p',
    action="store_true",
    help="Print passed test information")
parser.add_argument(
    '-f',
    action="store_true",
    help="Print failed tests (during -np...)")
parser.add_argument(
    '-i',
    action="store_true",
    help="Interactive Markdown input mode")
parser.add_argument(
    '-d',
    action="store_true",
    help="Debug, trace calls")
parser.add_argument(
    '-np',
    action="store_true",
    help="Only print section header, tick, or cross")
parser.add_argument(
    '-s',
    action="store_true",
    help="Print percent of tests passed by category")
args = parser.parse_args()

if args.d:
    sys.settrace(trace_calls)

renderer = CommonMark.HtmlRenderer()
parser = CommonMark.Parser()

f = codecs.open("spec.txt", encoding="utf-8")
datalist = []
for line in f:
    datalist.append(line)
data = "".join(datalist)
passed = 0
failed = 0
catStats = {}
examples = []
example_number = 0
current_section = ""
tabChar = '\u2192'
spaceChar = '\u2423'
nbspChar = '\u00A0'


def showSpaces(t):
        t = re.sub("\\t", tabChar, t)
        t = re.sub(" ", spaceChar, t)
        t = re.sub(nbspChar, spaceChar, t)
        return t

t = re.sub("\r\n", "\n", data)

tests = re.sub("^<!-- END TESTS -->(.|[\n])*", '', t, flags=re.M)
testMatch = re.findall(
    re.compile(
        "^\.\n([\s\S]*?)^\.\n([\s\S]*?)^\.$|^#{1,6} *(.*)$",
        re.M),
    tests)

for match in testMatch:
    if not match[2] == "":
        current_section = match[2]
    else:
        example_number += 1
        examples.append({
            'markdown': match[0],
            'html': match[1],
            'section': current_section,
            'number': example_number})

current_section = ""

startTime = time.clock()

if args.i:
    print(
        colors.OKGREEN +
        "(To end input of Markdown block enter 'end' on " +
        "it's own line, to quit enter 'quit')" +
        colors.ENDC)
    while True:
        s = ""
        while True:
            if sys.version_info >= (3, 0):
                inp = input(colors.OKBLUE + 'Markdown: ' + colors.ENDC)
            else:
                inp = raw_input(colors.OKBLUE + 'Markdown: ' + colors.ENDC)  # noqa

            if not inp == "end" and inp != "quit":
                s += inp + "\n"
            elif inp == "end":
                s = s[:-1]
                break
            elif inp == "quit":
                print(colors.HEADER+"bye!"+colors.ENDC)
                exit(0)
        ast = parser.parse(s)
        html = renderer.render(ast)
        print(colors.WARNING+"="*10+"AST====="+colors.ENDC)
        CommonMark.dumpAST(ast)
        print(colors.WARNING+"="*10+"HTML===="+colors.ENDC)
        print(html)

# some tests?
if args.t:
    tests = args.t.split(",")
    choice_examples = []
    for t in tests:
        if not t == "" and len(examples) > int(t):
            choice_examples.append(examples[int(t)-1])
    examples = choice_examples

# all tests

for i, example in enumerate(examples):  # [0,examples[0]]
    if not example['section'] == "" and \
       not current_section == example['section']:
        print('\n' + colors.HEADER + '[' + example['section'] + ']' +
              colors.ENDC + ' ', end='')
        current_section = example['section']
        catStats.update({current_section: [0, 0, 0]})

    catStats[current_section][2] += 1
    if args.d:
        print(colors.HEADER+"[Parsing]"+colors.ENDC)
    ast = parser.parse(re.sub(tabChar, "\t", example['markdown']))
    if args.d:
        print(colors.HEADER+"[Rendering]"+colors.ENDC)
    actual = renderer.render(ast)
    if re.sub('\t', tabChar, actual) == example['html']:
        passed += 1
        catStats[current_section][0] += 1
        if not args.f:
            print(colors.OKGREEN + '✓' + colors.ENDC, end='')
        if args.d:
            CommonMark.dumpAST(ast)
        if args.p or args.d and not args.np:
            print(
                colors.OKBLUE +
                "=== markdown ===============\n" +
                colors.ENDC + showSpaces(example['markdown']) +
                colors.OKBLUE +
                "\n=== expected ===============\n" +
                colors.ENDC + showSpaces(example['html']) +
                colors.OKBLUE +
                "\n=== got ====================\n" +
                colors.ENDC + showSpaces(actual))
    else:
        failed += 1
        catStats[current_section][1] += 1
        if args.t:
            print("Test #" + str(args.t.split(",")[i]), end='')
        else:
            print("Test #" + str(i+1), end='')
        print(' ' + colors.FAIL + "✗" + colors.ENDC)
        if args.d:
            CommonMark.dumpAST(ast)
        if not args.np or args.f:
            print(
                colors.WARNING +
                "=== markdown ===============\n" +
                colors.ENDC + showSpaces(example['markdown']) +
                colors.WARNING +
                "\n=== expected ===============\n" +
                colors.ENDC + showSpaces(example['html']) +
                colors.WARNING +
                "\n=== got ====================\n" +
                colors.ENDC + showSpaces(actual))

print('\n' + str(passed) + ' tests passed, ' + str(failed) + ' failed')

endTime = time.clock()
runTime = endTime-startTime

if args.s:
    for i in catStats.keys():
        per = catStats[i][0]/catStats[i][2]
        print(colors.HEADER + "[" + i + "]" + colors.ENDC +
              "\t" + str(per*100) + "% Passed")

print("runtime: " + str(runTime) + "s")

if (failed > 0):
    sys.exit(1)
