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

# Copyright(C) 2010-2011 Laurent Bachelier
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.

from __future__ import with_statement

import sys
import os
import tempfile
import imp
import inspect
import optparse
import re
import time

from weboob.tools.application.base import BaseApplication

BASE_PATH = os.path.join(os.path.dirname(__file__), os.pardir)
DEST_DIR = 'man'


class ManpageHelpFormatter(optparse.HelpFormatter):
    def __init__(self,
                 app,
                 indent_increment=0,
                 max_help_position=0,
                 width=80,
                 short_first=1):
        optparse.HelpFormatter.__init__(self, indent_increment, max_help_position, width, short_first)
        self.app = app

    def format_heading(self, heading):
        return ".SH %s\n" % heading.upper()

    def format_usage(self, usage):
        txt = ''
        for line in usage.split('\n'):
            line = line.lstrip().split(' ', 1)
            if len(txt) > 0:
                txt += '.br\n'
            txt += '.B %s\n' % line[0]

            arg_re = re.compile(r'([\[\s])([\w_]+)')
            args = re.sub(arg_re, r"\1\\fI\2\\fR", line[1])
            txt += args
            txt += '\n'
        return '.SH SYNOPSIS\n%s' % txt

    def format_description(self, description):
        desc = u'.SH DESCRIPTION\n.LP\n\n%s\n' % description
        if hasattr(self.app, 'CAPS'):
            self.app.weboob.modules_loader.load_all()
            backends = []
            for name, backend in self.app.weboob.modules_loader.loaded.iteritems():
                if backend.has_caps(self.app.CAPS):
                    backends.append(u'* %s (%s)' % (name, backend.description))
            if len(backends) > 0:
                desc += u'\n.SS Supported websites:\n'
                desc += u'\n.br\n'.join(sorted(backends))
        return desc

    def format_commands(self, commands):
        s = u''
        for section, cmds in commands.iteritems():
            if len(cmds) == 0:
                continue
            s += '.SH %s COMMANDS\n' % section.upper()
            for cmd in sorted(cmds):
                s += '.TP\n'
                h = cmd.split('\n')
                if ' ' in h[0]:
                    cmdname, args = h[0].split(' ', 1)
                    arg_re = re.compile(r'([A-Z_]+)')
                    args = re.sub(arg_re, r"\\fI\1\\fR", args)

                    s += '\\fB%s\\fR %s' % (cmdname, args)
                else:
                    s += '\\fB%s\\fR' % h[0]
                s += '%s\n' % '\n.br\n'.join(h[1:])
        return s

    def format_option_strings(self, option):
        opts = optparse.HelpFormatter.format_option_strings(self, option).split(", ")

        return ".TP\n" + ", ".join("\\fB%s\\fR" % opt for opt in opts)


def main():
    scripts_path = os.path.join(BASE_PATH, "scripts")
    files = os.listdir(scripts_path)

    # Create a fake "scripts" modules to import the scripts into
    sys.modules["scripts"] = imp.new_module("scripts")

    for fname in files:
        fpath = os.path.join(scripts_path, fname)
        if os.path.isfile(fpath) and os.access(fpath, os.X_OK):
            with open(fpath) as f:
                # Python will likely want create a compiled file, we provide a place
                tmpdir = os.path.join(tempfile.gettempdir(), "weboob", "make_man")
                if not os.path.isdir(tmpdir):
                    os.makedirs(tmpdir)
                tmpfile = os.path.join(tmpdir, fname)

                desc = ("", "U", imp.PY_SOURCE)
                try:
                    script = imp.load_module("scripts.%s" % fname, f, tmpfile, desc)
                except ImportError, e:
                    print >>sys.stderr, "Unable to load the %s script (%s)" \
                        % (fname, e)
                else:
                    print "Loaded %s" % fname
                    # Find the applications we can handle
                    for klass in script.__dict__.itervalues():
                        if inspect.isclass(klass) and issubclass(klass, BaseApplication):
                            analyze_application(klass, fname)
                finally:
                    # Cleanup compiled files if needed
                    if (os.path.isfile(tmpfile + "c")):
                        os.unlink(tmpfile + "c")


def format_title(title):
    return re.sub(r'^(.+):$', r'.SH \1\n.TP', title.group().upper())


# XXX useful because the PyQt QApplication destructor crashes sometimes. By
# keeping every applications until program end, it prevents to stop before
# every manpages have been generated. If it crashes at exit, it's not a
# really a problem.
applications = []


def analyze_application(app, script_name):
    application = app()
    applications.append(application)

    formatter = ManpageHelpFormatter(application)

    # patch the application
    application._parser.prog = "%s" % script_name
    application._parser.formatter = formatter
    helptext = application._parser.format_help(formatter)

    cmd_re = re.compile(r'^.+ Commands:$', re.MULTILINE)
    helptext = re.sub(cmd_re, format_title, helptext)
    helptext = helptext.replace("-", r"\-")
    coding = r'.\" -*- coding: utf-8 -*-'
    header = '.TH %s 1 "%s" "%s %s"' % (script_name.upper(), time.strftime("%d %B %Y"),
                                        script_name, app.VERSION.replace('.', '\\&.'))
    name = ".SH NAME\n%s \- %s" % (script_name, application.SHORT_DESCRIPTION)
    footer = """.SH COPYRIGHT
%s
.LP
For full COPYRIGHT see COPYING file with weboob package.
.LP
.RE
.SH FILES
 "~/.config/weboob/backends" """ % application.COPYRIGHT
    if len(app.CONFIG) > 0:
        footer += '\n\n "~/.config/weboob/%s"' % app.APPNAME

    # Skip internal applications.
    footer += "\n\n.SH SEE ALSO\nHome page: http://weboob.org/applications/%s" % application.APPNAME

    mantext = u"%s\n%s\n%s\n%s\n%s" % (coding, header, name, helptext, footer)
    with open(os.path.join(BASE_PATH, DEST_DIR, "%s.1" % script_name), 'w+') as manfile:
        for line in mantext.split('\n'):
            manfile.write('%s\n' % line.lstrip().encode('utf-8'))
    print "wrote %s/%s.1" % (DEST_DIR, script_name)

if __name__ == '__main__':
    sys.exit(main())
