#!/usr/bin/env python3
#
# SPDX-FileCopyrightText: Copyright Eric S. Raymond <esr@thyrsus.com>
# SPDX-License-Identifier: BSD-2-Clause

# pylint: disable=line-too-long,missing-module-docstring,multiple-imports,invalid-name,redefined-outer-name,missing-class-docstring,too-many-instance-attributes,missing-function-docstring,unspecified-encoding,consider-using-with,consider-using-f-string,too-many-branches,too-many-statements,too-few-public-methods

import os, os.path, sys

subdir = "prepatch"

distro = "Xubuntu 18.04 with some extras"
future = "next Xubuntu release"

CATEGORY_COUNT = 8


class Buglist:
    def __init__(self, filename="PATCHES"):
        with open(filename) as file:
            self.codes = {}
            while True:
                line = file.readline()
                if line == "%%\n":
                    break
                if line[0] == "#":
                    continue
                if not line[0].isspace():
                    key = line[0]
                    self.codes[key] = ""
                    line = line[1:]
                self.codes[key] += line.strip() + "\n"

            self.maildict = {}
            self.lines = []
            self.fields = []
            self.typeseen = {}
            self.promised = 0
            self.counts = [0] * CATEGORY_COUNT
            self.patched = 0
            self.warnings = 0
            while True:
                line = file.readline()
                if not line:
                    break
                self.lines.append(line)
                fields = line.split("|")
                try:
                    (status, pages, problems, mailto) = list(
                        map(lambda x: x.strip(), fields)
                    )
                    if "p" in status:
                        self.promised += len(pages.split(","))
                except ValueError:
                    print("Wrong field count")
                    print(line)
                    sys.exit(1)
                for c in problems:
                    self.typeseen[c] = True
                self.fields.append(list(map(lambda x: x.strip(), fields)))
                if mailto not in self.maildict:
                    self.maildict[mailto] = []
                self.maildict[mailto].append((status, pages, problems))
        try:
            with open("full.log") as lf:
                warn_latch = False
                while True:
                    line = lf.readline()
                    if not line:
                        break
                    if not line.strip():
                        if warn_latch:
                            self.warnings += 1
                        continue
                    if "warning -" in line:
                        warn_latch = True
                    if line[0] != "!":
                        continue
                    warn_latch = False
                    line = line[2:]
                    rcolon = line.rindex("=")
                    retval = line[rcolon + 1 :].split()[0]
                    if retval.endswith("*"):
                        self.patched += 1
                        retval = retval[:-1]
                    self.counts[int(retval)] += 1
        except (OSError, IOError):
            sys.stderr.write("Conversion log is missing.\n")

    def pagelist(self, include="", exclude=""):
        lst = []
        for (status, pages, _, _) in self.fields:
            addit = not include
            for c in include:
                if c in status:
                    addit = True
                    break
            for c in exclude:
                if c in status:
                    addit = False
                    break
            if addit:
                lst += list(map(lambda x: x.strip(), pages.split(",")))
        lst.sort()
        return lst


def filestem(x):
    if x.endswith(".patch"):
        return x[:-6]
    if x.endswith(".correction"):
        return x[:-11]
    return x


def pagetofile(page):
    page = os.path.join(subdir, page)
    if os.path.exists(page + ".patch"):
        fp = open(page + ".patch")
        txt = fp.read()
        fp.close()
    # manlifter doesn't pick up corrections
    elif os.path.exists(page + ".correction"):
        fp = open(page + ".correction")
        txt = fp.read()
        fp.close()
    else:
        txt = None
    return txt


if __name__ == "__main__":
    import getopt

    (options, arguments) = getopt.getopt(sys.argv[1:], "e:")
    error_type_filter = None
    for (opt, val) in options:
        if opt == "-e":
            error_type_filter = val

    bugs = Buglist()
    if error_type_filter:  # report on what entries contain specified code
        for (status, pages, problems, mailto) in bugs.fields:
            if error_type_filter in problems:
                print("|".join((status, pages, problems, mailto)))
    else:
        # Default action is to sanity-check the database
        patches = set(filestem(x) for x in os.listdir(subdir))
        pages = set(bugs.pagelist())
        unresolved = set(bugs.pagelist(exclude="y"))
        resolved = set(bugs.pagelist(include="y"))
        counts = {}
        for page in pages:
            counts[page] = counts.get(page, 0) + 1
        duplicates = [x for x in pages if counts[x] > 1]
        if duplicates:
            print("Duplicates:", duplicates)
        print(
            "%d unresolved patches, %d resolved, %d promised, %d total, %d patches."
            % (len(unresolved), len(resolved), bugs.promised, len(pages), len(patches))
        )
        if patches - pages:
            print("These patches have no buglist entry:", patches - pages)
        if unresolved - patches:
            print("These bugs have no filelist entry:", unresolved - patches)
        if len(patches - unresolved):
            print("Leftovers:", " ".join(patches - unresolved))
        nonbugs = []
        for c in list(bugs.codes.keys()):
            if not c in bugs.typeseen:
                nonbugs.append(c)
        if nonbugs:
            print("These bug types no longer occur: ", ", ".join(nonbugs))
        available = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
        for c in list(bugs.codes.keys()):
            available.remove(c)
        if available:
            print("These bug keys are available: ", ", ".join(available))
        else:
            print("All bug keys are in use")

# end
