#!/usr/bin/python
#
# querybts - Examine the state of a debbugs server
#   Written by Chris Lawrence <lawrencc@debian.org>
#   (C) 1999-2000 Chris Lawrence
#
# This program is freely distributable per the following license:
#
##  Permission to use, copy, modify, and distribute this software and its
##  documentation for any purpose and without fee is hereby granted,
##  provided that the above copyright notice appears in all copies and that
##  both that copyright notice and this permission notice appear in
##  supporting documentation.
##
##  I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
##  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL I
##  BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
##  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
##  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
##  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
##  SOFTWARE.
#
# Version ##VERSION##; see changelog for revision history

import reportbug, debianbts, commands, getopt, sys, string, os, re
try:
    import snack
except:
    print "You must install the \"python-newt\" package before using "\
          "querybts."
    sys.exit(1)

VERSION = "querybts ##VERSION##"

USAGE = ("querybts - Examine the state of a debbugs server.\n\n"
         "Usage: querybts [options] <package>\n"
         "Supported options (see man page for long forms):\n"
         "  -B: Specify an alternate debbugs BTS. *\n"
         "  -h: Display this help message.\n"
         "  -l: Disable LDAP access to BTSes that support it.\n"
         "  -v: Show the version number of this program.\n"
         "  -w: Use a web browser instead of the internal interface.\n"
         "\nOptions marked * take the word 'help' to list allowed options.")

def whiptail(args, title="", clear=0):
    if clear: args = '--clear '+args
    if title: args = ('--title "%s" ' % title) + args
    return os.system('/usr/bin/whiptail --backtitle "%s" %s' % (VERSION, args))

##def infobox(text, height=7, width=50, title="", clear=0, screen=None):
##    return whiptail('--infobox "%s" %d %d' % (text, height, width),
##                    title, clear)

def infobox(text, height=7, width=50, title="", screen=None):
    if not screen:
        s = snack.SnackScreen()
    else:
        s = screen
        
    if not title:
        title = VERSION

    t = snack.TextboxReflowed(width, text, maxHeight = s.height - 12)
    g = snack.GridForm(s, title, 1, 2)
    g.add(t, 0, 0, padding = (0, 0, 0, 1))
    g.draw()
    s.refresh()
    if not screen:
        s.finish()

def msgbox(text, height=7, width=50, title="", clear=0):
    return whiptail('--msgbox "%s" %d %d' % (text, height, width),
                    title, clear)

def menu(text, height=20, width=60, menuheight=15, menu=None,
         title="", scroll=0, screen=None, startpos=1):
    if not menu: return None
    if not screen:
        s = snack.SnackScreen()
    else:
        s = screen
    items = []
    for item in menu:
        if item[0]:
            items.append(('%6s: %s' % item)[:width])
        else:
            items.append(item[1])

    if len(items) > menuheight: scroll=1
    res = startpos
    while 1:
        button, res = snack.ListboxChoiceWindow(s, title, text, items,
                                                width=width, height=menuheight,
                                                scroll=scroll, default=res)
        if button == 'cancel':
            if not screen:
                s.finish()
            return None
        elif menu[res][0]:
            selected = menu[res][0]
            break

    if not screen:
        s.finish()
    return selected

def show_report(info, sysinfo, system, columns, use_ldap, mirrors,
                http_proxy):
    number = int(info)
    s = snack.SnackScreen()
    infobox('Retrieving report #%d from %s bug tracking '
            'system...' % (number, sysinfo['name']), screen=s)

    width = columns-8
    info = debianbts.get_report(number, system,
                                ldap_ok=use_ldap, mirrors=mirrors,
                                http_proxy=http_proxy)
    if not info:
        s.finish()
        msgbox('Bug report #%d not found.' % number)
        return

    while 1:
        (bugtitle, body) = info

        lines = string.split(body, '\n')
        lines = map(lambda x, y=width: x[:y], lines)
        body = string.join(lines, '\n')

        r = snack.ButtonChoiceWindow(s, bugtitle, body,
                                     buttons=['Ok', 'More details '
                                              '(launch browser)...'],
                                     width=width)
        if not r or (r == 'ok'):
            break
        s.finish()
        launch_browser(number, system, mirrors)
        s = snack.SnackScreen()
        
    s.finish()
    return

