#!/usr/bin/env python
# coding: utf-8

"""
Quepy command line tool.

Usage:
    quepy startapp <name>
    quepy graph <app_name> <question> ...
    quepy nltkdata <path>
    quepy tag <app_name> <text> ...
    quepy autotest <app_name>
    quepy -v | --version

Description:
    startapp: Creates an application template.
    graph: Generates an HTML inform with a graph representation of the query generated.
    nltkdata: Downloads the necesary nltk data files into a supplied path
    tag: Prints the POS tags of a given text.
    autotest: Runs automatic tests for the application
"""

import os
import sys
import base64
import subprocess
from docopt import docopt
from xml.sax.saxutils import escape

import quepy
from quepy import generation
from quepy.encodingpolicy import encoding_flexible_conversion


HTML_TEMPLATE = """
<html><body>
<table style="border:0" align="center">
    <tr>
        <td colspan="2"><h2 style="text-align: center">{question}</h2></td>
    </tr>
    <tr><td colspan="2"><hr /></td></tr>
    {rows}
</table>
</body></html>
"""

QUERY_TEMPLATE = """
<tr>
    <td><b style="text-align: center"></b><br /> <pre>{sparql}</pre> </td>
    <td style="padding-left: 50px">
        <img src="data:image/png;base64,{image_base64}" />
    </td>
</tr>
<tr>
    <td colspan="2"><hr /></td>
</tr>
"""


class CommandNotFound(Exception):
    pass


def startapp(name):
    san_name = name.decode("ascii", "ignore").lower().replace(" ", "_")
    header_template = "# coding: utf-8\n\n"
    main_template = "import quepy\n" \
                    "{san_name} = quepy.install(\"{name}\")\n"
    description_template = "\"\"\"\n" \
                           "{module} for {name} quepy.\n" \
                           "\"\"\"\n\n" \

    # Create the main folder
    folder = san_name
    if os.path.exists(folder):
        print "Error: folder '{}' already exists".format(folder)
        return
    os.mkdir(folder)
    os.mkdir(os.path.join(folder, folder))

    main_filename = os.path.join(folder, "main.py")
    parsing_filename = os.path.join(folder, folder, "basic.py")
    init_filename = os.path.join(folder, folder, "__init__.py")
    dsl_filename = os.path.join(folder, folder, "dsl.py")

    # We'll copy the content of the settings on quepy to the app
    quepy_folder = os.path.dirname(quepy.__file__)
    settings_real_file = os.path.join(quepy_folder, "settings.py")
    settings_filename = os.path.join(folder, folder, "settings.py")

    with open(main_filename, "w") as fh:
        fh.write(header_template)
        fh.write(description_template.format(module="Main script",
                                             name=name))
        fh.write(main_template .format(san_name=san_name, name=name))

    with open(parsing_filename, "w") as fh:
        fh.write(header_template)
        fh.write(description_template.format(module="Basic queries",
                                             name=name))
        fh.write("from dsl import *\n")

    with open(dsl_filename, "w") as fh:
        fh.write(header_template)
        fh.write(description_template.format(module="Domain specific language",
                                             name=name))

    with open(init_filename, "w") as fh:
        fh.write(header_template)
        fh.write(description_template.format(module="Init",
                                             name=name))
        fh.write("from basic import *\n")

    # Copy the content of settings
    with open(settings_real_file, "r") as fh:
        settings_content = fh.read()
    with open(settings_filename, "w") as fh:
        fh.write(settings_content)

    print "Application template created on: {}".format(san_name)


def print_version():
    print "Quepy {0}".format(quepy.VERSION)


