#!/usr/bin/env python
#
# This file is part of KDevelop
#
# Copyright 2016 Anton Anikin <anton.anikin@htower.ru>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.

from xml.sax.saxutils import escape, unescape
import pyparsing as pp
import string
import re

# escape() and unescape() takes care of &, < and >.
html_escape_table = {
    '"': "&quot;",
    "'": "&apos;"
    }

html_unescape_table = {v:k for k, v in html_escape_table.items()}

def html_escape(text):
    return escape(text, html_escape_table)

def html_unescape(text):
    return unescape(text, html_unescape_table)

def parseFile(fileName):
    EOL = pp.LineEnd().suppress()
    endTag = pp.Literal('**Compliance:**')

    ruleTitle = pp.Regex(r'[A-Z]\d{3}') + pp.White().suppress() + pp.restOfLine() + pp.ZeroOrMore(EOL)
    ruleTitle.setParseAction(
        lambda t: '\ntitles[type("%s")] = "%s";\nexplanations[type("%s")] =\n<html>\n%s: %s' %
            (t[0], html_unescape(t[1]),
             t[0], t[0], t[1])
    )

    ruleEnd = endTag + pp.restOfLine() + pp.ZeroOrMore(EOL)
    ruleEnd.setParseAction( lambda t: '%s\n</html>' % (t[0] + t[1]) )

    hline = pp.Regex(r'-{3,}') + pp.ZeroOrMore(EOL)
    hline.setParseAction( lambda t: '<hr>' )

    textLine  = pp.LineStart() + pp.NotAny('~') + pp.NotAny(endTag) + pp.NotAny(EOL) + pp.restOfLine() + EOL
    textBlock = pp.OneOrMore(textLine) + pp.ZeroOrMore(EOL)
    textBlock.setParseAction( lambda t: '%s\n<br><br>' % ' '.join(t) )

    codeTag   = pp.Regex(r'~~~~.*') + EOL
    codeLine  = pp.LineStart().leaveWhitespace() + pp.NotAny(codeTag) + pp.restOfLine() + pp.ZeroOrMore(EOL)
    codeBlock = codeTag.suppress() + pp.OneOrMore(codeLine) + codeTag.suppress() + pp.ZeroOrMore(EOL)

    parametersLine = pp.Literal(' ').leaveWhitespace() + pp.restOfLine() + EOL
    parametersLine.setParseAction( lambda t: ''.join(t) )
    parametersBlock = pp.OneOrMore(parametersLine) + pp.ZeroOrMore(EOL)

    listLine = pp.Literal('-') + pp.restOfLine() + EOL
    listLine.setParseAction( lambda t: ("&#8226;"+t[1]).replace('`', '') )
    listBlock = pp.OneOrMore(listLine) + pp.ZeroOrMore(EOL)

    preBlock = codeBlock ^ parametersBlock ^ listBlock
    preBlock.setParseAction( lambda t: '<pre>\n%s\n</pre>' % '\\n\n'.join(t) )

    rule = ruleTitle + hline + pp.OneOrMore(preBlock ^ textBlock) + ruleEnd
    rule.setParseAction( lambda t: '\n'.join(t) )

    rules = pp.Literal("Rules").suppress() + pp.Literal("=====").suppress() + EOL + pp.OneOrMore(rule)
    rules.setParseAction( lambda t: '\n'.join(t) )

    t = open(fileName, 'r').read()

    # escaping
    t = html_escape(t)
    t = re.sub(r'\\', r'\\\\', t)

    t = rules.parseString(t)[0]

    # add bold and italic
    t = re.sub(r'\*\*(.+)\*\*', r'<b>\1</b>', t)
    t = re.sub(r'\*(.+)\*', r'<i>\1</i>', t)

    # remove <br> before and after <pre> blocks
    t = re.sub(r'<br><br>\n<pre>', r'<pre>', t)
    t = re.sub(r'</pre>\n<br><br>', r'</pre>', t)

    # 'stringify' lines
    t = re.sub(r'(.+)', r'"\1"', t)

    # fix begin ane end of code
    t = re.sub(r'</html>"', r'</html>";', t)
    t = re.sub(r'"(titles\[.*)"', r'\1', t)
    t = re.sub(r'"(explanations\[.*)"', r'\1', t)

    #r = re.sub(r'^"', r'    "', r, flags = re.MULTILINE)

    return t

prefix=\
    '// This file is generated by \'rules_db_create.py\' from \'Rules.md\'.\n' \
    '// Please don\'t edit it\n\n' \
    '#include "rules.h"\n\n' \
    '#include <QString>\n\n' \
    'namespace verapp\n' \
    '{\n\n' \
    'namespace rules\n' \
    '{\n\n' \
    'void initDb(QString* titles, QString* explanations)\n' \
    '{\n'

suffix='\n\n}\n\n}\n\n}\n'

f = open('rules_db.cpp', 'w')
f.write(prefix)
f.write(parseFile('Rules.md'))
f.write(suffix)
