# Copyright 2007-2020 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

import logging
import portage

from portage.output import colorize


def display_preserved_libs(vardb, verbose=False):
    MAX_DISPLAY = 3

    plibdata = vardb._plib_registry.getPreservedLibs()
    linkmap = vardb._linkmap
    consumer_map = {}
    owners = {}

    try:
        linkmap.rebuild()
    except portage.exception.CommandNotFound as e:
        portage.util.writemsg_level(
            f"!!! Command Not Found: {e}\n", level=logging.ERROR, noiselevel=-1
        )
    else:
        search_for_owners = set()
        for cpv in plibdata:
            internal_plib_keys = {linkmap._obj_key(f) for f in plibdata[cpv]}
            for f in plibdata[cpv]:
                if f in consumer_map:
                    continue
                consumers = []
                for c in linkmap.findConsumers(f, greedy=False):
                    # Filter out any consumers that are also preserved libs
                    # belonging to the same package as the provider.
                    if linkmap._obj_key(c) not in internal_plib_keys:
                        consumers.append(c)
                consumers.sort()
                consumer_map[f] = consumers
                max_search = None if verbose else MAX_DISPLAY + 1
                search_for_owners.update(consumers[:max_search])

        owners = {}
        for f in search_for_owners:
            owner_set = set()
            for owner in linkmap.getOwners(f):
                owner_dblink = vardb._dblink(owner)
                if owner_dblink.exists():
                    owner_set.add(owner_dblink)
            if owner_set:
                owners[f] = owner_set

    all_preserved = set()
    all_preserved.update(*plibdata.values())

    for cpv in plibdata:
        print(colorize("WARN", ">>>") + f" package: {cpv}")
        samefile_map = {}
        for f in plibdata[cpv]:
            obj_key = linkmap._obj_key(f)
            alt_paths = samefile_map.get(obj_key)
            if alt_paths is None:
                alt_paths = set()
                samefile_map[obj_key] = alt_paths
            alt_paths.add(f)

        for alt_paths in samefile_map.values():
            alt_paths = sorted(alt_paths)
            for p in alt_paths:
                print(colorize("WARN", " * ") + f" - {p}")
            f = alt_paths[0]
            consumers = consumer_map.get(f, [])
            consumers_non_preserved = [c for c in consumers if c not in all_preserved]
            if consumers_non_preserved:
                # Filter the consumers that are preserved libraries, since
                # they don't need to be rebuilt (see bug #461908).
                consumers = consumers_non_preserved

            if verbose:
                max_display = None
            elif len(consumers) == MAX_DISPLAY + 1:
                # Display 1 extra consumer, instead of displaying
                # "used by 1 other files".
                max_display = MAX_DISPLAY + 1
            else:
                max_display = MAX_DISPLAY
            for c in consumers[:max_display]:
                if c in all_preserved:
                    # The owner is displayed elsewhere due to having
                    # its libs preserved, so distinguish this special
                    # case (see bug #461908).
                    owners_desc = "preserved"
                else:
                    owners_desc = ", ".join(x.mycpv for x in owners.get(c, []))
                print(colorize("WARN", " * ") + f"     used by {c} ({owners_desc})")
            if not verbose and len(consumers) > max_display:
                print(
                    colorize("WARN", " * ")
                    + "     used by %d other files" % (len(consumers) - max_display)
                )
