"""
    MoinMoin - HoverCraft action
    
    @copyright: 2014 Lars Kruse <devel@sumpfralle.de>


    Licence:

    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 3 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.  If not, see <http://www.gnu.org/licenses/>.



    HoverCraft is a presentation generator based on reStructuredText:
      https://github.com/regebro/hovercraft
      http://hovercraft.readthedocs.org/

    You need to specify some settings within the 'hovercraft_options' dict in
    your wiki config file:
      * storage_dir: the local directory where resulting files should be stored
      * storage_url: the URL that points to the above directory (e.g. for apache: "Alias /URL /PATH")
      * hovercraft_bin: location of your local hovercraft executable (default: /usr/bin/hovercraft)
      * template: (optional) location of your custom template directory (if empty: use hovercraft's default template)
      * css: (optional) additional CSS file location

    Probably you will want to add something like the following to your webserver config:
      Alias /moin_cache/HoverCraft /var/cache/moin/HoverCraft
    See 'storage_url' and 'storage_dir' above.

    Usage: choose the "HoverCraft" action for any given rst page.

    Presentation example:

        #format rst

        .. title:: Introduction to hovercraft presentations within moinmoin

        .

        ----

        Formatting
        ==========

        * Text is *italic* (``*italic*``)

        * Text is **bold** (``**bold**``)

        * Text is ``not formatted`` (````not formatted````)

        ----

        Lists
        =====

        * item

        #. numbered item

        term
          description text



    Changelog:

    2014-08-25 - v.10
      * Initial release
"""


DEFAULT_OPTIONS = {
        # where to store the generated files and directories
        "storage_dir": None,
        # URL for the above directory
        # configure something like "Alias URL DIRECTORY" in your apache configuration
        "storage_url": None,
        # location of the hovercraft executable
        "hovercraft_bin": '/usr/bin/hovercraft',
        # use default template if empty
        "template": None,
        # optional additional CSS URL
        "css": None,
}


import os
import tempfile
import shutil
import subprocess

from MoinMoin import config, wikiutil
from MoinMoin.Page import Page
from MoinMoin.action import AttachFile


def send_error_page(request, pagename, errors, gettext_func):
    _ = gettext_func
    request.theme.send_title(_('HoverCraft error on Page "%s"') % pagename, pagename=pagename)
    request.write(_("<h1>Failed to create HoverCraft presentation</h1>"))
    request.write("<ul>")
    for text in errors:
        request.write('<li>%s</li>' % str(text))
    request.write("</ul>")
    request.theme.send_footer(pagename)


def check_config_for_errors(options, gettext_func):
    _ = gettext_func
    if not options["storage_url"]:
        yield _("missing option in wiki config: hovercraft_options['storage_url']")
    if not options["storage_dir"]:
        yield _("missing option in wiki config: hovercraft_options['storage_dir']")
    elif not os.path.isdir(options["storage_dir"]):
        try:
            os.mkdir(options["storage_dir"])
        except OSError, err_msg:
            yield _("failed to create 'storage_dir' (%s): %s") % (options['storage_dir'], err_msg)
    if not options["hovercraft_bin"]:
        yield _("missing option in wiki config: hovercraft_options['hovercraft_bin']")
    elif not os.path.exists(options["hovercraft_bin"]):
        yield _("could not find hovercraft executable (hovercraft_bin=%s)") %  options['hovercraft_bin']


def check_page_for_errors(page, gettext_func):
    _ = gettext_func
    page_format = page.pi["format"]
    if page_format != "rst":
        yield _("the wiki page uses the '%s' formatter instead of 'rst' (you should add '#format rst' as the first line)") % page_format


def get_page_lines(page):
    in_header = True
    for line in page.get_raw_body().splitlines():
        if in_header:
            if line.startswith("#"):
                # ignore the line
                continue
            else:
                in_header = False
        yield line


def copy_attachments(pagename, request, target_dir):
    attach_dir = AttachFile.getAttachDir(request, pagename)
    for filename in AttachFile._get_files(request, pagename):
        full_filename = os.path.join(attach_dir, filename)
        shutil.copy(full_filename, target_dir)


def execute(pagename, request):
    _ = request.getText

    errors = []
    options = dict(DEFAULT_OPTIONS)
    try:
        options.update(request.cfg.hovercraft_options)
    except AttributeError:
        # maybe no options were defined
        errors.append(_("Failed to find the 'hovercraft_options' setting in your wiki config file."))
        # without a settings dictionary there is no use for further errors
        return

    # check for given configuration options
    errors.extend(check_config_for_errors(options, request.getText))
    # check if the page content is suitable for hovercraft
    errors.extend(check_page_for_errors(request.page, request.getText))

    if errors:
        send_error_page(request, pagename, errors, request.getText)
    else:
        wikinamefs = wikiutil.quoteWikinameFS(pagename)
        hc_dir = os.path.join(options["storage_dir"], wikinamefs)
        hc_url = "/".join([options["storage_url"], wikinamefs])

        # create directory if it does not exist (necessary for attachment copying)
        if not os.path.isdir(hc_dir):
            os.mkdir(hc_dir)
        # copy all attachments (maybe they are referenced as files/images)
        copy_attachments(pagename, request, hc_dir)

        # write page content to input file
        page_content = os.linesep.join(get_page_lines(request.page))
        rst_filename = os.path.join(hc_dir, "index.rst")
        if not os.path.exists(hc_dir):
            os.makedirs(hc_dir)
        file(rst_filename, "w").write(page_content.encode("utf-8"))

        # assemble hovercraft call arguments
        arguments = [options["hovercraft_bin"]]
        if options.get("template"):
            arguments.append("--template")
            arguments.append(options["template"])
        if options.get("css"):
            arguments.append("--css")
            arguments.append(options["css"])

        arguments.append(rst_filename)
        arguments.append(hc_dir)

        proc = subprocess.Popen(arguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate()
        if proc.returncode == 0:
            # redirect to the resulting html presentation
            request.http_redirect(hc_url)
        else:
            # error: show the output
            send_error_page(request, pagename, [_("hovercraft reported an error: %s") % stderr], request.getText)