def launch_browser(info, system, mirrors=None):
    if re.match('^\d+$', str(info)):
        url = debianbts.report_url(system, info, mirrors)
    else:
        url = debianbts.package_url(system, info, mirrors)

    X11BROWSER = os.environ.get('X11BROWSER', 'netscape')
    CONSOLEBROWSER = os.environ.get('CONSOLEBROWSER', 'lynx')

    if (os.environ.has_key('DISPLAY') and
        not os.system('command -v '+X11BROWSER+' &> /dev/null')):
        cmd = "%s '%s' &" % (X11BROWSER, url)
    else:
        cmd = "%s '%s'" % (CONSOLEBROWSER, url)

    os.system(cmd)

def main():
    system = 'debian'
    http_proxy = ''
    use_browser = use_ldap = 0
    mirrors = None

    args = reportbug.parse_config_files()
    for option, arg in args.items():
        if option == 'system':
            system = arg
        elif option == 'ldap':
            use_ldap = arg
        elif option == 'mirrors':
            mirrors = arg
        elif option == 'http_proxy':
            http_proxy = arg

    try:
        (opts, args) = getopt.getopt(sys.argv[1:],
                                     'B:hlvw', ['help', 'version', 'no-ldap',
                                                'bts=', 'ldap', 'web',
                                                'http_proxy=', 'proxy='])
    except getopt.error, msg:
        print msg
        sys.exit(1)

    for option, arg in opts:
        if option in ('-h', '--help'):
            print USAGE
            return
        elif option in ('-v', '--version'):
            print VERSION
            return
        elif option in ('--proxy', '--http_proxy'):
            http_proxy = arg
        elif option in ('-l', '--no-ldap'):
            use_ldap = 0
        elif option == '--ldap':
            use_ldap = 1
        elif option in ('-w', '--web'):
            use_browser = 1
        elif option in ('-B', '--bts'):
            if arg in reportbug.SYSTEMS.keys():
                system = arg
            elif arg == 'help':
                print 'Permitted arguments to --bts:'
                names = reportbug.SYSTEMS.keys()
                names.sort()
                for bsys in names:
                    print ' %-11.11s %s' % \
                          (bsys, reportbug.SYSTEMS[bsys]['name'])
                return
            else:
                print "Ignoring unknown BTS server %s." % arg

    sysinfo = reportbug.SYSTEMS[system]
    if len(args) == 0:
        print "Please specify a package or bug number."
        sys.exit(1)
    elif len(args) > 1:
        print "Please specify one package or bug number."
        print "[Did you forget to put all switches before the package name?]"
        sys.exit(1)

    package = args[0]
    if use_browser:
        launch_browser(package, system, mirrors)
        return

    r, c = string.split(commands.getoutput('stty size'))
    rows, columns = int(r), int(c)
    # Reasonable defaults
    rows = rows or 24
    columns = columns or 79

    if re.match('^\d+$', package):
        show_report(package, sysinfo, system, columns, use_ldap, mirrors,
                    http_proxy)
        return
    
    screen = snack.SnackScreen()
    infobox('Querying %s bug tracking system for reports on %s...'
            % (sysinfo['name'], package), screen=screen)
    try:
        (count, title, hierarchy) =debianbts.get_reports(package, system,
                                                         ldap_ok=use_ldap,
                                                         mirrors=mirrors,
                                                         http_proxy=http_proxy)
        if screen:
            screen.finish()

        if not count:
            msgbox('No outstanding bugs for %s.' % package)
        else:
            if count > 1:
                s='s'
            else:
                s=''

            title = '%d bug report%s found' % (count, s)
            list = []
            for (type, bugs) in hierarchy:
                bcount = len(bugs)
                s=''
                if bcount > 1: s='s'
                list.append( ('', '%s %d report%s' % (type, bcount, s)) )
                for bug in bugs:
                    tag, info = string.split(bug[1:], ': ', 1)
                    list.append( (tag, info) )

            p = 1
            while 1:
                info = menu('Select a bug to read the report:', rows-6,
                            columns-10, rows-15, list, title, startpos=p)
                if not info:
                    break
                else:
                    p = i = 0
                    for (number, subject) in list:
                        if number == info: p = i
			i = i + 1

                    show_report(info, sysinfo, system, columns, use_ldap,
                                mirrors, http_proxy)

    except IOError:
        msgbox('Unable to connect to %s BTS.\n' % sysinfo['name'])

    return

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print "reportbug: exiting due to user interrupt."