def graph_query(app_name, question):
    question = question.decode("ascii")
    # Set the path to the app
    sys.path.append(os.getcwd())

    try:
        app = quepy.install(app_name)
    except Exception, error:
        print >> sys.stderr, "Couldn't install app '%s': %s" % \
                             (app_name, error)
        sys.exit(1)

    rows = ""
    for expression, userdata in app._iter_compiled_forms(question):
        _, dot_string = generation.get_code(expression, "dot")
        target, query = generation.get_code(expression, "sparql")

        dot_path = "/tmp/quepy_graph.dot"
        cmdline = "dot -Tpng %s" % dot_path

        with open(dot_path, "w") as filehandler:
            filehandler.write(dot_string)

        try:
            call = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE)
            output, _ = call.communicate()
        except OSError:
            msg = "Error running '{}': the program 'dot' was not found."
            print msg.format(cmdline)
            sys.exit(1)

        image_base64 = base64.b64encode(output)
        query = "\n".join([x for x in query.split("\n")
                           if not x.startswith("PREFIX")])
        query = escape(query)
        rows += QUERY_TEMPLATE.format(sparql=query, image_base64=image_base64)

    html = HTML_TEMPLATE.format(question=question, rows=rows)
    with open("inform.html", "w") as filehandler:
        filehandler.write(html)


def print_tags(app_name, text):
    # Set the path to the app
    sys.path.append(os.getcwd())

    try:
        # Install the app to set the settings
        quepy.install(app_name)
    except Exception, error:
        print >> sys.stderr, "Couldn't install app '%s': %s" % \
                             (app_name, error)
        sys.exit(1)

    text = text.decode("ascii")
    tagger = quepy.tagger.get_tagger()
    tagger_out = tagger(text)

    attrs = "TOKEN LEMMA POS PROB".split()
    print " ".join(["{:13.13}".format(x) for x in attrs])
    for word in tagger_out:
        attrs = unicode(word).split("|")
        print " ".join(["{:13.13}".format(x) for x in attrs])


def nltkdata(path):
    print "Preparing to download..."
    import nltk
    try:
        os.mkdir(path)
    except OSError:
        pass
    nltk.download("wordnet", path)
    nltk.download("maxent_treebank_pos_tagger", path)
    print "Finished"


def autotest(app_name):
    import re
    import refo

    _EOL = None
    sys.path.append(os.getcwd())
    example_re = re.compile('"(.*?)"')

    try:
        # Install the app to set the settings
        quepy.install(app_name)
    except Exception, error:
        print >> sys.stderr, "Couldn't install app '%s': %s" % \
                             (app_name, error)
        sys.exit(1)

    parsing_module = __import__("{0}.parsing".format(app_name), fromlist=[None])
    errors_found = False
    regex_list = {}
    for attr_name in dir(parsing_module):
        attr = getattr(parsing_module, attr_name)
        try:
            if issubclass(attr, quepy.parsing.QuestionTemplate):
                examples = example_re.findall(attr.__doc__)
                regex_list[attr] = examples
        except TypeError:
            pass

    for regex_class in regex_list:
        regex = regex_class.regex + refo.Literal(_EOL)

        for text in regex_list[regex_class]:
            print "Testing {}...".format(text),
            text = encoding_flexible_conversion(text)
            tagger = quepy.tagger.get_tagger()
            words = tagger(text)

            match = refo.match(regex, words + [_EOL])
            if not match:
                print "ERROR"
                if not errors_found:
                    errors_found = True
                    print "The following errors have been found:\n"

                print regex_class.__name__
                print words
                print
            else:
                print "OK"

    if not errors_found:
        print "No errors were found :)"


if __name__ == "__main__":
    args = docopt(__doc__)
    if args["startapp"]:
        startapp(args["<name>"])
    elif args["graph"]:
        question = " ".join(args["<question>"])
        graph_query(args["<app_name>"], question)
    elif args["nltkdata"]:
        nltkdata(args["<path>"])
    elif args["tag"]:
        text = " ".join(args["<text>"])
        print_tags(args["<app_name>"], text)
    elif args["autotest"]:
        autotest(args["<app_name>"])
    elif args["-v"] or args["--version"]:
        print_version()
