#!/usr/bin/env python

# Written by Henrik Nilsen Omma
# (C) Canonical, Ltd. Licensed under the GPL

import os
import sys
import urllib
import re
import time

try:
    from commandLine import commandLine
    from infoFiles import InfoFiles
    import connector as Connector
    import utils
    import config
    import bzrutils
    import output
    import statistic
except:
    from bugHelper.commandLine import commandLine
    from bugHelper.infoFiles import InfoFiles
    import bugHelper.config as config
    import bugHelper.bzrutils as bzrutils
    import bugHelper.output as output
    import bugHelper.statistic as statistic
    import launchpadbugs.connector as Connector
    import bugHelper.utils as utils
    from launchpadbugs.basebuglistfilter import URLBugListFilter
    from launchpadbugs.lpconstants import BASEURL, BUG

def main():
    conf = config.Config("~/.bughelper/config")
    cl = commandLine()
    
    if cl.options.parsemode not in ("text","html"):
        cl.parser.print_usage()
        sys.exit(1)
    Bug = Connector.ConnectBug(method=cl.options.parsemode)
    BugList = Connector.ConnectBugList(method=cl.options.parsemode)
    
    cookie = cl.options.cookie
    if cookie:
        cookie = os.path.expanduser(cookie)
    else:
        try:
            cookie = os.path.expanduser(conf.cookie)
        except:
            if cl.options.debug:
                print >> sys.stderr, "No cookie-file found"
                
    if cookie:
        BugList.authentication=cookie
        Bug.authentication=cookie
        
    try:
        out = output.Output("bughelper",cl.options.format,cl.options.file)
    except output.StyleNotFound, e:
        print >> sys.stderr, e
        sys.exit(1)
    out.print_header()
    start = time.time()
    if cl.options.gen_config:
        sys.exit(0)

    # TODO: Where to print messages like 'Now on revision xx'
    # or 'No revisions to pull.'
    try:
        (bzrinfo,bzrerr) = bzrutils.update_packages_data(conf.packages_dir, conf.update_interval)
        # print (bzrinfo,bzrerr)
    except bzrutils.BzrError, e:
        out.error(e)
    if not cl.options.try_only_clue:
        files = InfoFiles(set((conf.packages_dir, conf.local_packages_dir)))
    else:
        files = InfoFiles(set())
        files.add_simple_clue(cl.options.try_only_clue[0], 
                              cl.options.try_only_clue[1],
                              cl.options.try_only_clue[2])
    if cl.options.try_clue:
        # load existing clues first
        files.get_info_file(cl.options.try_clue[0], cl.options.verbose)
        files.add_simple_clue(cl.options.try_clue[0], 
                              cl.options.try_clue[1],
                              cl.options.try_clue[2])
    if cl.options.bugnr:
        bl = set([cl.options.bugnr]) #FIXME: this should be BugList, not set
    else:
        if not cl.options.url and not cl.options.sourcepackage:
            cl.parser.print_usage()
            sys.exit(1)
            
        bug_filter = URLBugListFilter()
        
        if not cl.options.url:
            cl.options.url = \
                bug_filter("%s/ubuntu/+source/%s/+bugs" %(BASEURL.BUG_NG, cl.options.sourcepackage))
        else:
            try:
                cl.options.url = bug_filter(cl.options.url)
            except ValueError, e:
                print >> sys.stderr, e
                sys.exit(1)
    
        #HACK!!
        # the text-interface of LP does not provide infos like status, importance etc.
        # in a bug-list. [..]
        # move this to the end of the functions-list?
        if cl.options.parsemode == "text":
            from launchpadbugs.basebuglistfilter import get_current_task
            bug_filter.functions.append(lambda x: get_current_task(x, bug_filter.baseurl, Bug))
            
        if cl.options.ignore_conflicts:
            bug_filter._conflicts_error = bug_filter.ADD
             
        if cl.options.minbug:
            from launchpadbugs.basebuglistfilter import minbug
            bug_filter.functions.append(lambda x: minbug(x, int(cl.options.minbug)))
            
        if cl.options.filterbug:
            from launchpadbugs.basebuglistfilter import filterbug
            bug_filter.functions.append(lambda x: filterbug(x, map(int, cl.options.filterbug.split(","))))
          
        if cl.options.status:
            x = set(cl.options.status.split(","))
            if not x <= set(BUG.STATUS.values()).union(set(BUG.STATUS_INCOMPLETE_ADD.values())):
                raise ValueError, "unknown status: %s" %x
            if "Incomplete" in x:
                x.remove("Incomplete")
                x = x.union(set(BUG.STATUS_INCOMPLETE_ADD.keys()))
            for k,i in BUG.STATUS_INCOMPLETE_ADD.iteritems():
                if i in x:
                    x.remove(i)
                    x.add(k)
            bug_filter.add_option("status", x)
            
        if cl.options.importance:
            x = cl.options.importance.split(",")
            if not set(x) <= set(BUG.IMPORTANCE.values()):
                raise ValueError, "unknown status: %s" %x
            bug_filter.add_option("importance", x)
        
        if cl.options.closed_bugs:
            bug_filter.add_option("status", BUG.STATUS.values())
            
        if cl.options.tag:
            bug_filter.add_option("tag", cl.options.tag.split(","))
            
        if cl.options.duplicates:
            bug_filter.add_option("duplicates", ("off",))
            
        if cl.options.reporter:
            bug_filter.add_option("reporter", (cl.options.reporter,))

        try:
            bl = BugList(cl.options.url)
        except BugList.Error.LPUrlError, e:
            if cl.options.sourcepackage:
                print >> sys.stderr, " Maybe package '%s' does not exist in Ubuntu." % cl.options.sourcepackage 
            else:
                print >> sys.stderr, "Error while parsing '%s': %s.%s" %(cl.options.url, e, x)
            sys.exit(1)
            
        if cl.options.upstream and cl.options.sourcepackage:
            l = None
            try:
                l = BugList(bug_filter("%s/%s/+bugs" %(BASEURL.BUG_NG, cl.options.sourcepackage)))
            except BugList.Error.LPUrlError, e:
                print >> sys.stderr, "There is no product <%s> in launchpad.net" %cl.options.sourcepackage
            if l:
                bl += l
            
                
        if cl.options.sourcepackage:
            path = os.path.expanduser(os.path.join(conf.attachments_cache, 
                                                   cl.options.sourcepackage))
            utils.remove_obsolete_attachments(path, bl)

    if not bl:
        if not bug_filter.urlopt:
            out.info("There are currently no open bugs.")
        else:
            out.info("No results for search.")
        out.print_footer()
        sys.exit(1)
    count_bugs = 0
    all_bugs = []
    if cl.options.attachments:
        Bug.attachment_path = conf.attachments_cache
    for bugNum in bl:
        b = bugNum
        if str(type(b)) != "Bug":
            try:
                b = Bug(bugNum)
            except Bug.Error.LPUrlError, e:
                if cl.options.debug:
                    print >> sys.stderr, "This error occurs while getting #%s: %s" %(bugNum, e)
                continue
        displayclues = dict()
        try:
            info_file = files.get_info_file(b.sourcepackage, cl.options.verbose)
        except AttributeError, e:
            if cl.options.debug:
                print >> sys.stderr, "This error occurs while getting #%s: %s, \
possible reason: bugreport changed while running bughelper" %(bugNum, e)
            continue
        if not int(bugNum) in info_file.dontlist:
            collected_clues = set()
            if cl.options.heuristic and (not b.sourcepackage or \
                                         not info_file.clues):
                all_files = files.get_available_clue_files()
                for f in all_files:
                    info_file = files.get_info_file(b.sourcepackage, \
                                                    cl.options.verbose)
                    collected_clues.update(info_file.clues)
                    collected_clues.update(info_file.inherited_clues)
            if info_file.clues:
                collected_clues.update(info_file.clues)
                collected_clues.update(info_file.inherited_clues)
                for clue in collected_clues:
                    try:
                        if info_file.clue_matches(clue, b, 
                                              cl.options.case_sensitive):
                            displayclues[clue.info] = set()
                    except AttributeError, e:
                        if cl.options.debug:
                            print >> sys.stderr, e
                    if cl.options.attachments:
                        for a in b.attachments.filter(lambda a: re.match("^.*[^\.gz]$", a.lp_filename)):
                            try:
                                if info_file.clue_matches(clue, a):
                                    if not displayclues.has_key(clue.info):
                                        displayclues[clue.info] = set()
                                    displayclues[clue.info].add(a.url)
                            except (AttributeError, Bug.Error.LPUrlError), e:
                                if cl.options.debug:
                                    print >> sys.stderr, e
                if displayclues:
                    out.print_item({"bug": b, "clue" : displayclues})
                    all_bugs.append(b)
    
    footer_opt = {}
    if cl.options.footer:
        o = list(cl.options.footer)
        if "s" in o:
            footer_opt["statistic"] = statistic.summary(all_bugs)
        if "t" in o:
            footer_opt["time"] = {
                "time": time.strftime("%a, %d %b %Y %H:%M:%S %Z"),
                "duration" : "%i" %(time.time() - start)}
    out.print_footer(footer_opt)

if __name__ == "__main__":
    main()

